#ifndef __FORM_H
#define __FORM_H

#ifndef __SCANNER_H
#include <scanner.h>
#endif

#ifndef __PRINTER_H
class TPrinter;
class TPrintrow;
#endif

#ifndef __MASK_H
class TMask;
#endif

#ifndef __ISAM_H
class TRectype;
#endif

#ifndef __RELATION_H
class TRelation;
class TRelation_description;
class TCursor;
#endif

enum pagetype { odd_page, even_page, first_page, last_page };
pagetype char2page(char); // prototipo della funzione che converte dalla notazione carattere al corrispondente enum pagetype

class TForm;
class TForm_item;

class TPrint_section : public TArray
{
  static TMask* _msk;

  word _height;           // Altezza della sezione
  bool _dirty;            // Flag di modifica parametri

  TForm* _form;           // Form cui appartiene alla sezione
  char _sec_type;         // H, B, F, G
  pagetype _page_type;    // Tipo della pagina
  bool _subsection;       // e' una sottosezione                                 
  
  TArray _item;           // Lista dei campi da stampare
  int    _repeat_count;   // n. ripetizioni eseguite 
  
  const TPrint_section& copy(const TPrint_section& ps);
  
protected:
  virtual void print_on(ostream& out) const;
  virtual TForm_item* parse_item(const TString& key);
  TForm_item* parse_item(TScanner& scanner);

public:
  TPrintrow& row(int num);
  TForm& form() const { return *_form; }
  
  TForm_item& field(int n) const { return (TForm_item&)_item[n]; }
  TForm_item& find_field(short id) const;

  word fields() const { return _item.items(); }
  word height() const { return _height; }
  void offset(int& x, int& y) const;
  void set_repeat_count(int x) { _repeat_count = x; }
  
  virtual bool ok() const { return height() > 0 || fields() > 0; }
  
  void reset();
  virtual bool update();
  bool parse(TScanner& scanner);
  
  bool read_from(const TRectype& rec);
  void print_on(TRectype& rec);

  bool edit(const char* title);
  char section_type() const { return _sec_type; }
  pagetype page_type() const { return _page_type; }
  
  bool dirty() const { return _dirty; }
  void set_dirty(bool d = TRUE) { _dirty = d; }
  
  const TPrint_section& operator=(const TPrint_section& ps) { return copy(ps); }
  TPrint_section(TForm* parent, char st, pagetype pt, bool subsection = FALSE);
  TPrint_section(const TPrint_section& ps) { copy(ps); }
  virtual ~TPrint_section();
};


class TForm : public TObject
{                    
  friend class TForm_editor;
  friend class TPrint_section;

  TString16 _name;        // Profile name                     
  TString16 _code;        // Profile code                    
  TString80 _fontname;    // Font name
  int       _fontsize;    // Font size
  int       _x, _y;       // Offset validi per tutte le sezioni
  char      _char_to_pos; // Carattere utilizzato per il posizionamento dei moduli
  int       _ipx, _ipy;   // Coordinate del posizionamento iniziale
  int       _fpx;         // Coordinata del posizionamento finale (la riga e' la stessa)
  bool      _dirty;       // Flag per ragistrare i parametri(font ed offset)
  
  TRelation* _relation;   // Can be NULL
  TCursor* _cursor;       // Can be NULL
  TRelation_description* _rel_desc; // Can be NULL

  TArray _head;           // Headers
  TArray _body;           // Bodies
  TArray _foot;           // Footers
  TArray _back;           // Graphic backgrounds

  bool   _lastpage;       // I am about to print the last page?

  bool   _isnew;          // new form
  bool   _isbase;         // base form (.frm file)    
  bool   _arrange;        // if TRUE perform arranging every time 
  int    _editlevel;      // Edit permission
  TString _desc;          // form description
  TToken_string _fink;    // finkatur characters       
  
  TPrint_section* exist(char s, pagetype t, bool create = FALSE);   // Can be NULL
  
  static void header_handler(TPrinter& p);
  static void footer_handler(TPrinter& p);                                         

  TToken_string& get_fincatura()    { return _fink; }
  void set_fincatura(const char* s) { _fink = s;    }
                                               
  // come sotto ma per printsection, all'uopo di chiamarle
  // con ricorsiva insistenza                                              
  bool ps_change_date_format(TPrint_section& s, const char* f);                                               
  bool ps_change_number_format(TPrint_section& s, int w, int dec, const char* p);                                               
                                                 
protected:                                                
  void init(); // inizializza il form
  void read(const char* form, const char* code = "", int editlevel = 0, const char* desc = ""); // carica il form dal file specificato

  // H = Header, B = Body, F = Footer, R = Relation
  TPrint_section& section(char s, pagetype pos);   // La crea se non esiste
  TPrint_section& section(char s, word page = 3);  // La crea se non esiste (3 e' una pagina dispari qualsiasi)

  word height(word page = 1);          // Height of a page (the first by default)
  
  void print_section(ostream& out, char s) const;
  virtual void print_on(ostream& out) const;
  
  bool parse_use(TScanner&);
  bool parse_join(TScanner&);
  
  bool parse_description(TScanner&);
  void print_description(ostream& out) const;
  
  bool parse_general(TScanner&);
  void print_general(ostream& out) const;
  virtual void extended_parse_general(TScanner&) {} // Used to parse non-standard items in general section
  
  bool read_profile();
  bool write_profile();
  
  word page(const TPrinter& p) const;
  void arrange_form();
  
