#include <applicat.h>
#include <defmask.h>
#include <dongle.h>
#include <modaut.h>
#include <progind.h>
#include <recset.h>
#include <reprint.h>
#include <textset.h>

#include "pd6342.h"
#include "pd6342100a.h"

#include "../ca/movana.h"
#include "../ca/rmovana.h"
#include "../ca/calib01.h"
#include "../ca/calib02.h"

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

TPrint_cosric_month_mask::TPrint_cosric_month_mask() : TAutomask("pd6342100a")
{
	int nfields = ca_create_fields(*this, 0, LF_COMMESSE, 2, 4, F_CMS, F_CMS + 100, 0x0, "#CMS");
	for (int i = 0; i < nfields; i++)
	{
		TMask_field& dacms = field(F_CMS + i);
		dacms.set_group(1);
    dacms.check_type(CHECK_NORMAL);
	}
  //conti
  ca_create_fields(*this, 0, LF_PCONANA, 2, 7, F_DACONTO, F_DACONTO + 100, 0x0, "#DACONTO");
	nfields = ca_create_fields(*this, 0, LF_PCONANA, 2, 11, F_ACONTO, F_ACONTO + 100, 0x0, "#ACONTO");
	for (int i = 0; i < nfields; i++)
	{
		TMask_field& daconto = field(F_DACONTO + i);
		daconto.set_group(1);
    daconto.check_type(CHECK_NORMAL);
		TMask_field& aconto = field(F_ACONTO + i);
		aconto.set_group(2);
    aconto.check_type(CHECK_NORMAL);
	}
}

bool TPrint_cosric_month_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch(o.dlg())
  {
  case DLG_PRINT:
    if (e == fe_button)
    {
      main_app().print();
      return false;
    }
    break;
  case DLG_PREVIEW:
    if (e == fe_button)
    {
      main_app().preview();
      return false;
    }
    break;
  default:
    break;
  }
  return true;
}


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

////////////////////////////////////////////////////////
//  RECORDSET
////////////////////////////////////////////////////////
class TPrint_cosric_month_recordset : public TAS400_recordset
{
public:
  bool crea_nuova_riga(const TString& codcms, const TString& codfase, const TString& codconto, TArray& importi);
  TPrint_cosric_month_recordset();
};


TPrint_cosric_month_recordset::TPrint_cosric_month_recordset() 
                              : TAS400_recordset("AS400(300)")
{
  create_field(RMOVANA_CODCMS,   -1, 20, _alfafld, true);
  create_field(RMOVANA_CODFASE,  -1, 10, _alfafld);
  create_field(RMOVANA_CODCONTO, -1, 20, _alfafld, true);
  TString16 month_string;
  for (int i = 1; i <= 13; i++)
  {
    month_string.format("IMPORTO_%02d", i);
    create_field(month_string,  -1, 18, _realfld);
    month_string.format("SEZIONE_%02d", i);
    create_field(month_string,  -1, 1, _alfafld);
  }
}

bool TPrint_cosric_month_recordset::crea_nuova_riga(const TString& codcms, const TString& codfase, 
                                                   const TString& codconto, TArray& importi)
{
  new_rec("");
  set(RMOVANA_CODCMS, codcms);
  set(RMOVANA_CODFASE, codfase);
  set(RMOVANA_CODCONTO, codconto);
  TString16 month_string;
  for (int i = 1; i <= 13; i++)
  {
    const TImporto& importo = (const TImporto&)importi[i - 1];
    if (!importo.is_zero())
    {
      month_string.format("IMPORTO_%02d", i);
      real imp = importo.valore(); 
      imp.round(2);
      set(month_string, imp);
      month_string.format("SEZIONE_%02d", i);
      TString4 sez;
      sez << importo.sezione();
      set(month_string, sez);
    }
  }
  return true;
}


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

class TPrint_cosric_month : public TSkeleton_application
{
  TPrint_cosric_month_mask* _mask;
  bool _has_ca;

protected:
  virtual bool check_autorization() const {return false;}
  virtual const char * extra_modules() const {return "ca";}

	virtual bool create();
  virtual void print();
  virtual void preview();
  virtual void print_or_preview(const bool stampa);

  TPrint_cosric_month_recordset* elabora() const;

public:
  virtual void main_loop();

};


