#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

#ifndef __ASSOC_H
#include <assoc.h>
#endif

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

class TForm;
class TMask_field;
class TSheet_field;    
class TForm_item;
class TPrint_section;

const int MAXCOLUMNS = 32;

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

  bkg_mode  _background_mode;

  TString   _name;        // Profile name                     
  TString   _code;        // Profile code                    
  TString   _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
  char    _fink[11];      // finkatur characters       
  
  
  static void header_handler(TPrinter& p);
  static void footer_handler(TPrinter& p);                                         

  const char* get_fincatura()    { return _fink; }
  void set_fincatura(const char* s);
                                               
  // come sotto ma per printsection, all'uopo di chiamarle
  // con ricorsiva insistenza                                              
                                                 
protected:                                                
  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);                                               
  TPrint_section* exist(char s, pagetype t, bool create = FALSE);   // Can be NULL
  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
  // Queste due funzioni vengono chiamate per controlli non standard nell'edit della sezione
  virtual void pre_edit_checks(TMask&m, TPrint_section* sec) {}
  virtual bool post_edit_checks(TMask& m, TPrint_section* sec) {return FALSE;} 
  
  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:               
                                       
  // genera automaticamente la sezione grafica con colonne fincate
  // parametri: posizione pagina, prima e ultima Y per le righe
  // verticali, array di posizioni riga con 0 per finire  
  // ritorna FALSE se non c'e' il body per quella pagina                                   
  bool genera_fincatura(pagetype p, int y1, int y2,  const int* rows);
 
  // Genera le righe di intestazione colonna alla riga indicata, vale per COLUMNWISE
  // I form_items di intestazione vengono aggiunti alla sezione header di tipo p con ID -1
  bool genera_intestazioni(pagetype p, short y);
  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; }
  
  virtual const char* section_mask() { return "ba2100s"; }
  bool edit_level() const { return _editlevel; }
  void set_edit_level(int n) { _editlevel = n; }
  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; }
  TString& 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                                          
  virtual void change_number_format(int w, int dec, const char* p);                     
  // Rilegge la sezione specificata
  bool reread(char sec, pagetype p, bool force=FALSE);
  // editor interface
  TForm_editor& editor() const;
  
  // Notifica l'inizio di stampa dell'ultima pagina
  void set_last_page(bool lp) { _lastpage = lp; }
  
  // Setta il modo di sfondo (fincatura)
  void set_mode(bkg_mode b);
  bkg_mode mode() { return _background_mode;}
  // 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;
  bool finkl     : 1;
  bool finkr     : 1;
  bool memo      : 1;
  
protected:
  void print_on(ostream& out) const;

public:
  TForm_flags();

  void set_shown(bool b)   { shown = b; }
  void set_finkl(bool b)   { finkl = b; }
  void set_finkr(bool b)   { finkr = b; }
  void set_memo (bool b)   { memo  = b; }
  void print_on(TMask& m);
  void read_from(const TMask& m);

  bool update(const char* s);
};

class TPrint_section : public TArray
{
  static TMask* _msk;    

  word _height;           // Altezza della sezione
  word _ofspc;            // Offset prima colonna
  word _ofsvr;            // Offset verticale intestazione colonna
  word _nfld;             // number of columns if columnwise
  bool _dirty;            // Flag di modifica parametri
  bool _columnwise;       // Columnwise field specification
  bool _temp;             // temporanea (da non salvare)
  
  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 
  
  int    _tab[MAXCOLUMNS]; // columns offset if columnwise
  
  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);

  // handlers for section editing
  static bool detail_field_handler(TMask_field&, KEY);
  static bool special_field_handler(TMask_field&, KEY);
  static bool detail_field_notify (TSheet_field&, int, KEY);

