#ifndef __PRINTER_H
#define __PRINTER_H

#ifndef __STDIO_H
#include <stdio.h>
#endif

#ifndef __DATE_H
#include <date.h>
#endif

#ifndef __TEXT_H
#include <text.h>
#endif                   


// @DPUB
enum TPrintstyle 
{
  normalstyle     = 0,
  boldstyle       = 1,
  underlinedstyle = 2,
  italicstyle     = 4
  };

enum TPrtype 
{
  normprinter  = 0,
  fileprinter  = 1,
  spoolprinter = 2,
  localprinter = 3,
  screenvis    = 4,
  winprinter   = 5,
  export       = 6
  };


// @END

// @C
// class TPrintrow : public TObject
// @END

class TPrintrow : public TObject
{
  enum { MAXSTR = 256 };

  // @DPROT
  TString256  _row;          // the actual string to print
  char        _attr[MAXSTR]; // contains char attributes of _row
  int         _cols[MAXSTR]; // contains color attributes of _row
  TBit_array  _tab;

  TPrintstyle _currentstyle; // the current char attribute
  int         _currentcolor; // the current color attribute
  int         _lastpos;      // last print position

public:
  // @FPUB
  TPrintrow();
  TPrintrow(const TPrintrow& pr);
  virtual ~TPrintrow() {}

  //  TPrintrow&      center(const char* str, int position);
  virtual word        class_id() const;
  virtual const char* class_name() const;
  virtual TObject* dup() const;

  const char* row() const { return _row; }
  const char* row_codified() const;
  TPrintrow& reset();

  TPrintstyle get_style(int position) const { return (TPrintstyle)_attr[position]; }
  TPrintstyle get_style() const { return _currentstyle; }
  int get_color(int position) const { return (TPrintstyle)_cols[position]; }
  int get_color() const { return _currentcolor; }
  TPrintrow& put(const char* str, int position = -1, int len=0);
  void set_style(TPrintstyle style)  { _currentstyle=style; }
  int  lastpos() const { return _lastpos; }
};

class PrinterDef : public TObject
{
  friend class TPrinter;
  TString _printername;   // name of the printer file
  TString _printertype;   // type of printer (0=diretta,1=locale,2=spool)
  TString _filtername;    // filter for the pipe (UNIX only)
  TString _devicename;    // name of print device
  char    _atstr[4][10];  // attribute codes for the current printer
  TString_array _codes;   // print codes
  TString_array _names;   // name of print codes
  TString _ffcode;        // formfeed code for the current printer
  TString _nlcode;        // special newline code for the current printer

public:
  bool read(const char* name, FILE* fd);    // read description from file;
  bool isdefault();       // name matches "Default"
  const char* get_codenames(word i) const { return  i < (word)_names.items() ? (const char*)_names.row(i) : NULL; }
  const char* get_codes(word i) const { return  i < (word)_codes.items() ? (const char*)_codes.row(i) : NULL; }
  PrinterDef() : _printername(10), _filtername(10), _ffcode("\f"), _nlcode("\n") {}
};


class BkDef : public TObject
{
public:
  int     _id;
  int     _father_id;
  TString _txt;
  long    _row;
  
  BkDef() {}
  virtual ~BkDef() {}
};


class TPrinter;

typedef void (*PRINTSECTIONHANDLER)(TPrinter& printer);
typedef void (*LINKHANDLER)(int, const char*);


// @C
// class TPrinter : public TObject
// @END

class TViswin;               

class TPrinter : public TObject
{
  // @DPROT

  FILE* _cnfptr;          // config file
  FILE* _fp;              // pointer to the printer file
  TViswin* _vf;           // pointer to file visualizer

  TTextfile _txt;
  TFilename _exportfile;  // name of export file
  int _headersize;
  int _footersize;
  TArray _header;
  TArray _footer;
  TArray _printers;       // printers descriptions
  int    _curprn;         // current printer index
  int    _curcode;        // current printer index
  int    _formlen;        // length of the logic page
  int    _formwidth;      // size of the logic page
  int    _currentrow;     // next row to print

  TString80 _fontname;    // Font name
  int    _ch_size;        // Font height

  word   _currentpage;    // logic page containing _currentrow
  word   _frompage;       // first page to print (normally 0)
  word   _topage;         // last page to print (normally = USHRT_MAX)
  bool   _hwformfeed;     // if TRUE a ff will be printed after any footer
  TPrtype _printertype;   // specifies the kind of output the user wants
  bool   _isopen;         // printer open
  TDate  _date;           // printing date
  TFilename _printerfile; // filename for printing on file
  TArray _linksdescr;        
  TArray _bookmarks;      // bookmarks
  bool   _multiple_link;  //
  
