#include <applicat.h>
#include <automask.h>
#include <printer.h>
#include <recarray.h>

#include "celib.h" 
#include "ce3400.h" 
#include "ce3400a.h" 

#include "../cg/cglib01.h" 

#include "cespi.h" 
#include "movce.h" 
#include "salce.h" 

///////////////////////////////////////////////////////////
// Generic Form
///////////////////////////////////////////////////////////

void TCespi_list_form::print_section(TPrint_section& sec)
{                          
  TPrinter& pr = printer();
  sec.update();
  const unsigned int h = sec.height();
  if (h > pr.rows_left())
    pr.formfeed();
  for (unsigned int r = 0; r < h; r++)
    pr.print(sec.row(r));
  sec.reset();
}

void TCespi_list_form::print_row(char filler)
{               
  TPrintrow row;
  if (filler > ' ')
  {
    TString256 spc; 
    spc.fill(filler, 132);
    row.put(spc);
  }
  printer().print(row);
}

void TCespi_list_form::print_separator()
{               
  print_row('_');
}

void TCespi_list_form::set_testata(const TMask& m)
{ 
  TPrint_section& header = section('H', odd_page);
  header.find_field(F_CODDITTA).set(m.get(F_CODDITTA));
  header.find_field(F_RAGSOC).set(m.get(F_RAGSOC));
  
  header.find_field(F_ESERCIZIO).set(m.get(F_ESERCIZIO));
  header.find_field(F_DATAINIZIO).set(m.get(F_DATAINIZIO));
  header.find_field(F_DATAFINE).set(m.get(F_DATAFINE));
  
  header.find_field(F_GRUPPO).set(m.get(F_GRUPPO));
  header.find_field(F_D_GRUPPO).set(m.get(F_D_GRUPPO));

  header.find_field(F_SPECIE).set(m.get(F_SPECIE));
  header.find_field(F_D_SPECIE).set(m.get(F_D_SPECIE));
  
  if (m.id2pos(F_SITUAZIONE) > 0)
    header.find_field(F_SITUAZIONE).set(m.get(F_SITUAZIONE));
}

TCespi_list_form::TCespi_list_form(const char* name) : TForm(name)
{ 
  _cur_form = this;
  printer().setheaderhandler(TForm::header_handler);
  printer().setfooterhandler(TForm::footer_handler);
}

TCespi_list_form::~TCespi_list_form() 
{ 
  _cur_form = NULL;
  printer().setheaderhandler(NULL);
  printer().setfooterhandler(NULL);
}

///////////////////////////////////////////////////////////
// Main Form
///////////////////////////////////////////////////////////

class TPR_form : public TCespi_list_form
{ 
public:
  TPrint_section& categoria() { return section('H', even_page); }
  TPrint_section& cespite()   { return section('B', first_page); }
  TPrint_section& saldo()     { return section('B', even_page); }
  TPrint_section& movimento() { return section('B', odd_page); }
  TPrint_section& totale()    { return section('B', odd_page); }

  TPR_form() : TCespi_list_form("ce3400a") { }
};

///////////////////////////////////////////////////////////
// Main Mask
///////////////////////////////////////////////////////////

class TPR_mask : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& f, TField_event e, long jolly);

public:
  TPR_mask() : TAutomask("ce3400a") { }
};

bool TPR_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{ 
  bool ok = TRUE;
  switch (f.dlg())
  {
  case F_FROM_CAT:
  case F_D_FROM_CAT:
  case F_TO_CAT:
  case F_D_TO_CAT:
    {
      TDitta_cespiti& dc = ditta_cespiti();
      ok = dc.on_category_event(f, e, jolly);
    }
    break;
  default: break;
  }
  return ok;
}

///////////////////////////////////////////////////////////
// Totalizer
///////////////////////////////////////////////////////////
            
class TTotalizer : public TAssoc_array
{
  TString _str;

protected:
  void add_num(const TRectype& rec, const char* name, char segno);
  
public:
  void add_rec(const TRectype& rec, char segno = '+');
  TTotalizer& operator+=(TTotalizer& tot);
  real get_num(const char* name);
  const TString& get(const char* name);
};

const TString& TTotalizer::get(const char* name) 
{  
  _str = get_num(name).string(); 
  return _str;
} 


void TTotalizer::add_num(const TRectype& rec, const char* name, char segno)
{
  real num = rec.get_real(name);
  if (!num.is_zero())
  {
    if (segno == '-')
      num = -num;
    real* val = (real*)objptr(name);
    if (val)
      *val += num;
    else
      add(name, num);
  }
}

void TTotalizer::add_rec(const TRectype& rec, char segno)
{                       
  add_num(rec, SALCE_CSTO,  segno);
  add_num(rec, SALCE_RIV75, segno);
  add_num(rec, SALCE_RIV83, segno);
  add_num(rec, SALCE_RIV90, segno);
  add_num(rec, SALCE_RIV91, segno);
  add_num(rec, SALCE_RIVGF, segno);
  add_num(rec, SALCE_RIVGC, segno);
}

