// cg5200.cpp  - Visualizzazione saldi

#include <brwapp.h>
#include <msksheet.h> 
#include <tabutil.h>
#include <utility.h>
#include <urldefid.h>

#include <saldi.h>
#include <clifo.h>
#include <pconti.h>

#include "cglib.h"
#include "cg5200.h"

class TRiga_array : public TArray
{
public:
  bool add_riga(const TRectype& rec_saldi); 
};

bool TRiga_array::add_riga(const TRectype& rec_saldi) 
{
  bool flsca, found = FALSE;
  int annoes, annoesr;
  char flag = ' ', flagr = ' ';    
  char flagfin = ' ', flagfinr = ' ';
  TDate udata, udatar;
  long  unum, unumr;
  real saldofin,pdare,pavere,saldoini,pdarepro,paverepro;
  real saldofinr,pdarer,paverer,saldoinir,pdarepror,paverepror;
  
  
  for (int i = 0; i < items(); i++)
  {
    TRectype& r = (TRectype&)(*this)[i];
    annoes    = r.get_int(SLD_ANNOES);
    annoesr   = rec_saldi.get_int(SLD_ANNOES);

// TBI occhio al flag

    if ( annoes == annoesr ) 
    {           
      flsca     = r.get_bool(SLD_FLSCA);
      flag      = r.get_char(SLD_FLAGSALINI);
      flagfin   = r.get_char(SLD_FLAGSALFIN);
      pdare     = r.get_real(SLD_PDARE);
      pavere    = r.get_real(SLD_PAVERE);
      saldoini  = r.get_real(SLD_SALDO);   
      saldofin  = r.get_real(SLD_SALDOFIN);
      pdarepro  = r.get_real(SLD_PDAREPRO);
      paverepro = r.get_real(SLD_PAVEREPRO);
      udata     = r.get(SLD_DATAULMOV);
      unum      = r.get_long(SLD_NUMULTMOV);     
      flagr     = rec_saldi.get_char(SLD_FLAGSALINI);
      flagfinr  = rec_saldi.get_char(SLD_FLAGSALFIN);
      pdarer    = rec_saldi.get_real(SLD_PDARE);
      pdarer   += pdare;
      paverer   = rec_saldi.get_real(SLD_PAVERE);
      paverer  += pavere;
      saldoinir = rec_saldi.get_real(SLD_SALDO);
      saldofinr = rec_saldi.get_real(SLD_SALDOFIN);
      udatar    = rec_saldi.get(SLD_DATAULMOV);
      unumr     = rec_saldi.get_long(SLD_NUMULTMOV);
      udatar    = fnc_max(udatar,udata);
      //unumr     = (unum > unumr) ? unum : unumr;
      if (udata > udatar)
        unumr = unum;
      if (flagr == flag)
        saldoinir += saldoini;
      else saldoinir -= saldoini;
      if (saldoinir < ZERO) // saldoinir e' piu' piccolo di saldoini => vince il flag di saldoini
      {
        flagr = flag;
        saldoinir = -saldoinir;
      }      
      pdarepror  = rec_saldi.get_real(SLD_PDAREPRO);
      pdarepror  += pdarepro;
      paverepror = rec_saldi.get_real(SLD_PAVEREPRO);
      paverepror += paverepro;
      found = TRUE;                
      r.put(SLD_FLSCA, flsca);
      r.put(SLD_ANNOES, annoes);
      r.put(SLD_PDARE, pdarer);
      r.put(SLD_PAVERE,paverer);
      r.put(SLD_FLAGSALINI,flagr);
      r.put(SLD_FLAGSALFIN,flagfinr);
      r.put(SLD_SALDO, saldoinir);
      r.put(SLD_SALDOFIN, saldofinr);
      r.put(SLD_PDAREPRO, pdarepror);
      r.put(SLD_PAVEREPRO,paverepro);
      r.put(SLD_DATAULMOV, udatar);
      r.put(SLD_NUMULTMOV, unumr);
    }
  }
  if (!found)
  {
    TRectype* r = new TRectype(rec_saldi); // copia anche i valori di rec_saldi
    add(r);
  }
  return found;
}             

///////////////////////////////////////////////////////////
// Visualizzazione saldi
///////////////////////////////////////////////////////////

