#include "tp0900a.h"

#include <applicat.h>
#include <automask.h>
#include <modaut.h>
#include <progind.h>
#include <recarray.h>
#include <relation.h>
#include <reprint.h>
#include <reputils.h>
#include <textset.h>

#include <clifo.h>
#include <doc.h>
#include <rdoc.h>

#include "../ve/velib.h"

///////////////////////////////////////////////////////////
//  MASCHERA
///////////////////////////////////////////////////////////
class TDichiarazione_CONAI_mask : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); 
	
public:
  TDichiarazione_CONAI_mask();
  virtual ~TDichiarazione_CONAI_mask() {}
};

TDichiarazione_CONAI_mask::TDichiarazione_CONAI_mask() : TAutomask("tp0900a")
{
}

bool TDichiarazione_CONAI_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())
  {
  case F_PERIODO:
    break;
  default:
    break;
  }

  return true;
}

/////////////////////////////////////////////////////////////
//  REPORT
/////////////////////////////////////////////////////////////
class TDichiarazione_CONAI_report : public TReport
{
protected:
virtual bool use_mask() { return false; }
public:
  TDichiarazione_CONAI_report() {}
};

/////////////////////////////////////////////////////////////
//	CSV RECORDSET
/////////////////////////////////////////////////////////////

class TDichiarazione_CONAI_csv_recordset : public TCSV_recordset
{
protected:
  //virtual const TVariant& get(const char* field_name) const;
public:
	TDichiarazione_CONAI_csv_recordset();
};


/*const TDichiarazione_CONAI_csv_recordset::get(const char* field_name) const
{
	if (*field_name == '#')
	{
		if (strcmp(field_name, "#RAGSOC") == 0)
		{
			TVariant& var = get_tmp_var();
			var = mask.;
		}
    return var;
  }
  return NULL_VARIANT;
}*/


TDichiarazione_CONAI_csv_recordset::TDichiarazione_CONAI_csv_recordset() 
: TCSV_recordset("CSV(,)\n")
{
}


///////////////////////////////////////////////////////////
// APPLICAZIONE
///////////////////////////////////////////////////////////

class TDichiarazione_CONAI : public TSkeleton_application
{

protected:
  void elabora(const TMask& mask) const;
  void scrivi_csv(const TRectype& prima_riga, TDichiarazione_CONAI_csv_recordset& csv, 
                  const int conai_specie, const TString& conai_codart) const;
  void scrivi_csv_doc_con_riga_generata(TDocumento& doc, const int n_riga_generata,
                                        TDichiarazione_CONAI_csv_recordset& csv, const int conai_specie) const;
  void scrivi_csv_doc_speciale(TDocumento& doc, TDichiarazione_CONAI_csv_recordset& csv,
                               const int conai_specie, const TString& conai_codart) const;

public:
	virtual bool create();
  virtual void main_loop();

};