TTotalizer& TTotalizer::operator+=(TTotalizer& tot)
{
  FOR_EACH_ASSOC_OBJECT(tot, obj, name, itm)
  {
    real* val = (real*)objptr(name);
    if (val)
      *val += *(real*)itm;
    else
      add(name, *(real*)itm);
  }
  return *this;
}

real TTotalizer::get_num(const char* name)
{
  real* val = (real*)objptr(name);
  return val ? *val : ZERO;
}

///////////////////////////////////////////////////////////
// Main Application
///////////////////////////////////////////////////////////

class TPR_app : public TSkeleton_application
{
  int _tipo_sit, _order; 
  TTotalizer _tot_grp, _tot_gen;
  TPR_form* _form;
  
protected:
  virtual void main_loop();
  
public:
  bool has_rivalutation(const TRectype& rec) const;

  void print_categoria(const TString& codtab);
  void print_cespite(const TRectype& cespi, const TRectype& salini);
  void print_movimenti(const TRectype& salini);
  void print_saldo(const real& valore);
  void print_total(TTotalizer& tot, const char* prompt = NULL);
};

bool TPR_app::has_rivalutation(const TRectype& rec) const
{
  if (rec.get_real(_tipo_sit == 1 ? SALCE_RIVGF : SALCE_RIVGC) > ZERO)
    return TRUE;
  if (rec.get_real(SALCE_RIV91) > ZERO)
    return TRUE;
  if (rec.get_real(SALCE_RIV90) > ZERO)
    return TRUE;
  if (rec.get_real(SALCE_RIV83) > ZERO)
    return TRUE;
  if (rec.get_real(SALCE_RIV75) > ZERO)
    return TRUE;
  return FALSE;
}

void TPR_app::print_categoria(const TString& codtab)
{
  TPrint_section& header = _form->categoria();
  
  header.find_field(F_CODTAB).set_prompt(_order == 1 ? FR("@bCategoria@r ") : TR("@bImpianto@r "));
  header.find_field(F_CODTAB).set(codtab);
  TString80 descr;
  if (_order == 1)
  {
    const TRectype& cat = ditta_cespiti().categoria(0, NULL, atoi(codtab));
    descr = cat.get("S0");
  }
  else
    descr = cache().get("CIM", codtab, "S0");
  header.find_field(F_D_CODTAB).set(descr);
  _form->print_separator();
  _form->print_row();
  _form->print_section(header);
  _form->print_separator();
  _tot_grp.destroy();
}

void TPR_app::print_cespite(const TRectype& cespi, const TRectype& salini)
{
  TPrint_section& ces = _form->cespite();
  ces.find_field(1).set(cespi.get(CESPI_IDCESPITE));
  ces.find_field(2).set(cespi.get(CESPI_DESC));
  ces.find_field(3).set(cespi.get(CESPI_DTCOMP));
  _form->print_section(ces);

  TTotalizer tot; 
  tot.add_rec(salini);
  print_total(tot, FR("@bSaldi@r"));
  _tot_grp += tot;
}

void TPR_app::print_movimenti(const TRectype& salini)
{
  const TString16 idcespite = salini.get(SALCE_IDCESPITE);
  const int codes = salini.get_int(SALCE_CODES);
  
  TEsercizi_contabili esc;
  const TDate inies = esc[codes].inizio();
  const TDate fines = esc[codes].fine();

  TRelation rel(LF_MOVCE);
  TRectype& movsem = rel.curr();
  movsem.put(MOVCE_IDCESPITE, idcespite);
  
  TString filtro;
  filtro << "(ANSI(DTMOV)>=\"" << inies.string(ANSI) << "\")";
  filtro << "&&(ANSI(DTMOV)<=\"" << fines.string(ANSI) << "\")";
  
  TCursor cur(&rel, filtro, 2, &movsem, &movsem);
  const long items = cur.items();
  
  TTotalizer totces;
  totces.add_rec(salini);
  
  if (items > 0)
  {
    cur.freeze();
    TTotalizer tot;
    for (cur = 0L; cur.pos() < items; ++cur)
    {        
      const TString4 codmov = movsem.get(MOVCE_CODMOV);
      const char tmv = cache().get("%TMC", codmov, "S6")[0];
      if (tmv == 'R')
      {
        const char segno = movsem.get_char(MOVCE_SEGNO);
        tot.add_rec(movsem, segno);
      }
    }
    print_total(tot, FR("@bRivalutazioni nell'esercizio@r"));
    totces += tot;
    _tot_grp += tot;
  }

  real valore = salini.get_real(SALCE_CSTO);
  valore += totces.get_num(SALCE_RIV75);
  valore += totces.get_num(SALCE_RIV83);
  valore += totces.get_num(SALCE_RIV90);
  valore += totces.get_num(SALCE_RIV91);
  valore += totces.get_num(_tipo_sit == 1 ? SALCE_RIVGF : SALCE_RIVGC);
  print_saldo(valore);
}