  TString _config;        // Nome del paragrafo di configurazione

  TString_array _background;     
  TString_array _image_names;

  const char*  _bg_desc;                                            
  TToken_string _printer_names;
  bool          _isgraphics;
  bool          _frozen; 
  int     _ncopies;
#if XVT_OS == XVT_OS_WIN
  PRINT_RCD*  _print_rcd;
  int         _print_rcd_size;
#endif                          
  int         _lines_per_inch;
  int         _vert_offset;
  int         _horz_offset;
  int         _dots_per_line;                                     
  
  void        _get_windows_printer_names(TToken_string& t);
  bool        _multiple_copies;
  bool        _export_header;                                   
  int         _export_header_len;
  
  PRINTSECTIONHANDLER _headerhandler, _footerhandler;
  LINKHANDLER         _linkhandler;   
  
  // @END

  // @FPROT
protected:
  virtual char newline() { return '\n'; }
  bool printrow (TPrintrow* rowtoprint=NULL); // base methods for printing
  bool printformfeed ();

  bool printheader();
  bool printfooter();

  void save_configuration();

public:

  // @FPUB
  TPrinter ();
  virtual ~TPrinter();    
  
#if XVT_OS == XVT_OS_WIN        
  static BOOLEAN XVT_CALLCONV1 start_winprint(long);
#endif

  void set_from_page (word from) { _frompage = from; }
  void set_to_page (word to) { _topage = to; }
  void set_hwff (bool hwff) { _hwformfeed = hwff; }

  // resa pubblica per farsi usare dagli altri
  // la stampante e' un servizio, se non si fa usare
  // che servizio e'?
  void parse_background(const char* bgdesc, TArray& bg);

  int descriptions() { return _printers.items(); }
  const PrinterDef& get_description(word i) const { return (const PrinterDef&) _printers[i]; }
  
  virtual const char* class_name() const;
  virtual word        class_id()   const;

  int         formlen       () const  { return _formlen; }
  int         formwidth     () const  { return _formwidth; }

  word        frompage      () const  { return _frompage; }
  word        topage        () const  { return _topage; }
  int         headersize    () const  { return _headersize; }
  int         footersize    () const  { return _footersize; }
  TPrintrow*  getheaderline (int linetoget);
  TPrintrow*  getfooterline (int linetoget);
  int         formlen       (int fl)  { return (_formlen=fl); }
  int         footerlen     (int fl)  { return (_footersize=fl); }
  int         headerlen     (int hl)  { return (_headersize=hl); }
  word        frompage      (word fp) { return (_frompage=fp);}
  word        topage        (word tp) { return (_topage=tp); }
  void        setheaderline (int linetoset, TPrintrow* line);
  void        setheaderline (int linetoset, const TPrintrow& line);
  void        setfooterline (int linetoset, TPrintrow* line);
  void        setfooterline (int linetoset, const TPrintrow& line);
  void        resetheader();
  void        resetfooter();                                    
  void        setbackground(const char* bg);     
  TString_array&     image_names()   { return _image_names; }
  TString_array&     getbgdesc()     { return _background; }
  TArray&            get_bookmarks() { return _bookmarks;  }
  bool        frozen() { return _frozen; } 
  void        freeze(bool b = TRUE) { _frozen = b; }
  int         n_copies() { return _ncopies; }
  void        enable_multiple_copies(bool b = TRUE) { _multiple_copies = b; }
  
  TToken_string& getprinternames();
  TTextfile& get_txt() { return _txt; }
  
  void setheaderhandler(PRINTSECTIONHANDLER h) { _headerhandler = h; }
  void setfooterhandler(PRINTSECTIONHANDLER h) { _footerhandler = h; }

  // used by viswin()
  // sono qui e non nella printapp per poter usare una viswin
  // completamente anche da un'altra application
  void setlinkhandler(LINKHANDLER h)           { _linkhandler   = h; }
  LINKHANDLER getlinkhandler()                 { return _linkhandler; }
  TArray& links() { return _linksdescr; }
  void setmultiplelink(bool on) { _multiple_link = on;   }
  bool ismultiplelink()         { return _multiple_link; }