//riempie recordset con le righe CONAI del documento che contiene una riga generata CONAI
void TDichiarazione_CONAI::scrivi_csv_doc_con_riga_generata(TDocumento& doc, const int n_riga_generata, TDichiarazione_CONAI_csv_recordset& csv, 
                                      const int conai_specie) const
{
  //prende dalla riga i dati che gli servono per fare vari calcoli
  const TRiga_documento& riga_generata = doc[n_riga_generata];
  const TString80 conai_codart = riga_generata.get(RDOC_CODART); //questo ci serve per trovare le righe conai
  const real totale_qta_assogg = riga_generata.get_real(RDOC_QTA);  //questo ci serve per le quantita' assoggetate o no

  TGeneric_distrib agip(totale_qta_assogg, 5);    //distrib per ridistribuire le % dei quantitativi assoggetati
  TArray qta_AB_conai;    //array con le quantita' conai totali (A+B)

  //scopre se il doc e' una NAC
  const bool is_nac = doc.is_nota_credito();

  //prende la data del documento
  const TDate& datadoc = doc.data();

  //prende il cliente ed i suoi dati
  TCli_for clifo = doc.clifor();
  const long clifo_cod = clifo.codice();
  TString16 clifo_cofi = clifo.get(CLI_COFI);
  if (clifo_cofi.empty())
    clifo_cofi = clifo.get(CLI_PAIV);

  const int nrighe = doc.rows();

  //ciclo di creazione del distrib con le quote conai
  for (int j = 1; j <= nrighe; j++)
  {
    const TRiga_documento& rdoc = doc[j];

    //servono SOLO le righe CONAI!!!!!
    const TString& codagg1 = rdoc.get(RDOC_CODAGG1);

    if (codagg1 == conai_codart)
    {
      //quantita' totale conai (A + B) sul report
      const real n = rdoc.calc_conai_qta(conai_specie);
      qta_AB_conai.add(n, j); //va calcolato con il metodo apposito

      //quantita' assoggettata (B) sul report
	    agip.add(n);
    }
  }

  //ciclo di riempimento delle righe csv;scandisce solo l'array con i valori compilati
  FOR_EACH_ARRAY_ROW(qta_AB_conai, i, obj)
  {
    const TRiga_documento& rdoc = doc[i];

    //servono SOLO le righe CONAI!!!!!
    const TString& codagg1 = rdoc.get(RDOC_CODAGG1);

    if (codagg1 == conai_codart)
    {
      //se non e' stata definita la sottocategoria conai (maiali!!) va messa uguale a quella generica
      TString4 codagg2 = rdoc.get(RDOC_CODAGG2);
      if (codagg2.empty())
        codagg2 = codagg1;
      //puo' capitare che la sottocategoria sia stata troncata alla categoria
      if (codagg2 == codagg1)
        codagg2 << "99";

      //creazione di un nuovo record da esportare
      csv.new_rec("");

      //riempie i campi del record del csv
      //codnum-anno-ndoc-datadoc-codcli-cofi-nriga-codagg1-codagg2-prezzo-um-conai(AB)-conai(B)-conai(A)
      //parte chiave della riga
      csv.set(0, TVariant(rdoc.get(RDOC_CODNUM)));
      csv.set(1, TVariant(rdoc.get(RDOC_ANNO)));
      csv.set(2, TVariant(rdoc.get(RDOC_NDOC)));
      csv.set(3, TVariant(datadoc));
      csv.set(4, TVariant(clifo_cod));
      csv.set(5, TVariant(clifo_cofi));
      csv.set(6, TVariant(rdoc.get(RDOC_CODART)));
      csv.set(7, TVariant(rdoc.get(RDOC_NRIGA)));

      //codici conai
      csv.set(8, TVariant(codagg1));   //codice materiale conai (es. carta, legno...)
      csv.set(9, TVariant(codagg2));   //sottocodice materiale (es. carta imballo, busta...)

      //prezzo
      const real prezzo = riga_generata.get_real(RDOC_PREZZO);  //va preso dalla riga generata
      csv.set(10, TVariant(prezzo));

      //um conai
      const TString4 umqta = cache().get("SPP", conai_codart, "S7"); //unita' di misura dalla tabella SPP
      csv.set(11, TVariant(umqta));     

      //quantita' totale conai (A + B) sul report (le NAC hanno segno rovesciato)
      real qta_tot_conai = (real&)qta_AB_conai[i];
      if (is_nac)
        qta_tot_conai = -qta_tot_conai;
      csv.set(15, TVariant(qta_tot_conai));

      //percentuale di esenzione conai al 100%?
      const real perc = rdoc.get_real(RDOC_QTAGG2);

      //quantita' assoggettata (B) sul report (le NAC hanno segno rovesciato)
      real qta_assoggettata_conai = agip.get();

      if (perc == CENTO)
        qta_assoggettata_conai = ZERO;

      if (is_nac)
        qta_assoggettata_conai = -qta_assoggettata_conai;
      csv.set(13, TVariant(qta_assoggettata_conai));

      //quantita' esente conai (A) sul report
      const real qta_esente_conai = qta_tot_conai - qta_assoggettata_conai;
      csv.set(12, TVariant(qta_esente_conai));

      //valore totale contributo (BxC) sul report
      const TCurrency totale_contrib_conai = qta_assoggettata_conai * prezzo;
      csv.set(14, TVariant(totale_contrib_conai.get_num()));
    }
  }
}