class TSaldibrowse_application : public TBrowse_application
{
  
  TMask*          _msk;
  TCursor       * _cur;
  TRelation     * _rel,* _rel1;
  TTable        * _esc;
  TRiga_array   _riga;
  int _anno, _annop, _g, _c;
  long _s;
  bool _saldo_conto, _saldo_gruppo, _saldo_sottoc, _scarongly;
  
protected:
  virtual bool user_create();
  virtual bool user_destroy();
  virtual TRelation*   get_relation() const { return _rel; }
  virtual TMask*       get_mask(int mode)   { return _msk; }
  virtual bool         changing_mask(int mode) {return FALSE; }
  virtual int read(TMask& m);
  virtual void init_query_mode(TMask&);
  virtual void init_modify_mode(TMask&); 

  static int  compare_rows(const TObject **o1, const TObject** o2);
  static bool anno_handler  (TMask_field& f, KEY k);
  static bool flsca_handler (TMask_field& f, KEY k);
  static bool sottoc_handler (TMask_field& f, KEY k);
  static bool sheet_action(TSheet_field& s, int r, KEY k);  
public:
  void add_r(int,int,real&,char,real&,char,real&,real&, real&,real&,
             TDate&,long,real&,real&,real&, real&, real&);
  void compilasheet();
  bool fai_filtro();
  TSheet_field& ss() const { return (TSheet_field&)_msk->field(F_SHEET_SALDI);}

  TSaldibrowse_application() {}
};

HIDDEN TSaldibrowse_application& app() { return (TSaldibrowse_application&) main_app(); }

bool TSaldibrowse_application::sheet_action(TSheet_field& s, int r, KEY k)
{                    
  // non si possono cancellare o aggiungere righe
  return (k != K_DEL && k != K_INS);
}

void TSaldibrowse_application::init_query_mode(TMask& m)
{
  _anno = 0;
  _scarongly = FALSE;
  m.disable(DLG_FINDREC);
  m.enable(F_DESCR_CONTO);
  m.enable(F_ANNO);
  m.enable(F_SCARICATO);
}

void TSaldibrowse_application::init_modify_mode(TMask& m)
{
  m.disable(DLG_FINDREC);
  m.disable(F_ANNO);
  m.disable(F_SCARICATO);
  TString tipo(m.get(F_TIPOCF));
  
  if (tipo=="C")
    m.disable(F_DESCR_CLIENTE);
  else if (tipo=="F")
    m.disable(F_DESCR_FORN);
  else m.disable(F_DESCR_CONTO);
}

bool TSaldibrowse_application::fai_filtro()
{
  TSaldo sld; 
  int annop = 0;
  char tipo;
  
  _saldo_gruppo = _saldo_conto = _saldo_sottoc = FALSE;
  TMask& m = curr_mask();
  tipo  = m.get(F_TIPOCF)[0];
  if (_anno != 0)
    _annop = EsePre(_anno);
  else 
    _annop = 0;
  _g = m.get_int(F_GRUPPO);
  _c = m.get_int(F_CONTO);

  if (tipo == '\0')
    _s = m.get_long(F_SOTTOCONTO);
  else if (tipo == 'C')
    _s = m.get_long(F_SOTTOC_CLIENTE);
  else _s = m.get_long(F_SOTTOC_FORN);
  if (_c == 0)
    _saldo_gruppo = TRUE;
  else if (_s == 0l)
    _saldo_conto = TRUE;
  else _saldo_sottoc = TRUE;   
  
  TLocalisamfile& saldi = _rel1->lfile();
  TRectype from (saldi.curr());
  TRectype to   (saldi.curr());
  from.zero();
  to.zero();
  
  
  from.put(SLD_GRUPPO,_g);
  if (_c != 0)
    from.put(SLD_CONTO, _c);
  if (_s != 0l)   
    from.put(SLD_SOTTOCONTO, _s);
  
  to.put(SLD_GRUPPO,_g);
  if (_c != 0)
    to.put(SLD_CONTO,_c);
  if (_s != 0l)   
    to.put(SLD_SOTTOCONTO,_s);
  
  _cur->setkey(2);
  
  _cur->setregion(from,to);                      
  
  return TRUE;   
}