public:

  TPrintrow& row(int num);
  TForm& form() const { return *_form; }
  
  TArray&     field_array() { return _item; }
  TForm_item& field(int n) const { return (TForm_item&)_item[n]; }
  TForm_item& find_field(short id) const;
  void        destroy_field(int n, bool c = TRUE) {  _item.destroy(n, c);  }
  void        destroy_fields() { _item.destroy(); }
  void        change_field(int n, TForm_item* f);
  void        insert_field(int n, TForm_item* f);                 
  void        add_field(TForm_item* f);

  virtual bool& temp() { return _temp; };
  virtual bool  temp() const { return _temp; };
  
  word fields() const { return _item.items(); }
  // returns 0 if not columnwise; means n. of printable fields             
  word columns()      { tab(0); return _nfld; }
  word height() const { return _height; }
  word ofspc()  const { return _ofspc; }
  word ofsvr()  const { return _ofsvr; }
  void offset(int& x, int& y);
  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; }
  bool columnwise() const { return _columnwise; }
  // ritorna l'offset della colonna corrispondente se columnwise
  int   tab(int col);                                            
  void  reset_tabs();                                            
  
  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_item : public TObject
{
  friend class TPrint_section;
  TPrint_section* _section;
  TForm_flags _flag;
  TBit_array _group;
  TAssoc_array _special;
  bool _temp;

protected:       

  short _id, _x, _y, _width, _height, _effective_height, _ofs;
  TString _prompt;
  TString _desc, _col_head;
  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);

  const char* get_special_item(const char* s, int n) const;

public:

  short id() const { return _id; }     
  virtual short& id() { return _id; };
  virtual int width() const { return _width; } 
  virtual short& width() { return _width; } 
  virtual int height() const { return _height; }
  virtual short& height() { return _height; }
  virtual short& ofs() { return _ofs; }
  virtual int effective_height() const { return _effective_height; }

  virtual bool& temp() { return _temp; };
  virtual bool  temp() const { return _temp; };
  bool has_memo() const { return _flag.memo; }
  
 // virtual short& x() { return _x; };
  virtual void set_x(short x) {_x=x;}
  virtual short x();
  virtual short& y() { return _y; }
  virtual short y() const { return _y; }
  virtual short get_column() { CHECK(_section->columnwise(),"La sezione non e' COLUMNWISE"); return _x; }
  virtual void  set_column(short c) {  CHECK(_section->columnwise(),"La sezione non e' COLUMNWISE"); _x = c;}
  virtual const int fields() { return 0;}
  
  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; }
  bool finkl()    const { return _flag.finkl;    }
  bool finkr()    const { return _flag.finkr;    }
  bool memo()     const { return _flag.memo;     }

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

  virtual void print_on(TMask& m);
  virtual void print_on(TRectype& rform);
  virtual void print_on_sheet_row(TToken_string& t) const;

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

  virtual bool edit(TMask& m); 

  virtual const char* get() const { return _prompt; }
  virtual bool set(const char* s) { _prompt = s; return TRUE; }

  // example() ritorna un esempio del formato corrente
  virtual const char* example() const { return ""; }
  
  const TString& col_head() const {CHECK(_section->columnwise(),"La sezione non e' COLUMNWISE"); return _col_head;}
  void set_col_head(const char* s) {CHECK(_section->columnwise(),"La sezione non e' COLUMNWISE"); _col_head = s;}
  const TString& prompt() const { return _prompt; }
  void set_prompt(const char* s) { _prompt = s; }
  
  virtual TToken_string& memo_info();         // Da' CHECK
  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); }
                                                     
  // variabili personalizzate   low-level                                                
  int           special_items() const { return _special.items(); }
  TAssoc_array& specials() const { return (TAssoc_array&)_special; }
  
  // high-level
  int get_special_names(TString_array& r);
  const char* get_special_value(const char* s) const { return get_special_item(s, 1); }
  const char* get_special_type (const char* s) const { return get_special_item(s, 0); }   
  const char* get_special_desc (const char* s) const { return get_special_item(s, 2); }
  
  TForm_item(TPrint_section* section);
  virtual ~TForm_item() {}
};


#endif
