
/******************************************************************************
* MODULE     : skeleton.gen.cc
* DESCRIPTION: Line breaking facility for paragraphs
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <array.gen.cc>
#include <Page/vpenalty.gen.h>

#module skeleton
#define no_tree_converter<insertion>
#define no_tree_converter<pagelet>
#import vpenalty

/******************************************************************************
* Abstract definitions of skeletons, pagelets and insertions
******************************************************************************/

struct array<pagelet>;
struct insertion_rep;
struct insertion {
#import concrete (insertion, insertion_rep)
  inline insertion ();
  inline insertion (tree type, path begin, path end);
  inline insertion (tree type, array<pagelet> sk);
  friend bool operator == (insertion ins1, insertion ins2);
  friend bool operator != (insertion ins1, insertion ins2);
  friend ostream& operator << (ostream& out, insertion ins);
};
#import array (insertion)

struct pagelet_rep;
struct pagelet {
#import concrete_null (pagelet, pagelet_rep)
  inline pagelet (space ht);
  void operator << (insertion ins);
  void operator << (space ht);
  friend bool operator == (pagelet pg1, pagelet pg2);
  friend bool operator != (pagelet pg1, pagelet pg2);
  friend ostream& operator << (ostream& out, pagelet pg);
};
#import array (pagelet)
typedef array<pagelet> skeleton;

/******************************************************************************
* Code for insertions
******************************************************************************/

struct insertion_rep: concrete_struct {
  tree      type;     // type of insertion
  path      begin;    // begin location in array of page_items
  path      end;      // end location in array of page_items
  skeleton  sk;       // or possible subpagelets (used for multicolumns)
  space     ht;       // height of pagelet
  vpenalty  pen;      // penalty associated to pagelet
  double    stretch;  // between -1 and 1 for determining final height
  SI        top_cor;  // top correction
  SI        bot_cor;  // bottom correction

  inline insertion_rep () {}
  inline insertion_rep (tree type2, path begin2, path end2):
    type (type2), begin (begin2), end (end2) {}
  insertion_rep (tree type, skeleton sk);
};
#import code_concrete (insertion, insertion_rep)

inline
insertion::insertion () {
  rep= new insertion_rep ();
}

inline
insertion::insertion (tree type, path begin, path end) {
  rep= new insertion_rep (type, begin, end);
}

inline
insertion::insertion (tree type, skeleton sk) {
  rep= new insertion_rep (type, sk);
}

/******************************************************************************
* Code for pagelets
******************************************************************************/

struct pagelet_rep: concrete_struct {
  array<insertion> ins;
  space            ht;
  vpenalty         pen;
  double           stretch;

  inline pagelet_rep (space ht2): ht (ht2) {}
};
#import code_concrete_null (pagelet, pagelet_rep)

inline
pagelet::pagelet (space ht) {
  rep= new pagelet_rep (ht);
}

inline void
pagelet::operator << (insertion ins) {
  rep->ht  += ins->ht;
  rep->pen += ins->pen;
  rep->ins << ins;
}

inline void
pagelet::operator << (space spc) {
  rep->ht += spc;
}

bool operator == (pagelet pg1, pagelet pg2);
bool operator != (pagelet pg1, pagelet pg2);
ostream& operator << (ostream& out, pagelet pg);

#endmodule // skeleton

#module code_skeleton
#import skeleton
#import code_array (insertion)
#import code_array (pagelet)

bool var_path_inf_eq (path p1, path p2);

insertion_rep::insertion_rep (tree type2, skeleton sk2):
  type (type2), begin (sk2[0]->ins[0]->begin),
  end (sk2[0]->ins[0]->end), sk (sk2)
{
  int i, n= N(sk);
  for (i=0; i<n; i++) {
    int j, k= N(sk[i]->ins);
    for (j=0; j<k; j++) {
      if (var_path_inf_eq (sk[i]->ins[j]->begin, begin))
	begin= sk[i]->ins[j]->begin;
      if (var_path_inf_eq (end, sk[i]->ins[j]->end))
	end= sk[i]->ins[j]->end;
    }
  }
}

bool
operator == (insertion ins1, insertion ins2) {
  return
    (ins1->type  == ins2->type ) &&
    (ins1->begin == ins2->begin) &&
    (ins1->end   == ins2->end  ) &&
    (ins1->sk    == ins2->sk   );
}

bool
operator != (insertion ins1, insertion ins2) {
  return
    (ins1->type  != ins2->type ) ||
    (ins1->begin != ins2->begin) ||
    (ins1->end   != ins2->end  ) ||
    (ins1->sk    != ins2->sk   );
}

bool
operator < (insertion ins1, insertion ins2) {
  if (ins1->type != ins2->type) {
    if (is_tuple (ins1->type, "footnote")) return FALSE;
    if (is_tuple (ins2->type, "footnote")) return TRUE;
    if (ins1->type == tuple ("float", "b")) return FALSE;
    if (ins2->type == tuple ("float", "b")) return TRUE;
    if (ins1->type == tuple ("float", "t")) return TRUE;
    if (ins2->type == tuple ("float", "t")) return FALSE;
  }
  return !var_path_inf_eq (ins2->begin, ins1->begin);
}

ostream&
operator << (ostream& out, insertion ins) {
  if (ins->type != "") out << ins->type << " ";
  out << "insertion [ " << ins->begin << " -- " << ins->end;
  if (N(ins->sk)>0) out << "; " << ins->sk;
  return out << " ]";
}

bool
operator == (pagelet pg1, pagelet pg2) {
  if (nil (pg1) || nil (pg2)) return nil (pg1) == nil (pg2);
  return (pg1->ins == pg2->ins);
}

bool
operator != (pagelet pg1, pagelet pg2) {
  if (nil (pg1) || nil (pg2)) return nil (pg1) != nil (pg2);
  return (pg1->ins != pg2->ins);
}

ostream&
operator << (ostream& out, pagelet pg) {
  return out << "pagelet " << pg->ins;
}

void
sort (pagelet& pg) {
  int i, n= N (pg->ins);
  while (TRUE) {
    bool flag =TRUE;
    for (i=0; i<n-1; i++)
      if (pg->ins[i+1] < pg->ins[i]) {
	insertion tmp= pg->ins[i];
	pg->ins[i]= pg->ins[i+1];
	pg->ins[i+1]= tmp;
	flag= FALSE;
      }
    if (flag) break;
  }
}

#endmodule // code_skeleton
