#ifndef __PRINTAPP_H
#define __PRINTAPP_H

#ifndef __APPLICATION_H
#include <applicat.h>
#endif

#ifndef __PRINTER_H
#include <printer.h>
#endif

#ifndef __RELATION_H
#include <relation.h>
#endif

// compatibility 
#define TPrintapp TPrint_application

// @doc INTERNAL

// @enum print_action
enum print_action { 
  REPEAT_PAGE,  // @emem Ripeta la stampa dell'ultima pagina
  NEXT_PAGE };  // @emem Stampa la prossima pagina

// @doc EXTERNAL

// @func funzione per il passaggio delle informazioni alla <mf TPrint_application::set_row>
//
// @rdesc Ritorna una stringa contenente i parametri passati separati dal pipe
const char* FLD(
  int lognum,    // @parm Numero logico
  const char* f, // @parm Nome campo numerico
  int from = -1, // @parm Da (default -1)
  int to = -1);  // @parm A (default -1)
  // @parm const char* | picture | Picture string
  // @parm const char* | tabname | Nome tabella

  // @syntax const char* FLD(int lognum, const char* f, int from, int to);
  // @syntax const char* FLD(int lognum, const char*  f, const char* picture);
  // @syntax const char* FLD(const char* tabname, const char*  f, const char* picture);
  // @syntax const char* FLD(const char* tabname, const char* f, int from, int to);

  // @devnote Non viene creata una classe o una interfaccia C++ gradevole fino a quando varargs
  //        non assume un aspetto adeguato

  const char* FLD(int lognum, const char*  f, const char* picture);

  const char* FLD(const char* tabname, const char*  f, const char* picture);

  const char* FLD(const char* tabname, const char* f, int from = -1, int to = -1);

// @doc EXTERNAL

  // @struct link_item | Definisce il file a cui si riferisce il link da effettuare sulla stampa
  struct link_item {
    int _logicnum;       // @field Numero logico del link (default l)
    link_item* _son;     // @field File link figlio (default NULL)
    link_item* _brother; // @field File link fratello (default NULL)
    int _cnt;       // @field Contatore indicante il numero di volte che viene ripetuta 
    //        la stampa (default 0)

    link_item(int l)        // @field void | link_item(int l) | Inizializza il numero logico del link
    { _logicnum = l; _son = NULL; _brother = NULL; _cnt = 0; }
  };


class TProgind;

// @doc EXTERNAL

// @class TPrint_application | Classe per la definizione delle applicazioni per la stampa
//
// @base public | TApplication
class TPrint_application : public TApplication

// @author:(INTERNAL)Villa

// @comm ISTRUZIONI PER l'USO
//       <nl>La Printapp consente di operare su uno
//       o piu' cursori stampando automaticamente anche files
//       collegati. La sequenza delle operazioni e' la seguente:
//
//       <nl>1) Derivare una classe da TPrint_application
//       <nl>2) Implementare <mf TPrint_application::user_create> e <mf TPrint_application::user_destroy>;
//          Nella user_create() si creino i necessari cursori,
//          che vengono passati alla Printapp usando <mf TPrint_application::add_cursor>.
//          Si puo' fare add_cursor (new TCursor(...))
//          dato che il cursore viene distrutto automaticamente.
//       <nl>3) Per ciascun file del cursore che si desidera porre
//          nell'albero di stampa, si chiami la <mf TPrint_application::add_file>
//          es.: add_file(logicnum [,from]); <p from> sara' il file a cui e' 
//          collegato nella relazione. add_file VA FATTA anche per il file principale,
//          altrimenti non stampera' nulla;
//       <nl><nl>FUNZIONI VIRTUALI OBBLIGATORIE
//       <nl>4) Si definiscono le necessarie funzioni virtuali: e'
//          necessaria la <mf TPrint_application::set_page> nella quale
//          si metteranno (sotto if o switch) le istruzioni 
//          <mf TPrint_application::set_row> corrispondenti alla pagina
//          logica relativa a ciascun record di ogni file da stampare.
//          Va definita anche <mf TPrint_application::set_print> in cui si presentera'
//          la maschera di scelta se necessaria o una box yes_no.
//          Ritornando TRUE da set_print la stampa viene eseguita 
//          automaticamente (in genere ritorna FALSE se l'utente
//          annulla la stampa con ESC.)
//          
//          <nl><nl>Alla set_page, come alle pre_ e post_ process, viene
//          passato 0 se il cursore attuale e' nullo (vedi sotto).
//       <nl><nl>FUNZIONI VIRTUALI FACOLTATIVE
//       <nl>5) Le varie funzioni <mf TApplication::pre_process_page>
//          <mf TApplication::pre_process_print> <mf TApplication::post_process_page>
//          <mf TApplication::post_process_print>
//          vengono chiamate prima e dopo la stampa di ogni record
//          o gruppo di record relativo alla relazione immessa;
//          ad esempio, post_process_print() viene chiamata per il
//          file principale una volta dopo l'intera stampa; per
//          un file collegato nella relazione, e' chiamata tante
//          volte quanti gruppi di almeno un record esistono per
//          record del file genitore. Qui si possono modificare
//          righe, calcolare totali etc. A queste funzioni 
//          viene sempre passato il file (logicnum) in corso di stampa e
//          un contatore che indica quante volte la stampa e' stata
//          ripetuta. le pre_ ritornano TRUE o FALSE, nell'ultimo
//          caso interrompono la stampa; le post_ ritornano
//          <e print_action.NEXT_PAGE> (comportamento normale) o <e print_action.REPEAT_PAGE>
//       <nl>6) <mf Tprint_application::set_print> viene chiamata dalla voce Selezione,
//          unica del secondo menu. E' il posto dove mettere
//          una buona maschera di selezione di cosa stampare.
//          Alla fine, si esegua <mf TPrint_application::enable_print_menu> per
//          abilitare la voce Stampa, inizialmente inattiva.
//       <nl>7) <mf TPrint_application::cancel_hook> permette di intercettare la
//          cancellazione della stampa; ritornando TRUE
//          la stampa viene effettivamente cancellata
//          Tutti i parametri relativi al progress indicator
//          vengono settati da funzioni apposite (vedi oltre)