//riempie recordset con le righe CONAI del documento che NON ha una riga generata CONAI;trattasi di documenti..
//..farlocchi costruiti ad arte per correggere le vaccate dei rompiscatolifici
void TDichiarazione_CONAI::scrivi_csv_doc_speciale(TDocumento& doc, TDichiarazione_CONAI_csv_recordset& csv,
                                                   const int conai_specie, const TString& conai_codart) const
{
  //scopre se il doc e' una NAC
  const bool is_nac = doc.is_nota_credito();

  //prende la data del documento
  const TDate& datadoc = doc.data();

  //prende il cliente ed i suoi dati
  TCli_for clifo = doc.clifor();
  const long clifo_cod = clifo.codice();
  TString16 clifo_cofi = clifo.get(CLI_COFI);
  if (clifo_cofi.empty())
    clifo_cofi = clifo.get(CLI_PAIV);

  const int nrighe = doc.rows();

  //ciclo di riempimento delle righe csv;scandisce solo l'array con i valori compilati
  for (int i = 1; i <= nrighe; i++)
  {
    const TRiga_documento& rdoc = doc[i];

    //servono SOLO le righe CONAI!!!!!
    const TString& codagg1 = rdoc.get(RDOC_CODAGG1);
    
    if (codagg1 == conai_codart)
    {
      //se non e' stata definita la sottocategoria conai (maiali!!) va messa uguale a quella generica
      TString4 codagg2 = rdoc.get(RDOC_CODAGG2);
      if (codagg2.empty())
        codagg2 = codagg1;
      //puo' capitare che la sottocategoria sia stata troncata alla categoria
      if (codagg2 == codagg1)
        codagg2 << "99";

      //creazione di un nuovo record da esportare
      csv.new_rec("");

      //riempie i campi del record del csv
      //codnum-anno-ndoc-datadoc-codcli-cofi-nriga-codagg1-codagg2-prezzo-um-conai(AB)-conai(B)-conai(A)
      //parte chiave della riga
      csv.set(0, TVariant(rdoc.get(RDOC_CODNUM)));
      csv.set(1, TVariant(rdoc.get(RDOC_ANNO)));
      csv.set(2, TVariant(rdoc.get(RDOC_NDOC)));
      csv.set(3, TVariant(datadoc));
      csv.set(4, TVariant(clifo_cod));
      csv.set(5, TVariant(clifo_cofi));
      csv.set(6, TVariant(rdoc.get(RDOC_CODART)));
      csv.set(7, TVariant(rdoc.get(RDOC_NRIGA)));

      //codici conai
      csv.set(8, TVariant(codagg1));   //codice materiale conai (es. carta, legno...)
      csv.set(9, TVariant(codagg2));   //sottocodice materiale (es. carta imballo, busta...)

      //prezzo
      const real prezzo = rdoc.get_real(RDOC_PREZZO);  //va preso dalla riga stessa
      csv.set(10, TVariant(prezzo));    

      //um conai
      const TString4 umqta = cache().get("SPP", conai_codart, "S7"); //unita' di misura dalla tabella SPP
      csv.set(11, TVariant(umqta));     

      //quantita' totale conai (A + B) sul report (le NAC hanno segno rovesciato)
      real qta_tot_conai = rdoc.get_real(RDOC_QTA);
      if (is_nac)
        qta_tot_conai = -qta_tot_conai;
      csv.set(15, TVariant(qta_tot_conai));

      //percentuale di esenzione conai al 100%?
      const real perc = rdoc.get_real(RDOC_QTAGG2);

      //quantita' assoggettata (B) sul report (le NAC hanno segno rovesciato)
      real qta_assoggettata_conai = qta_tot_conai;

      if (perc == CENTO)
        qta_assoggettata_conai = ZERO;

      if (is_nac)
        qta_assoggettata_conai = -qta_assoggettata_conai;
      csv.set(13, TVariant(qta_assoggettata_conai));

      //quantita' esente conai (A) sul report
      const real qta_esente_conai = qta_tot_conai - qta_assoggettata_conai; //deve essere sempre ZERO!
      csv.set(12, TVariant(qta_esente_conai));

      //valore totale contributo (BxC) sul report
      const TCurrency totale_contrib_conai = qta_assoggettata_conai * prezzo;
      csv.set(14, TVariant(totale_contrib_conai.get_num()));
    }
  }
}