bool TSaldibrowse_application::anno_handler(TMask_field& f, KEY key)
{
  if (key == K_TAB && f.focusdirty())
  { 
    TString cod(f.get());
    app()._anno = atoi(cod);
    app()._esc->zero();
    app()._esc->put("CODTAB",cod);
    if (cod.not_empty() && app()._esc->read() != NOERR)
    {
      f.error_box("Esercizio %s non presente.",(const char*) cod);
      return FALSE;
    }
  }
  return TRUE;
}

bool TSaldibrowse_application::flsca_handler(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
    app()._scarongly = f.get() == "" ? FALSE : TRUE;
  return TRUE;
}

bool TSaldibrowse_application::sottoc_handler(TMask_field& f, KEY key)
{
  bool ok = TRUE;
  
  if (key == K_TAB)
  {      
    bool stop = FALSE;
    
    TMask& m = f.mask();
    int  gruppo = m.get_int(F_GRUPPO);
    int  conto  = m.get_int(F_CONTO);
    const long sottoconto = atol(f.get());
    TLocalisamfile pconti(LF_PCON);
    
    const short id  = f.dlg();
    
    if (sottoconto != 0)
    {
      if (id == F_SOTTOCONTO)
      {
        if (gruppo != 0 && conto != 0)
        {
          pconti.setkey(1);
          pconti.put(PCN_GRUPPO, gruppo) ;
          pconti.put(PCN_CONTO, conto);
          pconti.put(PCN_SOTTOCONTO, sottoconto);
          ok = stop = pconti.read() == NOERR;
        }  
        else ok = FALSE;
      } 
      else
      {
        const char tipo = id == F_SOTTOC_CLIENTE ? 'C' : 'F';
        TLocalisamfile clifo (LF_CLIFO);       
        clifo.setkey(1);
        clifo.put(CLI_TIPOCF,tipo); 
        clifo.put(CLI_CODCF, sottoconto) ;
        app()._s = sottoconto;
        ok = stop = clifo.read() == NOERR;
        if (ok && (gruppo == 0 || conto == 0))
        {
          m.set(F_GRUPPO, gruppo = clifo.get_int("GRUPPO"));
          m.set(F_CONTO, conto = clifo.get_int("CONTO"));
          ok = stop = gruppo != 0 && conto != 0;
        }
      }
    }  
    else
      if (gruppo != 0 /* && conto != 0 */)
      {
        pconti.setkey(1);
        pconti.zero();
        pconti.put(PCN_GRUPPO, gruppo) ;
        pconti.put(PCN_CONTO, conto);
        ok = stop = pconti.read() == NOERR;
        if (ok) 
          m.set(F_DESCR_CONTO, pconti.get(PCN_DESCR));
        else 
          m.reset(F_DESCR_CONTO);
      }
    if (!ok)
      f.error_box("Conto errato o incompleto");
  }
  
  return ok;
}

bool TSaldibrowse_application::user_create()
{
  _rel   = new TRelation(LF_PCON);
  _rel1  = new TRelation(LF_SALDI);
  _cur   = new TCursor(_rel1, "", 2);
  _esc   = new TTable("ESC");
  _rel->add(LF_CLIFO,"TIPOCF=TMCF");
  _msk  = new TMask("cg5200a");
  _msk->set_handler(F_ANNO, anno_handler);
  _msk->set_handler(F_SCARICATO, flsca_handler);
  _msk->set_handler(F_SOTTOCONTO, sottoc_handler);
  _msk->set_handler(F_SOTTOC_CLIENTE, sottoc_handler);
  _msk->set_handler(F_SOTTOC_FORN, sottoc_handler);
  ss().disable();  
  ss().set_notify(sheet_action);      
  
  set_search_field(F_GRUPPO);
  
  return TRUE;
}

bool TSaldibrowse_application::user_destroy()
{
  delete _msk;
  delete _rel;
  delete _rel1;
  delete _cur;
  delete _esc;
  
  return TRUE;
}

int TSaldibrowse_application::read(TMask& m)
{
  m.autoload(*_rel);
  m.set(F_ANNO,_anno);
  m.set(F_SCARICATO,_scarongly ? "X" : " ");
  TString tipo(m.get(F_TIPOCF));
  //if (tipo == "C")
  //  m.set(F_SOTTOC_CLIENTE,_s);
  //else if (tipo == "F")
  //  m.set(F_SOTTOC_FORN,_s);
  fai_filtro();
  compilasheet();

  return NOERR;
}