  virtual long records() const;
  virtual word set_background(word p, bool u);
  virtual word set_header(word p, bool u);
  virtual word set_body(word p, bool u);
  virtual word set_footer(word p, bool u);
  
public:               

  bool print(long from = 0L, long to = -1L);
  
  TArray& body() { return _body; }
  TArray& head() { return _head; }
  TArray& foot() { return _foot; }
  TArray& back() { return _back; }

  const TString& name() const { return _name; }
  const TString& code() const { return _code; }
  
  bool edit_level() const { return _editlevel; }
  void set_description(const char* s) { _desc = s; }
  
  virtual TRelation* relation() const { return _relation; }
  virtual TCursor* cursor() const { return _cursor; }
  TRelation_description& rel_desc() const;
  virtual bool validate(TForm_item& fld, TToken_string& val);
  
  TForm_item& find_field(char sec, pagetype pag, short id) const;
  int& offset_x()  { return _x; }
  int& offset_y()  { return _y; }
  TString80& fontname() { return _fontname; }
  int&  fontsize()   { return _fontsize; } 
  char& char_to_pos(){ return _char_to_pos; }
  int&  ipx()   { return _ipx; }
  int&  ipy()   { return _ipy; }
  int&  fpx()   { return _fpx; }
  bool dirty() const { return _dirty; }
  void set_dirty(bool d = TRUE) { _dirty = d; }
  void set_arrange(bool arng = TRUE) { _arrange = arng ; }
                                            
  // cambia il formato di tutte le date nel form                                          
  void change_date_format(const char* f);                     
  // cambia il formato di tutti i numeri nel form                                          
  void change_number_format(int w, int dec, const char* p);                     
                       
  // fincazione                                              
  char f_topleft()      { return _fink.get_char(0);  }                                              
  char f_topmiddle()    { return _fink.get_char(1);  }                                              
  char f_topright()     { return _fink.get_char(2);  }                                              
  char f_botleft()      { return _fink.get_char(3);  }                                              
  char f_botmiddle()    { return _fink.get_char(4);  }                                              
  char f_botright()     { return _fink.get_char(5);  }                                              
  char f_centerleft()   { return _fink.get_char(6);  }                                              
  char f_centermiddle() { return _fink.get_char(7);  }                                              
  char f_centerright()  { return _fink.get_char(8);  }                                              
  char f_horizontal()   { return _fink.get_char(9);  }                                              
  char f_vertical()     { return _fink.get_char(10); }                                              
  
  // Notifica l'inizio di stampa dell'ultima pagina
  void set_last_page(bool lp) { _lastpage = lp; }

  // if code == NULL it's a base form
  // otherwise it's integrated by a file definition                                       
  TForm();
  TForm(const char* form, const char * code = "", int editlevel = 0, const char* desc = "");
  virtual ~TForm();
};

struct TForm_flags : public TObject
{
  bool automagic : 1;
  bool enabled   : 1;
  bool shown     : 1;
  bool dirty     : 1;
  
protected:
  void print_on(ostream& out) const;

public:
  TForm_flags();

  void print_on(TMask& m);
  void read_from(const TMask& m);

  bool update(const char* s);
};

class TForm_item : public TObject
{
  TPrint_section* _section;
  TForm_flags _flag;
  TBit_array _group;

protected:
  short _id, _x, _y, _width, _height, _effective_height;
  TString _prompt;
  TString _desc;
  TString_array _message;

  virtual void print_on(ostream& out) const;
  virtual void print_body(ostream& out) const;

  virtual bool parse_head(TScanner&);
  virtual bool parse_item(TScanner&);

  TToken_string& message(int m = 0);
  void send_message(const TString& cmd, TForm_item& dest) const;
  bool do_message(int m = 0);
  
  void string_at(int x, int y, const char* s);
  
public:
  short id() const { return _id; }     
  virtual int width() const { return _width; } 
  virtual void set_width(int w) { _width = w; } 
  virtual int height() const { return _height; }
  virtual int effective_height() const { return _effective_height; }
  virtual short& x() { return _x; }
  virtual short& y() { return _y; }

  bool shown() const { return _flag.shown; }
  bool hidden() const { return !_flag.shown; }
  bool enabled() const { return _flag.enabled; }
  bool disabled() const { return !_flag.enabled; }
  bool automagic() const { return _flag.automagic; }

  virtual bool parse(TScanner&);
  virtual bool update();

  virtual void print_on(TMask& m);
  virtual void read_from(const TMask& m);
  
  virtual bool read_from(const TRectype& rform);
  virtual void print_on(TRectype& rform);

  virtual bool edit(TMask& m); 

  virtual const char* get() const { return _prompt; }
  virtual bool set(const char* s) { _prompt = s; return TRUE; }
  const TString& prompt() const { return _prompt; }
  
  virtual const TString& picture() const;     // Da' CHECK
  virtual void  set_picture(const char*);     // Da' CHECK

  TPrint_section& section() const { return *_section;         }
  TForm&          form()    const { return _section->form();  }
  TForm_item&     find_field(const TString& id) const;
  
  void set_dirty(bool d = TRUE) { _flag.dirty = d; }
  bool dirty() const { return _flag.dirty; }
  
  bool in_group(byte g) const { return g == 0 || _group[g];   }
  const TString& key() const { return _desc; }
  virtual void print_on(TToken_string& row) const;

  virtual void show(bool on = TRUE) { _flag.shown = on; }  
  void hide() { show(FALSE); }
  virtual void enable(bool on = TRUE);
  void disable() { enable(FALSE); }

  TForm_item(TPrint_section* section);
  virtual ~TForm_item() {}
};

#endif
