#include <applicat.h>
#include <config.h>
#include <form.h>
#include <printer.h>
#include <tabutil.h>
#include <urldefid.h>                    

#include "sc2.h"
#include "sc2402.h"
#include "sc2102.h"
#include "sc2400a.h"

#include <clifo.h>


  
///////////////////////////////////////////////////////////
// Stampa solleciti
///////////////////////////////////////////////////////////

class TStampaSol_application: public TApplication {                   
  TSol_mask *_msk;
  TSol_form *_form;
  TString _lingua_ditta;
  bool _gesval;
  TFile_array _file;
                                            
protected:
  virtual bool create();
  virtual bool destroy();  
  virtual bool menu(MENU_TAG m);
  virtual void on_firm_change();

public:
  TSol_mask &mask() { return *_msk; }
  TSol_form &form() { return *_form; }
  TCursor_sheet &sheet() { return _msk->cur_sheet(); }
  
  bool print_selected(); // cicla la stampa sugli elementi selezionati
  int print_sol(); // stampa l'elemento corrente

  TStampaSol_application();
  virtual ~TStampaSol_application() {}
};

bool TStampaSol_application::print_selected()
{            
  TCursor_sheet &s = sheet();         
  TCursor &c = *s.cursor();

  const char who = mask().get_who(); 
  const int key = mask().get_key();
  
  // filtra il cursore del form in mode che diventi uguale al cursor_sheet corrente   
  // Qui sarebbe bello copiarsi l'indice dell'altro cursore
  TCursor &fc = *form().cursor();
  fc.setkey(key);
  TRectype filter(LF_CLIFO);
  filter.put(CLI_TIPOCF, who);
  fc.setregion(filter, filter);
  
  const long print_all = !s.one_checked(); // se non ho selezionato nulla allora li stampo tutti
  long analfabeti = 0; // persone non stampate in quanto aventi lingua errata
  
  printer().open();
                                             
  const long items = c.items();
  for (long i=0; i < items; i++)
  {
    if (print_all || s.checked(i))
    {                                    
      fc= i; // muove il cursore alla posizione corrente
    
      const int ret = print_sol(); 
      if (ret < 0)
        analfabeti++;
    }
    
    if (printer().frozen())
      break;
  }
  printer().close();
  
  if (analfabeti > 0) {
    warning_box("%ld clienti non sono stati stampati in quanto "
                "il codice lingua non corrispondeva al profilo di stampa", analfabeti);
  }
  
  return TRUE;  
}