void TPR_app::print_saldo(const real& valore)
{
  TPrint_section& sal = _form->saldo();
  sal.find_field(1).set(valore.string());
  _form->print_section(sal);
}

void TPR_app::print_total(TTotalizer& tot, const char* prompt)
{ 
  if (prompt == NULL)
  {
    _form->print_separator();
    prompt = _order == 1 ? FR("@bTotale categoria@r ") : FR("@bTotale impianto@r ");
  }

  TPrint_section& body = _form->totale();
  body.find_field(1).set_prompt(prompt);
  
  TForm_item& field = body.find_field(2);
  const real costo(tot.get(SALCE_CSTO));
  if (!costo.is_zero())
  {                                
    field.show();
    field.set(costo.string());
  }
  else
    field.hide();
  
  body.find_field(3).set(tot.get(_tipo_sit == 1 ? SALCE_RIVGF : SALCE_RIVGC));
  body.find_field(4).set(tot.get(SALCE_RIV75));
  body.find_field(5).set(tot.get(SALCE_RIV83));
  body.find_field(6).set(tot.get(SALCE_RIV90));
  body.find_field(7).set(tot.get(SALCE_RIV91));
  _form->print_section(body);
}

void TPR_app::main_loop()
{
  TPR_mask m;
  ditta_cespiti().init_mask(m);
  while (m.run() != K_QUIT)
  {
    const int ese = m.get_int(F_ESERCIZIO);
    const int gruppo = m.get_int(F_GRUPPO);
    const TString4 specie = m.get(F_SPECIE);
    ditta_cespiti().set_attivita(ese, gruppo, specie);
  
    TPR_form form;
    _form = &form;
  
    TRelation rel(LF_CESPI);    
    TString expr;
    expr << "IDCESPITE==IDCESPITE|CODES==" << m.get(F_ESERCIZIO) << "|TPSALDO==1";
    rel.add(LF_SALCE, expr, 1, LF_CESPI, 1);  
    expr.rtrim(1); expr << '2';
    rel.add(LF_SALCE, expr, 1, LF_CESPI, 2);  

    const TRectype& cespi = rel.curr();
    const TRectype& salini = rel.curr(-1);
    const TRectype& salpro = rel.curr(-2);
    
    _tipo_sit = m.get_int(F_SITUAZIONE);
    _order = m.get_int(F_ORDINAMENTO);
    
    TString filter;
    if (_order == 1)
    {
      const int fc = m.get_int(F_FROM_CAT);
      const int tc = m.get_int(F_TO_CAT);
      if (fc != 0)
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << CESPI_CODCAT << ">=" << fc << ')';
      }
      if (tc != 0)
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << CESPI_CODCAT << "<=" << tc << ')' ;
      }
    }
    else
    {
      const TString& fi = m.get(F_FROM_IMP);
      const TString& ti = m.get(F_TO_IMP);
      if (!fi.blank())
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << CESPI_CODIMP << ">=" << fi << ')';
      }
      if (!fi.blank())
      {
        if (filter.not_empty()) filter << "&&";
        filter << '(' << CESPI_CODIMP << "<=" << ti << ')';
      }
    }
    
    const char* orderby = _order == 1 ? "CODCAT|IDCESPITE" : "CODIMP|IDCESPITE";
    TSorted_cursor cur(&rel, orderby, filter);

    const long items = cur.items();
    cur.freeze();
    
    printer().open();
    form.set_testata(m);
    
    TString16 last_group = "@";  // Simbolo speciale per indicare nessuna stampa!
    _tot_gen.destroy();
    
    for (cur = 0L; cur.pos() < items; ++cur)
    {
      // Controllo qui la validit� per non incasinare il valutatore con stringhe e numeri
      if (cespi.get_int(CESPI_CODCGRA) != gruppo || cespi.get(CESPI_CODSPA) != specie)
        continue;
      if (has_rivalutation(salpro))
      {
        const TString16 curr_group = cespi.get(_order == 1 ? CESPI_CODCAT : CESPI_CODIMP);
        if (curr_group != last_group)
        {
          if (last_group != "@")
          {
            print_total(_tot_grp); 
            _tot_gen += _tot_grp;
          }
          last_group = curr_group;
          print_categoria(curr_group);
        } 
        form.print_row();
        print_cespite(cespi, salini);
        print_movimenti(salini);
      }
    }
    if (last_group != "@")
    {
      print_total(_tot_grp);
      _tot_gen += _tot_grp;
      _form->print_separator();
      print_total(_tot_gen, FR("@bTOTALE GENERALE@r"));
      printer().formfeed();
    }

    printer().close();
    xvtil_statbar_set("");
  }
}

int ce3400(int argc, char* argv[])
{
  TPR_app app;
  app.run(argc, argv, TR("Prospetto rivalutazioni"));
  return 0;
}