void TSaldibrowse_application::add_r(int numrig,int a,real& slf,char sff,real& sc,char f,real& si,
                                     real& pd, real& pa,real& s,TDate& d,long n,real& pdp,
                                     real& pap,real& sp, real& dsc, real& asc)
{
  TSheet_field& cs = ss();
  char segno = ' ';
  
  TToken_string& riga = cs.row(numrig);
  riga.add(a, 0);
  riga.add(si.string(),1);
  if (si != ZERO)   
    riga.add(f,2);   
  riga.add(pd.string(),3); 
  riga.add(pa.string(),4); 
  if (s > ZERO)
    segno = 'D';
  else if (s < ZERO)
  {
    s = -s;
    segno = 'A'; 
  }            
  riga.add(s.string(),5);
  riga.add(segno,6);
  segno = ' ';
  if (sc > ZERO)
    segno = 'D';
  else if (sc < ZERO)
  {
    sc = -sc;
    segno = 'A';
  }     
  riga.add(slf.string(),7);
  if (slf != ZERO)   
    riga.add(sff,8);
  riga.add(sc.string(),9);
  riga.add(segno,10);
  riga.add(d.string(),11);
  riga.add(n,12);
  riga.add(pdp.string(),13);
  riga.add(pap.string(),14);
  segno = ' ';
  if (sp > ZERO)
    segno = 'D';
  else if (sp < ZERO)
  {
    sp = -sp;
    segno = 'A';
  }        
  riga.add(sp.string(),15);
  riga.add(segno,16); 
  riga.add(dsc.string(),17); 
  riga.add(asc.string(),18); 
}

int TSaldibrowse_application::compare_rows(const TObject** o1, const TObject** o2)
{
  TToken_string* r1 = ( TToken_string*)*o1;
  TToken_string* r2 = ( TToken_string*)*o2;
  int rt = 0;
  TDate   d1,d2;
  TString c1,c2;
  c1.format("%04d", r1->get_int(0));
  c2.format("%04d", r2->get_int(0));
  app()._esc->zero();
  app()._esc->put("CODTAB",c1);
  if (app()._esc->read() == NOERR) d1 = app()._esc->get_date("D0");
  else d1 = botime;
  app()._esc->put("CODTAB",c2);
  if (app()._esc->read() == NOERR) d2 = app()._esc->get_date("D0");
  else d2 = botime;
  
  if (d1 < d2) rt = -1;
  else if (d1 > d2) rt = +1;
  
  return rt;
}