//crea il documento che contiene la riga che gli viene passata,cerca la riga generata ed in base al risultato della ricerca chiama..
//..il metodo adatto
void TDichiarazione_CONAI::scrivi_csv(const TRectype& prima_riga, TDichiarazione_CONAI_csv_recordset& csv, 
                                      const int conai_specie, const TString& conai_codart) const
{
  //crea la testata delle righedoc per poter fare vari calcoli (e intanto il tempo se ne va...)
  const int anno = prima_riga.get_int(RDOC_ANNO);
  const TString4 codnum = prima_riga.get(RDOC_CODNUM);
  const long numdoc = prima_riga.get_long(RDOC_NDOC);

  //documento della prima riga e quindi anche di tutte le altre righe conai
  TDocumento doc('D', anno, codnum, numdoc);

  //cerca la riga generata (in tal caso e' un documento con righe CONAI giuste)
  const int nrighe = doc.rows();

  int n_riga_generata = 0;
  for (int j = 1; j <= nrighe; j++)
  {
    const TRiga_documento& rdoc = doc[j];
    //c'� la riga generata con codart di tipo conai (sia automatica che manuale)?
    if (rdoc.get(RDOC_CODART) == conai_codart && (rdoc.is_spese() || rdoc.is_generata()))
    {
      n_riga_generata = j;
      break;
    }
  }

  if (n_riga_generata > 0)
    scrivi_csv_doc_con_riga_generata(doc, n_riga_generata, csv, conai_specie);
  else
    scrivi_csv_doc_speciale(doc, csv, conai_specie, conai_codart);

}


static int compare_csv_rows_specie(const TObject** o1, const TObject** o2)
{
  TToken_string& s1 = *(TToken_string*)*o1;
  TToken_string& s2 = *(TToken_string*)*o2;

  //deve ordinare sul campo 8 (codagg2 = codice specie conai)
  const TString& c1 = s1.get(8);
  const TString& c2 = s2.get(8);

  int cmp = c1.compare(c2);

  // sotto ordinamento per codice cliente (campo 4)
  if (cmp == 0)
  {
    const TString& c1 = s1.get(4);
    const TString& c2 = s2.get(4);
    cmp = c1.compare(c2);
    
    // sotto-sotto ordinamento per ndoc (campo 2)
    if (cmp == 0)
    {
      const TString& c1 = s1.get(2);
      const TString& c2 = s2.get(2);
      cmp = c1.compare(c2);
    }
  }

  return cmp;
}

static int compare_csv_rows_cofi(const TObject** o1, const TObject** o2)
{
  TToken_string& s1 = *(TToken_string*)*o1;
  TToken_string& s2 = *(TToken_string*)*o2;

  //deve ordinare sul campo cofi/piva
  const TString& c1 = s1.get(5);
  const TString& c2 = s2.get(5);
  int cmp = c1.compare(c2);

  return cmp;
}

