#ifndef __PRINTER_H
#define __PRINTER_H

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

#ifndef __STRINGS_H
#include <strings.h>
#endif

#ifndef __ARRAY_H
#include <array.h>
#endif

#ifndef __VISWIN_H
#include <viswin.h>
#endif

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

#ifndef __PRINTWIN_H
#include <printwin.h>
#endif

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

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

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
  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();
  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
  TArray  _codes;         // print codes
  TArray  _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*)(TString&)_names[i] : NULL; }
  const char* get_codes(word i) const { return  i < (word) _codes.items() ? (const char*)(TString&)_codes[i] : NULL; }
  PrinterDef() : _printername(10), _filtername(10),
  _ffcode("\f"), _nlcode("\n")
  {}
};


class TPrinter;

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


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

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 _config;      // name of the configuration file
  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    _currentrow;        // next row to print
  int    _ch_size;
  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;        
  bool   _multiple_link;  //
  TArray _background;     
  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 _parse_background();
  void _get_windows_printer_names(TToken_string& t);
  bool        _multiple_copies;
  bool        _export_header;                                   
  
  PRINTSECTIONHANDLER _headerhandler, _footerhandler;
  LINKHANDLER         _linkhandler;   
  
  // @END

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

  bool printheader();
  bool printfooter();

public:

  // @FPUB
  TPrinter ();
  virtual ~TPrinter();    
  
#if XVT_OS == XVT_OS_WIN        
  static BOOLEAN start_winprint(long);
  
#endif
  void set_config_file (const char * ffile) { _config = ffile ; }
  void set_from_page (word from) { _frompage = from; }
  void set_to_page (word to) { _topage = to; }
  void set_hwff (bool hwff) { _hwformfeed = hwff; }

  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; }
  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);     
  TArray*     getbgdesc() { return &_background; }
  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; }
  TPrtype     printtype()  { return _printertype; }
  void        set_printtype(TPrtype dest)  { _printertype=dest; }
  void        set_printerfile(const char * ffile)  { _printerfile=ffile; }
  word        getcurrentpage() { 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) 
  { _printertype = export; _exportfile = n; _export_header = header; }
  // 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        
  PRINT_RCD*  get_printrcd() { return _print_rcd; }
  void        set_printrcd(PRINT_RCD* p) { _print_rcd = p; }
  int&        get_printrcdsize() { return _print_rcd_size; }
  void        set_win_formlen();  
#endif
  void        set_lines_per_inch(int n) { _lines_per_inch = n;    }
  int         get_lines_per_inch(int n) { return _lines_per_inch; }
  int         get_vert_offset()         { return _vert_offset; }
  int         get_horz_offset()         { return _horz_offset; }
  int         get_dots_per_line()       { return _dots_per_line; }
  bool        isgraphics()              { return _isgraphics;    }
  int         get_char_size()           { return _ch_size; }
};



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();
};

#endif  // __PRINTER_H
