#include <applicat.h>
#include <progind.h>

#include "sv2.h"
#include "svlib01.h"
#include "sv2100a.h"

#include "svriep.h"

class TRicalcolo_stats : public TSkeleton_application
{
  TStats_agg _agg;
  static TDate _datamin;

protected:
  void calcola_data_minima();

protected:
  virtual void main_loop();
  virtual bool create();
  virtual void on_config_change();
  
public:
  static bool datein_handler(TMask_field& f, KEY k);
  bool kill_stats(const TDate& dfr, const TDate& dto);
  void calc_stats(const TDate& dfr, const TDate& dto);
};

TDate TRicalcolo_stats::_datamin;

bool TRicalcolo_stats::create()
{ 
  open_files(LF_TABCOM, 0);                       // File comuni
  open_files(LF_TAB, LF_CLIFO, LF_OCCAS, 0);      // File ditta
  open_files(LF_CFVEN, LF_DOC, LF_RIGHEDOC, 0);   // File vendite
  open_files(LF_SVRIEP, 0);                       // File statistiche
            
  return TSkeleton_application::create();
}

void TRicalcolo_stats::on_config_change()
{
  _agg.init();
}

bool TRicalcolo_stats::kill_stats(const TDate& dfr, const TDate& dto)
{ 
  TRelation rel(LF_SVRIEP);
                          
  TRectype recfrom(LF_SVRIEP), recto(LF_SVRIEP);
  
  if (dfr.ok())              
  {
    recfrom.put(SVR_ANNO, dfr.year());
    recfrom.put(SVR_PERIODO, _agg.date2period(dfr));
  }
  if (dto.ok())              
  {
    recto.put(SVR_ANNO, dto.year());
    recto.put(SVR_PERIODO, _agg.date2period(dto));
  }
  
  TCursor cur(&rel, "", 1, &recfrom, &recto);
  const long items = cur.items();
  TProgind pi(items, TR("Azzeramento statistiche"), FALSE, TRUE);
  cur.freeze();
  
  for (cur = 0; cur.pos() < items; ++cur)
  {             
    pi.addstatus(1);
    const int err = rel.remove();
    if (err != NOERR)
    {
      error_box(FR("Errore %d durante l'azzeramento archivi"), err);
      return FALSE;
    }
  }  
  
  return TRUE;  
}

void TRicalcolo_stats::calcola_data_minima()
{
  TWait_cursor hourglass;

  TAssoc_array tipi_doc;

  TRelation rel_tip("%TIP");
  TCursor cur_tip(&rel_tip);
  const TRecnotype items_tip = cur_tip.items();
  cur_tip.freeze();
  for (cur_tip = 0L; cur_tip.pos() < items_tip; ++cur_tip)
  {
    const TRectype& rec_tip = rel_tip.curr();
    if (rec_tip.get_bool("B2")) // E' un tipo per le statistiche
      tipi_doc.add(rec_tip.get("CODTAB"), NULL);
  }

  TRelation rel_doc(LF_DOC);
  TCursor cur_doc(&rel_doc, "", 3);
  const TRectype& rec_doc = rel_doc.curr();
  const TRecnotype items_doc = cur_doc.items();
  cur_doc.freeze();

  for (cur_doc = 0L; cur_doc.pos() < items_doc; ++cur_doc)
  {
    const TString& tipodoc = rec_doc.get(DOC_TIPODOC);
    if (tipi_doc.is_key(tipodoc))
    {
      _datamin = rec_doc.get(DOC_DATADOC);
      _datamin.set_day(1);
      break;
    }
  }
}

void TRicalcolo_stats::calc_stats(const TDate& dfr, const TDate& dto)
{
  TRectype recfrom(LF_DOC), recto(LF_DOC);
  if (dfr.ok())
  {
    recfrom.put(DOC_DATADOC, dfr);
    recfrom.put(DOC_PROVV, "D");
  }
  if (dto.ok())
  {
    recto.put(DOC_DATADOC, dto);
    recto.put(DOC_PROVV, "D");
  }
  
  TRelation rel(LF_DOC);
  TCursor cur(&rel, "PROVV='D'", 3, &recfrom, &recto);
  const long items = cur.items();
  cur.freeze();

  TProgind pi(items, TR("Ricalcolo statistiche"), FALSE, TRUE);
  
  TDocumento* curr = new TDocumento;
  cur.file().set_curr(curr);
  const TDocumento& doc = *curr;
  
  long records = 0;
  _agg.reset();  
  
  for (cur = 0; cur.pos() < items; ++cur)
  {                         
    pi.addstatus(1);
    
    const TTipo_documento& tipodoc = doc.tipo();
    if (!tipodoc.statistiche())
      continue;   
      
    const bool nota_cr = tipodoc.nota_credito();
    for (int r = doc.physical_rows(); r > 0; r--)  
    {
      const TRiga_documento& rdoc = doc[r];
      if (nota_cr)
        _agg.sub(rdoc);
      else
        _agg.add(rdoc);
    }
    
    records++;
    if (records % 1000 == 0)  
      _agg.update();
  }
  _agg.update();
  if (_agg.empty())
    warning_box(TR("L'archivio riepilogativo delle statistiche ora ricalcolato risulta vuoto"));
}

bool TRicalcolo_stats::datein_handler(TMask_field& f, KEY k)
{                                    
  if (f.to_check(k))
  {
    const TDate inizio = f.get();
    if (inizio < _datamin)
      return f.error_box(FR("Impossibile effettuare la ricostruzione statistiche\nad una data antecedente il %s"), _datamin.string());
  }
  return TRUE;
}

void TRicalcolo_stats::main_loop()
{ 
  calcola_data_minima();

  TMask m("sv2100a");
  m.set_handler(F_FROMDATE, datein_handler);
  m.set(F_FROMDATE, _datamin);

  while (m.run() == K_ENTER)
  {
    const TDate dfr(m.get(F_FROMDATE));
    const TDate dto(m.get(F_TODATE));
    if (kill_stats(dfr, dto))
      calc_stats(dfr, dto);
  }
}

int sv2100(int argc, char* argv[])
{
  TRicalcolo_stats app;
  app.run(argc, argv, TR("Ricalcolo statistiche"));
  return 0;
}