int TStampaSol_application::print_sol()
{
  TSol_form &f= form();

  // preparazione variabili per controllo lingua
  const TRectype &clf= f.cursor()->file().curr();
  const TString lincf(clf.get(CLI_CODLIN));
  bool ok= TRUE;

  // controllo lingua ditta corrente
  if ((f.lingua() == _lingua_ditta && !lincf.empty()) || f.lingua() != _lingua_ditta) ok= (lincf == f.lingua());
  if (!ok) return -1; // cliente analfabeta
  
  f.azzera_totali();
  // filtra solo le partite del cliente selezionato
  TLocalisamfile& partite = _file[LF_PARTITE];
  partite.zero();
  partite.put(PART_TIPOCF, clf.get(CLI_TIPOCF));
  partite.put(PART_SOTTOCONTO, clf.get(CLI_CODCF));
  const TRectype filter(partite.curr());
  
  bool one_printed = FALSE; // booleano di controllo di riuscita della stampa
  const bool sel_tot_saldo = f.get_sel_tot_saldo(); // selezione sul saldo totale cliente
  const real sel_importo(f.get_sel_importo());   // importo di selezione
  const TDate data_limite_soll(f.data_limite_operazione());
  const TDate data_limite_scad(f.data_limite_scaduto());
  
  if (sel_tot_saldo)
  {                   
    real saldo;
    
    for (int err = partite.read(_isgteq); 
       err == NOERR && partite.curr() == filter; 
       err = partite.read(_isgreat))
    {                                
      TPartita game(partite.curr());
      saldo += game.calcola_scaduto_al(FALSE, data_limite_scad);
      partite.put(PART_NRIGA, 9999);
    }
    if (saldo < sel_importo) 
      return 0;
    partite.curr() = filter;
  }
  for (int err = partite.read(_isgteq); 
       err == NOERR && partite.curr() == filter; 
       err = partite.read(_isgreat))
  {                                
    TPartita game(partite.curr()); 
    real saldo(game.calcola_scaduto_al(FALSE, data_limite_scad));
    
    TImporto unreferenced; //Totale non assegnati per questa partita.
    {
      // Tutto questo ha senso se e solo se la partita e' espressa in un'unica valuta.
      /* Questo e' il vecchio modo di calcolare i non assegnati.
      TString valuta;
      TRecord_array& unassigned = game.unassigned();
      for (int r = unassigned.last_row(); r > 0; r = unassigned.pred_row(r))
      {     
        const TRectype& rec = unassigned.row(r);
        const TRiga_partite& sum = game.riga(rec.get_int(PAGSCA_NRIGP));
        const char * field = (sum.in_valuta() && f.in_valuta() ? PAGSCA_IMPORTOVAL : PAGSCA_IMPORTO);
        if (valuta.empty()) valuta = sum.get(PART_CODVAL);
        if (sum.get_date(PART_DATAPAG)<=data_limite_soll)
        {
          TImporto r(sum.sezione(),rec.get_real(field));
          unreferenced += r;
        }
      }
      */
      // E' piu' giusto calcolare il saldo, comprendente i non assegnati.
      // se il saldo della partita chiude in avere va sommato ad unreferenced
      const TRiga_partite& sum = game.riga(game.first());
      TString valuta(sum.get(PART_CODVAL));
      unreferenced = game.calcola_saldo_al(game.in_valuta() && f.in_valuta(),data_limite_soll, data_limite_scad, data_limite_scad);
      if (unreferenced.valore() > ZERO && unreferenced.sezione() == 'A')
      {
        unreferenced.normalize('A'); //per i non assegnati/anticipi c'e' solo la colonna AVERE
        form().totali().add(unreferenced,valuta);
      }
    }
    
    if (sel_tot_saldo || (saldo > ZERO && saldo >= sel_importo ))
    {                         
      const bool printed = form().print_game(game);
      if (printed) 
        one_printed = TRUE;
    }
    
    partite.put(PART_NRIGA, 9999);
    
    if (printer().frozen())
      break;
  }
  
  if (one_printed)
  {
    f.ultima_pagina();
    printer().formfeed(); 
    if (printer().isfax())
    {
      const char* tipo = clf.get_char(CLI_TIPOCF) ? "Clienti" : "Fornitori";
      const char* codice = clf.get(CLI_CODCF);
      printer().send_fax(tipo, codice);
    }  
  }
  
  return one_printed ? 1 : 0;
} 

bool TStampaSol_application::create()
{                           
  TApplication::create();
  
  _file.open(LF_TABCOM, LF_TAB, LF_CAUSALI, LF_MOV, LF_RMOV, 0);
  _file.open(LF_NDITTE, LF_ANAG, LF_COMUNI, LF_RFORM, 0);
  _file.open(LF_CLIFO, LF_PARTITE, LF_SCADENZE, LF_PAGSCA ,0);
  
  _msk= new TSol_mask("sc2400a");
  
  dispatch_e_menu(MENU_ITEM(1));
  return TRUE;
}

bool TStampaSol_application::destroy()
{               
  delete _msk;
  _file.close();
  return TApplication::destroy();
}

void TStampaSol_application::on_firm_change()
{
  mask().reset();        
  TApplication::on_firm_change();
  TConfig c(CONFIG_DITTA, "cg");
  _lingua_ditta= c.get("CodLin");
  _gesval= c.get_bool("GesVal");
}  

bool TStampaSol_application::menu(MENU_TAG)

{
  TSol_mask &m= mask();
  while (m.run() != K_QUIT)
  {          
    const TDate dlimsol(m.get(F_DATALIMSOL));
    const TDate dsped(m.get(F_DATASEND));                         
    if (dlimsol > dsped)
      error_box("La data limite sollecito deve essere specificata e non puo' essere superiore alla data di invio");
    else
    {
      _form= new TSol_form(m, _gesval, F_DATALIMOP, F_DATALIMSOL);
      print_selected();
      delete _form;
      _form= NULL;
    }
  }
  return FALSE;
}                

TStampaSol_application::TStampaSol_application(): _lingua_ditta(1), _msk(NULL), _form(NULL) {}



int sc2400(int argc, char** argv) {
  TStampaSol_application app;
  
  app.run(argc, argv, "Stampa solleciti");
  return 0;
}