TPrint_cosric_month_recordset* TPrint_cosric_month::elabora() const
{
  //creazione dell'as400 recordset che verra' riempito dai record del recordset righe
  TPrint_cosric_month_recordset* printset = new TPrint_cosric_month_recordset();

  //creazione della query per la creazione del recordset
  TString query;
  query << "USE RMOVANA KEY 4\n";
  query << "SELECT (ANNOES=#ANNOES)&&(BETWEEN(CODCONTO,#DACONTO,#ACONTO))\n";
  query << "JOIN MOVANA INTO NUMREG==NUMREG\n";
  query << "FROM CODCMS=#CMS\n";
  query << "TO CODCMS=#CMS";

  TISAM_recordset recset(query);

  recset.set_var("#CMS", TVariant(_mask->get(F_CMS)));
  recset.set_var("#ANNOES", TVariant(_mask->get(F_ANNO)));
  TString80 dacontone, acontone;
  //c'e' un range di conti da considerare?
  const short dlg_da = F_DACONTO;
  const short dlg_al = F_ACONTO;
	for (int i = 0; _mask->id2pos(dlg_da + i) > 0; i++)
	{
		dacontone << _mask->get(dlg_da + i);
		acontone << _mask->get(dlg_al + i);
	}
  acontone << "~";  //magia! infatti la between col cavolo che funzionava se acontone non era completo
  recset.set_var("#DACONTO", TVariant(dacontone));
  recset.set_var("#ACONTO", TVariant(acontone));

  const long recset_items = recset.items();
  if (recset_items > 0)
  {
    TAssoc_array commesse_fasi; //assoc_array con chiave cms-fase-conto e un simpatico array dei 12 importi dei mesi per quella chiave
    TToken_string key;    //chiave assoc_array

    TProgind pi(recset_items, TR("Elaborazione dati per la stampa..."), true, true);

    //Scansione delle righe analitiche filtrate...
    const TRectype& rmovana = recset.cursor()->curr();
    const TRectype& movana = recset.cursor()->curr(LF_MOVANA);
    for (bool ok = recset.move_first(); ok; ok = recset.move_next())
	  {
      if (!pi.addstatus(1))
        break;
      //questo per adesso non serve, ma non si sa mai che chiedano la spaccatura tra costi e ricavi...
      const TAnal_bill uncle(rmovana);
      const TIndbil indbil = uncle.indicatore_bilancio();

      key = rmovana.get(RMOVANA_CODCMS);
      key.add(rmovana.get(RMOVANA_CODFASE));
      key.add(rmovana.get(RMOVANA_CODCONTO));

      //importo
      const real valore = rmovana.get_real(RMOVANA_IMPORTO);
      const char sezione = rmovana.get_char(RMOVANA_SEZIONE);

      //durata del movana che contiene la riga in oggetto
      const TDate datacomp = movana.get_date(MOVANA_DATACOMP);
      TDate datafcomp = movana.get_date(MOVANA_DATAFCOMP);
      if (!datafcomp.ok())
        datafcomp = datacomp;
      const long durata_totale = datafcomp - datacomp + 1;

      //giro sulle durate per il riproporzionamento
      int first_month = datacomp.month();
      int last_month = datafcomp.month();
      if (datafcomp.year() > datacomp.year())
        last_month = 12;
    
      const int year = _mask->get_int(F_ANNO);
      for (int m = first_month; m <= last_month; m++)
      {
        TDate data_ini(1, m, year);
        TDate data_fin(1, m, year); data_fin.set_end_month();
        if (data_ini < datacomp)
          data_ini = datacomp;
        if (data_fin > datafcomp)
          data_fin = datafcomp;
        const int durata_month = data_fin - data_ini + 1;
        real valore_mese = valore * durata_month / durata_totale;
        const TImporto importo_mese(sezione, valore_mese);

        //cerca se l'importo in questione va aggiunto ad un elemento gi� esistente dell'assoc_array o se..
        //..l'elemento con questa chiave non esiste e quindi deve aggiungerlo
        TArray* cms_fas = (TArray*)commesse_fasi.objptr(key);
        if (cms_fas == NULL)
        {
          cms_fas = new TArray(13);
          const TImporto importo_nullo;
          for (int j = 0; j < 13; j++)
            cms_fas->add(importo_nullo);

          commesse_fasi.add(key, cms_fas);
        }
        TImporto& imp_cms_fas = (TImporto&)(*cms_fas)[m - 1];
        imp_cms_fas += importo_mese;

        TImporto& imp_anno = (TImporto&)(*cms_fas)[12];
        imp_anno += importo_mese;

      } //for(int m = first_month...

    } //for(bool.recset...

    
    FOR_EACH_ASSOC_OBJECT(commesse_fasi, obj, chiave, arr)
    {
      key = chiave;
      const TString& codcms = key.get(0);
      const TString& codfase = key.get(1);
      const TString& codconto = key.get(2);

      TArray& importi = *(TArray*)arr;
      printset->crea_nuova_riga(codcms, codfase, codconto, importi);
    }
    printset->sort();
  }

  return printset;
}


void TPrint_cosric_month::print_or_preview(const bool stampa)
{
  if (_mask->check_fields())
  {
    TPrint_cosric_month_report rep;
	  rep.load("pd6342100a.rep");

    TPrint_cosric_month_recordset* printset = elabora();
    rep.set_recordset(printset);

    //setta i valori della maschera sul report (dopo la set_recordset, senn�..
    //..sarebbero sovrascritti dalla set_recordset)
    rep.mask2report(*_mask);

    TReport_book book;
	  book.add(rep);

    if (stampa)
	    book.print();
    else
      book.preview();
  }
}

void TPrint_cosric_month::print()
{
  print_or_preview(true);
}

void TPrint_cosric_month::preview()
{
  print_or_preview(false);
}

void TPrint_cosric_month::main_loop()
{
  _mask = new TPrint_cosric_month_mask;
  _mask->run();
  delete _mask;
  _mask = NULL;
}

bool TPrint_cosric_month::create()
{
  //controlla se la chiave ha il modulo CA (e non solo CM) NON � ammesso CA E CM
  _has_ca = dongle().active(CAAUT);
  //in tal caso il programma � utilizzabile solo se si ha il piano dei conti contabile..
  if (_has_ca)
  {
    //le commesse devono essere state configurate
    const TMultilevel_code_info& mci = ca_multilevel_code_info(LF_COMMESSE);
    if (mci.levels() != 1)
      return error_box(TR("Il programma funziona solo con le commesse configurate come primo livello di CA"));
  }

  return TSkeleton_application::create();
}

int pd6342100(int argc, char* argv[])
{
  TPrint_cosric_month stat_anal;
  stat_anal.run(argc, argv, TR("Stampa costi per mese"));
  return 0;
}