#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
};


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