// @access:(INTERNAL) Private Member
{
  // @cmember:(INTERNAL) Descrittore delle righe
  TArray _rows;      
  // @cmember:(INTERNAL) Array di cursroi
  TArray _cursors;
  // @cmember:(INTERNAL) Cursore corrente
  TCursor* _cur;
  // @cmember:(INTERNAL) Tabella di traduzione dei campi
  TArray _transtab;
  // @cmember:(INTERNAL) Header delle linee
  TArray _header;
  // @cmember:(INTERNAL) Footer delle linee
  TArray _footer;
  // @cmember:(INTERNAL) Riga corrente di stampa
  int _currow;
  // @cmember:(INTERNAL) Stile corrente di stampa
  TPrintstyle _curstyle;
  // @cmember:(INTERNAL) Indica se effettuare il form feed automatico dopo ogni pagina
  bool _auto_ff;
  // @cmember:(INTERNAL) Indica se attivare barra per la classe <c TProgind>
  bool _wbar;
  // @cmember:(INTERNAL) Indica se abilitare o disabilitare il bottone Annulla
  bool _wcancel;
  // @cmember:(INTERNAL) Numero minimo di item per mostrare la barra di attesa
  int _wthr;     
  // @cmember:(INTERNAL) Carattere di riempimento per campi vuoti
  char _fillchar;
  // @cmember:(INTERNAL) Funzioni per la stampa automatica delle relazioni
  link_item* _pr_tree;
  // @cmember:(INTERNAL) Numero massimo di righe
  int _maxrow;
  // @cmember:(INTERNAL) Identificatore del file corrente
  int _cur_file;  
  // @cmember:(INTERNAL) Indica se � stat definita la stampante
  bool _print_defined; 
  // @cmember:(INTERNAL) Indica se forzare la presenza della barra di attesa anche nella stampe a video
  bool _force_progind;
  // @cmember:(INTERNAL) Indica se forzare la rilettura delle <mf TPrint_application::set_row>
  bool _force_setpage;
  // @cmember:(INTERNAL) Indica se stampare il valore 0 per i campi vuoti
  bool _print_zero;
  // @cmember:(INTERNAL) Barra di attesa
  TProgind* _prind;
  
  // @cmember:(INTERNAL) Picture default per i reali
  TString80 _picture;

  // @cmember:(INTERNAL) Valuta di stampa per TCurrency
  TString16 _curr_codval;
  // @cmember:(INTERNAL) Trasforma i real in TCurrency se necessario
  bool _magic_currency;

  // @cmember:(INTERNAL) Ultima scelta di men�
  MENU_TAG _last_choice;
  // @cmember:(INTERNAL) Numero di copie da stampare
  int _ncopies;
  // @cmember:(INTERNAL) Indica se si volgia ripetere la stampa
  bool _repeat_print;
  // @cmember:(INTERNAL) Indica se la stampa e' stata interrotta
  bool _cancelled;
  
// @access Protected Member
protected:
  // @cmember:(INTERNAL) Setta la stampante
  void  set_printer() 
  { printer().set(); }
  // @cmember:(INTERNAL) Stampa un singolo record
  bool print_one(int file);  
  // @cmember:(INTERNAL) Permette di stampare tutti i campi record cercando nell'albero i file corrispondenti
  bool print_tree(link_item* head);

  // @cmember:(INTERNAL) Metahandlers per controllare l'header quando si usa la 
  //          <c TViswin>; servono per controllare handlers di altre classi e chiamano
  //          virtuali di <c TPrintapp>.
  static void _pp_header(TPrinter& pr);
  // @cmember:(INTERNAL) Metahandlers per controllare il footer quando si usa la 
  //          <c TViswin>; servono per controllare handlers di altre classi e chiamano
  //          virtuali di <c TPrintapp>.
  static void _pp_footer(TPrinter& pr);
  // @cmember:(INTERNAL) Metahandlers per controllare i links quando si usa la 
  //          <c TViswin>; servono per controllare handlers di altre classi e chiamano
  //          virtuali di <c TPrintapp>.
  static bool _pp_link(int id, const char* s);

  // @cmember:(INTERNAL) Cerca per il nodo <p head> dove agganciarsi per rispettare la relazione
  link_item* _look_print_node(link_item* head, int logicnum);
  // @cmember:(INTERNAL) Annulla l'alebero a partire dal nodo <p head>
  void _reset_tree(link_item* head);
  // @cmember:(INTERNAL) Crea la finestra (vedi <mf TWindow::create>)
  virtual bool create();
  // @cmember:(INTERNAL) Distrugge la finestra
  virtual bool destroy();

  // @cmember Utilizzata per la creazione dei cursori necessari
  virtual bool user_create() pure;
  // @cmember Utilizzata per la distruzione dei cursori
  virtual bool user_destroy() pure;

  // @cmember Chiamata automaticamente dopo <mf TPrint_application::user_create>
  virtual bool set_print(int i = 1)        
  { return FALSE; }

  // @cmember Setta la pagina logica logica. La funzione <mf TPrint_application::set_row>
  //          DEVE essere chiamata qui in uno switch per ogni file particolare da stampare.
  virtual void set_page(int file, int cnt) 
  {}
  
  // @cmember Setta la strina di stampa dalla tabella o dal file. Viene chiamata prima di 
  //          processare ogni pagina, Non � inclusa nelle relazioni. <p count> � il numero 
  //          corrente della pagina da stampare.
  //          <nl>Ritornando FALSE viene cancellata la stampa delle pagine
  virtual bool preprocess_page(int file, int counter) 
  { return TRUE; }

// @cmember Permette di eseguire qualcosa prima dell'inizio della stampa
	virtual bool open_print() { return true ;}         

	// @cmember Permette di eseguire qualcosa prima della richiesta di un processo di stampa
  //                              (es. per inizializzare i contatori).
  //          <nl> Ritornando FALSE cencella la richeista di stampa o i sottoalberi
  virtual bool preprocess_print(int file, int counter) 
  { return TRUE; }

  // @cmember Ritornando <e print_action.REPEAT_PAGE> ristampa l'intera pagina (dopo che sono
  //          stati stampanti tutti i figli); <p counter> e' la pagina corrente o il numero di
  //          stampe effettuate.
  virtual print_action postprocess_page(int file, int counter)
  { return NEXT_PAGE; }

  // @cmember Utilizzata per modificare righe, calcolare totali, ecc. Per maggiori dettagli
  //          vedere punto 5)
  virtual print_action postprocess_print(int file, int counter)
  { return NEXT_PAGE; }

// @cmember Permette di eseguire qualcosa alla fine della stampa
	virtual void close_print() { }         

  // @cmember Viene eseguita dopo che tutti i lavori di stampa sono stati completati
  virtual void postclose_print() 
  {}
  // @cmember Viene eseguita dopo la stampa fisica di una "page"
  virtual void on_page_printed(int file)
  {}
  // @cmember Chiamata quando viene premuto il bottone Collega con la selezione attiva nella 
  //          finestra di anteprima
  virtual bool process_link(int id, const char* text) 
  { return false; }
  // @cmember Chiamata quando l'utente annulla la stampa. Ritornando TRUE viene immediata fermata 
  //          la stampa. Non viene chaimata nel caso non si voglia interrompere la stampa
  virtual bool cancel_hook() 
  {return true;}
  
  // @cmember Legata al menu' di stampa della <c TApplication>. Viene ridefinita solo in casi 
  //          particolari
  virtual void print();
  
  // @cmember Legata alla voce Selezione del menu' e chiamata dopo <mf TPrint_application::user_create>
  void do_print(int n);

  // @access Public Member
public:

  // @cmember Riporta i valori standard per la riga <p r>-esima
  void reset_row(int r);

  // @cmember Durante la stampa forza la rilettura di <mf TPrint_application::set_page> alla prossima volta
  void reset_print();

  // @cmember Permette di settare una riga di stampa
  void set_row(int r, const char* fmt, ...);

  // @cmember Setta riga di stampa usando una printrow gia' fatta
  void set_row(int r, TPrintrow& pr);

  // @cmember Setta i valori di traduzione per campi
  void set_translation(int lognum, const char* field, const char* from, const char* to);

  // @cmember Setta un segnalibro nell'anteprima di stampa
  int set_bookmark(const char* txt, int father = -1);

  // @cmember Converte un real nella stringa generata da un currency
  void real2currency(TString& s, const real& r, const char* p = NULL) const;

  // @cmember Permette di trovare un link ipertestuale
  int find_link(const char* descr) const;
  // @cmember Permette di abilitare determinati colori come indicatori di legame ipertestuale
  int enable_link (const char* descr, char fg, char bg = 'w');
  // @cmember Permette di disabilitare i link ipertestuali
  void disable_link(char fg, char bg = 'w');  
  // @cmember Elimina tutti i legami ipertestuali
  void disable_links() 
  { printer().links().destroy(); }   

  // @cmember Abilita/disabilita pi� link per la <mf TPrint_application::enable_link>
  void set_multiple_link(bool on);

  // @cmember Permette di stampare sullo sfondo e per variarne gli attributi
  void set_background(const char* bgdesc = NULL);

  // @cmember Setta/seleziona l'<p i>-esimo cursore. Inutile sec'e' un solo cursore
  void select_cursor(int i);
  // @cmember Ritorna l'<p i>-esimo cursore senza renderlo corrente
  TCursor* get_cursor(int i);

  // @cmember Ritorna il numero massimo di righe definite
  int get_maxrow()
  { return _maxrow; }

  // @cmember Aggiunge un cursore alla classe
  int add_cursor(TCursor* c);

  // @cmember Ritorna il cursore corrente
  TCursor* current_cursor()
  { return _cur; }

  // @cmember Permette di stampare (<p b>=TRUE) o non stampare (<p b>=FALSE) dopo ogni pagina
  //          logica (relativa ad un record) un form feed, anche se il cursore e' nullo.
  void set_auto_ff( bool b = TRUE) 
  { _auto_ff = b; }

  // @cmember Permette di definire il carattere di riempimento.
  //          <nl>Il carattere specificato con set_fillchar (default ' ') viene
  //          usato per riempire a destra e a sinistra i campi in cui si e' specificata
  //          una dimensione maggiore della lunghezza effettiva del contenuto,
  //          (a meno che non si sia usato un codice di formato maiuscolo)  
  void set_fillchar(char c) 
  { _fillchar = c; }

  // @cmember Riempie di righe vuote la pagina corrente fino alla dimensione della pagina
  void fill_page(int from = -1);
  
  // @cmember Aggiunge un menu nella barra dei menu. Di solito basta e avanza quella di default
  virtual bool menu(MENU_TAG m);
  
  // @cmember Ritorna l'identificatore della classe
  virtual word class_id() const 
  { return CLASS_PRINT_APPLICATION; }

  // @cmember Permette di abilitare il menu' di stampa. In genere e' abilitato quando
  //          <mf TPrint_application::set_print> ritorna TRUE
  void enable_print_menu();
  // @cmember Permette di disabilitare il menu' di stampa.
  void disable_print_menu();
  // @cmember Permette di abilitare il menu' di settaggio della stampante.
  void enable_setprint_menu(); 
  // @cmember Permette di disabilitare il menu' di settaggio della stampante.
  void disable_setprint_menu(); 
  
  // @cmember Permette di ridefinire l'header al verificarsi di condizioni durante la stampa
  virtual void preprocess_header() 
  {}
  // @cmember Permette di ridefinire il footer al verificarsi di condizioni durante la stampa
  virtual void preprocess_footer() 
  {}

  // @cmember Permette di definire l'header della stampa
  void set_header(int row, const char* fmt, ...);
  // @cmember Permette di definire il footer della stampa
  void set_footer(int row, const char* fmt, ...);
  // @cmember Elimina l'header della stampa
  void reset_header();
  // @cmember Elimina il footer della stampa
  void reset_footer();
  
  // @cmember Azzera l'albero di stampa con i file presenti
  void reset_files();
  // @cmember Aggiunge un file del cursore nell'albero di stampa
  void add_file(int file, int from = 0);
  // @cmember Aggiunge un file del cursore nell'albero di stampa
  void add_file(const char* tab, int from = 0);

  // @cmember Setta la picture default per i reali
  void set_real_picture(const char* p)
  { _picture = p; }

  // @cmember Ritorna la picture default per i reali
  const TString& get_real_picture() const
  { return _picture; }

  // @cmember Setta la valuta con cui stampare i Currency
  void set_curr_codval(const char* cv)
  { _curr_codval = cv; }

  // @cmember Ritorna la valuta con cui stampare i Currency
  const TString& get_curr_codval() const
  { return _curr_codval; }

  // @cmember Setta il flag di TCurrency automatici
  void set_magic_currency(bool mc)
  { _magic_currency = mc; }

  // @cmember Permette di stampare (<p b>=TRUE) o di non stampare (<p b>=FALSE) il valore 0
  //          nel caso di campo vuoto.
  void set_print_zero(bool b = TRUE)
  { _print_zero = b; }
  
  // @cmember Abilita (<p m>=TRUE) o disabilita (<p m>=FALSE) la barra di attesa (default abilitata)
  void set_wait_bar(bool m) 
  { _wbar = m;    }
  // @cmember Abilita (<p m>=TRUE) o disabilita (<p m>=FALSE) il bottone Annulla nella barra
  //          di attesa (default abilitato)
  void set_wait_cancel(bool m)
  { _wcancel = m; }
  // @cmember Setta il numero minimo di elementi per mostrare la barra di attesa (default 2)
  void set_wait_threshold(int m)
  { _wthr = m;    }

  // @cmember Permette di forzare (<p b>=TRUE) o non forzare (<p b>=FALSE) la progind anche per
  //          le stampe a video
  void force_progind(bool b = TRUE)
  { _force_progind = b; }
  
  // @cmember Permette di forzare (<p b>=TRUE) o non forzare (<p b>=FALSE) la rilettura delle 
  //          <mf TPrint_application::set_row> in <mf TPrint_application::set_page> ad ogni
  //          record stampato, in modo che i dati siano sempre quelli del record corrente
  //          anche se si usano codici %. Chiaramente la stampa viene un po' rallentata
  void force_setpage(bool b = TRUE)
  { _force_setpage = b; }
  
  // @cmember Ritorna il numero della pagina attualmente in stampa
  word get_page_number()       
  { return printer().getcurrentpage(); }
  // @cmember Setta il numero della pagina attualmente in stampa
  void set_page_number(word n) 
  { printer().setcurrentpage(n); }                                 
  
  // @cmember Dirige la stampa sul file specificato con <p name>, preservando gli attributi 
  //          di formato. Se <p header> == TRUE si stampano su file anche gli header.
  void set_export_file(const char* name, bool header = TRUE) 
  { printer().set_export_file(name,header); }
  // @cmember Inserisce un file di export fatto da un'altra printer (con formati e tutto).
  void merge_export_file(const char* file, bool header = TRUE, bool direct = FALSE);

  // @cmember Setta il numero di copie da stampare
  void set_n_copies(int n)  
  { _ncopies = n; }
  // @cmember Ritorna il numero di copie da stampare
  int get_n_copies() const
  { return _ncopies; }
  // @cmember Setta la ripetizione della stampa
  void repeat_print()
  { _repeat_print = TRUE; }
  
  bool need_to_repeat_print()
  { return _repeat_print; }
  
  // @cmember Ritorna se la stampa e' stata interrotta
  bool is_cancelled() const
  { return _cancelled; }
  
  // @cmember Costruttore
  TPrint_application();
  // @cmember Distruttore
  virtual ~TPrint_application();
};

#endif