  bool              skip          (int linetoskip);
  bool              jump          (int linestojump);
  void              reset         ();
  virtual void      set           ();
  bool              open          ();
  void              close         ();
  bool              formfeed      ();
  bool              print         (TPrintrow& rowtoprint);
  bool              isopen()      { return _isopen; }
  void        setdate(const TDate& d) { _date = d; }
  const TDate& getdate() const { return _date; }
  TPrtype     printtype()  { return _printertype; }
  void        set_printtype(TPrtype dest)  { _printertype=dest; }
  void        set_printerfile(const char * ffile)  { _printerfile=ffile; }
  word        getcurrentpage() const { return _currentpage; }
  void        setcurrentpage(word n) { _currentpage = n; }  
  // dirige la stampa sul file specificato, preservando gli attributi di formato  
  // se header == TRUE si stampano su file anche gli header    
  void        set_export_file(const char* n, bool header = TRUE, int len = 0) 
  { _printertype = export; _exportfile = n; _export_header = header;
    _export_header_len = len;}
  // infila un file di export fatto da un'altra printer (con formati e tutto, ignora
  // gli header supponendo che siano gia' presenti nel file)
  // se header == TRUE gli header stanno nel file e non vengono stampati
  void        merge_export_file(const char* file, bool header = TRUE);
  word rows() const { return _formlen-_headersize-_footersize; }
  word rows_left() const;                                   
#if XVT_OS == XVT_OS_WIN        
  void        set_printrcd();
  PRINT_RCD*  get_printrcd(int* size = NULL);
  void        set_win_formlen(WINDOW prwin = NULL_WIN);  
#endif
  void        set_lines_per_inch(int n)  { _lines_per_inch = n;    }
  int         get_lines_per_inch() const { return _lines_per_inch; }
  int         get_vert_offset()    const { return _vert_offset; }
  int         get_horz_offset()    const { return _horz_offset; }
  int         get_dots_per_line()  const { return _dots_per_line; }
  bool        isgraphics()         const { return _isgraphics;    }
  
  int         get_char_size()      const { return _ch_size; }
  char*       fontname()           const { return (char*)(const char*)_fontname; }
  
  void read_configuration(const char* parag = NULL);

  // bookmarks
  int set_bookmark(const char* txt, int father = -1);
};



class TFile_printer : public TPrinter
{
  long     _size;
  const char * _drive;
  int     _volume;          // numero progressivo volume
  int     _num_rec_volume;  // numero di record per disco
  int     _num_rec_testa_coda;  // numero di record per inizio e fine volume
  int     _num_rec_inizio;  // numero di record per inizio volume
  int     _num_rec_fine;    // numero di record per coda volume
  int     _len_rec;         // lunghezza record
  TArray  _record;          // array di tipi record
  bool    _nome_file_fissato;  // se il file sui dischetti deve avere un nome NON modificabile dall'utente
  bool    _label_fissata;  // se l'etichetta dei dischetti deve essere fissa
  bool    _formatta;
  const char * _file;          // file da generare sui dischetti
  const char * _label;          // etichetta da scrivere sui dischetti
  TArray  _tmp_files;      // array dei file temporanei generati
  FILE       * _fd;

  //  bool scrivi_volume();

public:

  virtual char newline() { return '\0'; }
  void set_file_fissato (bool fissato) { _nome_file_fissato = fissato; }
  void set_label_fissata (bool fissata) { _label_fissata = fissata; }
  void set_len_rec (int len) { _len_rec = len; }

  void set_file (const char * ffile) { _file = ffile; }
  void set_label (const char * label) { _label = label; }

  void set_record (int record_to_set, TPrintrow* line) 
  {_record.add(line, record_to_set); }

  TPrintrow * get_record (int record_to_get) 
  {return (TPrintrow *)&_record[record_to_get]; }

  TPrintrow* get_record_inizio_volume() const { return (TPrintrow*)&_record[0];}
  TPrintrow* get_record_inizio_elenco() const {return (TPrintrow*)&_record[1];}
  TPrintrow* get_record_dettaglio() const { return (TPrintrow*)&_record[2]; }
  TPrintrow* get_record_fine_elenco() const {return (TPrintrow*)&_record[3]; }
  TPrintrow* get_record_fine_volume() const { return (TPrintrow*)&_record[4]; }
  TPrintrow* get_record_filler() const { return (TPrintrow*)&_record[5]; }

  int  num_rec_volume () { return _num_rec_volume; }
  int  num_volumi () { return _volume; }
  void inc_volume () { _volume++; }

  void add_file (TFilename nomef) { _tmp_files.add(nomef); }

  void open();
  void close();

  //  void scrivi();
  bool genera_dischetti();

  virtual void set ();

  //
  // tipo_disco: 
  //              0 per 360
  //              1 per 1.2
  //              2 per 720
  //              3 per 1,44
  //              4 per 2,88
  //
  TFile_printer (const char* file, 
                 const char* label, 
                 int len_rec, 
                 int num_rec_inizio = 1, 
                 int num_rec_fine = 1, int tipo_disco=0);

  virtual ~TFile_printer();
};

TPrinter& printer();
void printer_destroy();

#endif  // __PRINTER_H