//metodo di base per la ricerca delle righe documento che soddisfano i parametri dell'utonto
void TDichiarazione_CONAI::elabora(const TMask& mask) const
{
  //Tanto per cominciare stabilisce il range di date...
  const int anno = mask.get_int(F_ANNO);

  TDate dataini(1, 1, anno);
  TDate datafin(31, 12, anno);

  const int tipo_periodo = mask.get_int(F_PERIODO);
  //se il periodo scelto non e' un anno intero...
  switch (tipo_periodo)
  {
  case 2:
    {
      const int mese = mask.get_int(F_TRIMESTRE);
      dataini.set_month(mese);
      datafin = dataini;
      datafin.addmonth(2);
      datafin.set_end_month();
    }
    break;
  case 3:
    {
    const int mese = mask.get_int(F_MESE);
    dataini.set_month(mese);
    datafin = dataini;
    datafin.set_end_month();
    }
    break;
  default:
    break;
  }
  
  //Adesso tocca al codice articolo in base alla specie CONAI
  const int specie_conai = mask.get_int(F_SPECIECONAI);
  TConfig ditta_ini(CONFIG_DITTA, "ve");

  TVariant codart;
  TString nome_report;    //report di tipo 6.1 scelto in base alla specie conai

  switch (specie_conai)
  {
  case 0:
    codart = ditta_ini.get("CODACC"); //acciaio
    nome_report = "tp0900ac.rep";
    break;
  case 1:
    codart = ditta_ini.get("CODALL"); //alluminio
    nome_report = "tp0900al.rep";
    break;
  case 2:
    codart = ditta_ini.get("CODCAR"); //carta
    nome_report = "tp0900ca.rep";
    break;
  case 3:
    codart = ditta_ini.get("CODPLA"); //plastica
    nome_report = "tp0900pl.rep";
    break;
  case 4:
    codart = ditta_ini.get("CODLEG"); //legno
    nome_report = "tp0900le.rep";
    break;
  case 5:
    codart = ditta_ini.get("CODVET"); //vetro
    nome_report = "tp0900ve.rep";
    break;
  default:
    break;
  }

  //In caso il tipo stampa NON sia  con il modello 6.1 basato sulla specie conai ma di tipo 6.3 basato sui..
  //fornitori e le loro esenzioni, il report va rinominato perche' e' unico
  if (mask.get_int(F_TIPOSTAMPA) == 2)
    nome_report = "tp0900es.rep";

  //Adesso prende le numerazioni e i tipi documento
  TSheet_field& sf = mask.sfield(F_TIPI);

  //la query e' sulle righe documento
  //cerca le righe con numerazione e tipo indicate nello sheet;prende sia le righe che generano CONAI (per avere il codice conai,..
  //..le quantita' etc) e le righe generate da CONAI (per avere i prezzi)
  TString query;
/*  query << "USE RDOC KEY 5\n";
  query << "SELECT (NUM(ANSI(33.DATADOC))>=NUM(ANSI(#DADATA)))&&(NUM(ANSI(33.DATADOC))<=NUM(ANSI(#ADATA)))&&(33.TIPODOC=#TIPODOC)&&(GENERATA=\"X\")\n";
  query << "JOIN DOC INTO PROVV==PROVV ANNO==ANNO CODNUM==CODNUM NDOC==NDOC\n";
  query << "FROM CODART=#CODART ANNO=#ANNO CODNUM=#CODNUM PROVV=\"D\"\n";
  query << "TO CODART=#CODART ANNO=#ANNO CODNUM=#CODNUM PROVV=\"D\"\n";*/

  query << "USE RDOC KEY 1\n";
  query << "SELECT (NUM(ANSI(33.DATADOC))>=NUM(ANSI(#DADATA)))&&(NUM(ANSI(33.DATADOC))<=NUM(ANSI(#ADATA)))&&(33.TIPODOC=#TIPODOC)&&(CODAGG1=#CODART)\n";
  query << "JOIN DOC INTO PROVV==PROVV ANNO==ANNO CODNUM==CODNUM NDOC==NDOC\n";
  query << "FROM CODNUM=#CODNUM ANNO=#ANNO PROVV=\"D\"\n";
  query << "TO CODNUM=#CODNUM ANNO=#ANNO PROVV=\"D\"\n";

  //crea il recordset principale relativo alle righe originali CONAI ed assegna subito i valori delle variabili che restano costanti al cambio..
  //..numerazione/tipo: sono le date ed il codice articolo
  TISAM_recordset rdoc(query);

  rdoc.set_var("#ANNO", TVariant((long)anno));
	rdoc.set_var("#DADATA", dataini);
	rdoc.set_var("#ADATA", datafin);
  rdoc.set_var("#CODART", codart);

  //creazione del csv recordset che verra' riempito dai record del recordset rdoc
  TDichiarazione_CONAI_csv_recordset* csv = new TDichiarazione_CONAI_csv_recordset;

  //quante righe dello sheet processa?
  const long tot_items = sf.items();

  //Visto che e' possibile avere una secchiata di numerazioni, gli tocca fare un giro per ogni numerazione
  FOR_EACH_SHEET_ROW(sf, r, row)
  {
    //estrazione definitiva dei record che soddisfano il casino di parametri richiesti
    rdoc.set_var("#CODNUM", TVariant(row->get(0)));
    rdoc.set_var("#TIPODOC", TVariant(row->get(2)));

    //quanti record validi ha trovato?
    const long items = rdoc.items();
/*#ifdef DBG
    warning_box("Hai trovato %ld righe di %s! Ti sembrano abbastanza?", items, row->get(0));
#endif*/

    //E crea pure la progind..
    TProgind pi(tot_items, TR("Generazione righe..."), true, true);

    long last_ndoc = 0;

    //Scansione del recordset trovato
    for (bool ok = rdoc.move_first(); ok; ok = rdoc.move_next())
	  {
      if (!pi.addstatus(1))
        break;
      
      const long ndoc = rdoc.get(RDOC_NDOC).as_int();
      if (ndoc != last_ndoc)
      {
        scrivi_csv(rdoc.cursor()->curr(), *csv, specie_conai, codart.as_string());
        last_ndoc = ndoc;
      }

    } //for(bool ok = rdoc.move_first(..

  } //FOR_EACH...
  
  //riordinamento del file secondo: 
  //In caso il tipo stampa sia  con il modello 6.3 basato sui..
  //fornitori e le loro esenzioni...
  if (mask.get_int(F_TIPOSTAMPA) == 2)
    csv->sort(compare_csv_rows_cofi);
  else
  //specie conai, codice cliente, numero documento
    csv->sort(compare_csv_rows_specie);

  //se richiesto il file in formato excel...
  if (mask.get_bool(F_EXCEL))
  {
    //crea la riga con le intestazioni dei campi e la mette all'inizio
    csv->insert_rec(0);
    //riempie i campi del primo record del csv in modo da avere l'intestazione
    csv->set(0, "CODNUM");
    csv->set(1, "ANNO");
    csv->set(2, "NDOC");
    csv->set(3, "DATADOC");
    csv->set(4, "CODCLI");
    csv->set(5, "COFICLI");
    csv->set(6, "CODART");
    csv->set(7, "NRIGA");
    csv->set(8, "CLASSE");
    csv->set(9, "SOTTOCL");
    csv->set(10, "PREZZO");
    csv->set(11, "UM");
    csv->set(12, "CONAI A");
    csv->set(13, "CONAI B");
    csv->set(14, "CONAI BxC");
    csv->set(15, "CONAI A+B");

    const TString path = mask.get(F_PATH);
    csv->save_as(path, fmt_text);
    
    //accoppa la riga con le intestazioni dei campi
    csv->destroy(0);

/*#ifdef DBG
	  xvt_sys_goto_url(path, "open");
#endif*/
  }
  
  //creazione del report di stampa
	TDichiarazione_CONAI_report rep;
	bool ok = rep.load(nome_report);
  //setta il recordset...
  //deve settare almeno un campo manualmente perche' funzioni la mask2report
  csv->set_var("#EMAIL", TVariant("Manca la email"), true);
  rep.set_recordset(csv);
  //..e poi carica i valori sulla maschera nel report!!!!
  rep.mask2report(mask);

	if (ok)
	{
		TReport_book book;
		ok = book.add(rep);
		if (ok)
			book.print_or_preview();
  }
}

void TDichiarazione_CONAI::main_loop()
{
  TDichiarazione_CONAI_mask mask;
  mask.field(F_FIRM).check(RUNNING_CHECK);
  while (mask.run() == K_ENTER)
  {
    elabora(mask);
  }
} 

bool TDichiarazione_CONAI::create()
{
  if (!has_module(DCAUT))
    return error_box(TR("Modulo non autorizzato"));

	return TSkeleton_application::create();
}

int tp0900(int argc, char* argv[])
{
  TDichiarazione_CONAI dc;
  dc.run(argc, argv, TR("Dichiarazione CONAI"));
  return 0;
}