void TSaldibrowse_application::compilasheet()
{
  char flagsal   = ' ';
  char flagfin   = ' ';
  real saldo = ZERO;
  real saldocompl = ZERO;
//  real saldosca = ZERO; 
  real saldopro = ZERO;
//  real saldo_gc = ZERO;
//  real saldoini_gc     = ZERO;     ??? a che servono????
//  real saldosca_gc     = ZERO;
//  real saldopro_gc     = ZERO;
  real saldoini  = ZERO; 
  real pdare     = ZERO;
  real pavere    = ZERO;
  real pdaresca  = ZERO;
  real paveresca = ZERO;
  real saldofin  = ZERO;
  real pdarepro  = ZERO;
  real paverepro = ZERO;
  int gruppo, conto, anno;
  long sottoconto;
  long ultimo_num = 0l; 
  TDate ultima_data;
  
  // nuova struttura archivio saldi
  
  _riga.destroy();
  
  TRecnotype items = _cur->items();
  *_cur = 0l;

  for (int i = 0; i < items; i++,++(*_cur))
  { 
                     
    const bool scar = _cur->curr().get_bool(SLD_FLSCA);
    if ((_scarongly && !scar) || (!_scarongly && scar))
      continue;
      
    anno   = _cur->curr().get_int(SLD_ANNOES);
    gruppo = _cur->curr().get_int(SLD_GRUPPO);
    conto  = _cur->curr().get_int(SLD_CONTO);
    sottoconto = _cur->curr().get_long(SLD_SOTTOCONTO);
    
    if (_anno != 0 && _anno != anno && _annop != anno) continue;
    
    if (gruppo != _g) continue;
    
    if (_saldo_conto && conto != _c) continue;
    
    if (_saldo_conto || _saldo_gruppo)
      _riga.add_riga(_cur->curr());
    
    if (_saldo_sottoc)
    {
      flagsal   = _cur->curr().get_char(SLD_FLAGSALINI);
      flagfin   = _cur->curr().get_char(SLD_FLAGSALFIN);
      saldoini  = _cur->curr().get_real(SLD_SALDO); 
      saldofin  = _cur->curr().get_real(SLD_SALDOFIN); 
      pdare     = _cur->curr().get_real(SLD_PDARE);
      pavere    = _cur->curr().get_real(SLD_PAVERE);
      pdarepro  = _cur->curr().get_real(SLD_PDAREPRO);
      paverepro = _cur->curr().get_real(SLD_PAVEREPRO);
      ultima_data = _cur->curr().get(SLD_DATAULMOV);
      ultimo_num  = _cur->curr().get_long(SLD_NUMULTMOV); 

      pdaresca  = ZERO;
      paveresca = ZERO;    
      

      if (flagsal == 'D')
        saldo = pdare + saldoini - pavere;
      else
        saldo = pdare - saldoini - pavere;

      if (flagfin == 'D')
        saldocompl = saldo + saldofin;
      else 
        saldocompl = saldo - saldofin;
      
      saldopro = pdarepro - paverepro;
      
      add_r(i,anno,saldofin,flagfin,saldocompl,flagsal,saldoini,pdare,pavere,saldo,
            ultima_data,ultimo_num,pdarepro,paverepro,saldopro,pdaresca, paveresca);   
    }
  }
  if (_saldo_gruppo || _saldo_conto)
  {
    for (int j = 0; j < _riga.items(); j++)
    {
      TRectype& riga = (TRectype&)_riga[j];
      anno = riga.get_int(SLD_ANNOES);
      flagsal   = riga.get_char(SLD_FLAGSALINI);
      flagfin   = riga.get_char(SLD_FLAGSALFIN);
      saldoini  = riga.get_real(SLD_SALDO);
      saldofin  = riga.get_real(SLD_SALDOFIN);
      pdare  = riga.get_real(SLD_PDARE);
      pavere = riga.get_real(SLD_PAVERE);
      if (flagsal == 'D')
        saldo = pdare + saldoini - pavere;
      else
        saldo = pdare - saldoini - pavere;

      if (flagfin == 'D')
        saldocompl = saldo + saldofin;
      else 
        saldocompl = saldo - saldofin;

      pdarepro  = riga.get_real(SLD_PDAREPRO);
      paverepro = riga.get_real(SLD_PAVEREPRO);
      saldopro  = pdarepro - paverepro;
      ultima_data = riga.get(SLD_DATAULMOV);
      ultimo_num  = riga.get_long(SLD_NUMULTMOV);

      pdaresca  = ZERO;
      paveresca = ZERO;

      if (!_scarongly && (j < _riga.items() - 1)) 
      {  
        TRectype& riga = (TRectype&)_riga[++j];
        if (riga.get_bool(SLD_FLSCA) &&
            sottoconto == riga.get_long(SLD_SOTTOCONTO) &&   
            conto      == riga.get_int(SLD_CONTO) &&
            gruppo     == riga.get_int(SLD_GRUPPO) &&
            anno       == riga.get_int(SLD_ANNOES))
        {
          pdaresca  = riga.get_real(SLD_PDARE);
          paveresca = riga.get_real(SLD_PAVERE);
        }
        else --j; 
      }
                                         
// come sopra
      add_r(j,anno,saldofin,flagfin,saldocompl,flagsal,saldoini,pdare,pavere,saldo,ultima_data,
            ultimo_num,pdarepro,paverepro,saldopro, pdaresca, paveresca);   
    } 
    _riga.destroy();
  }   
  
  // Ora ordina le righe dello sheet per ordine della data inizio esercizio
  TString_array& righe_sheet = ss().rows_array();
  righe_sheet.TArray::sort(compare_rows);
}     

int cg5200(int argc, char* argv[])
{
  TSaldibrowse_application a;
  a.run(argc, argv, "Visualizzazione saldi");
  return 0;
}




