// 771230.cpp - Quadri C, D, D bis, D1, E, E1, E2,
// Dal 2002 il Quadro LA riassume SC ed SE, che a loro volta erano D e D1)

#include <msksheet.h>
#include <progind.h>
#include <recarray.h>
#include <relapp.h>

#include "77lib.h"
#include "771230.h" 
#include "774200.h"
#include "defmask.h"

#include <anagr.h>
#include "caus77.h"
#include "quadroc.h"
#include "quadrod.h"
#include "quadrod1.h"
#include "quadroe.h"
#include "quadroe1.h"
#include "prospe1.h"
#include "rpag.h"
#include "scperc.h"

TString _quadronuovo;

///////////////////////////////////////////////////////////
// Righe pagamento delle schede percipienti
///////////////////////////////////////////////////////////

// Somma tutti i campi contenenti importi
TRectype& operator += (TRectype& dst, const TRectype& src)
{
  for (int i = dst.items()-1; i >= 0; i--)
  {              
    const char* name = dst.fieldname(i);
    if (dst.type(name) == _realfld && dst.length(name) >= 9)
    {
      real num = dst.get_real(name);
      num += src.get_real(name);
      dst.put(name, num);
    }
  }
  return dst;
}

class TRighe_pagamento : public TAssoc_array
{
  TString _quadro;       // Codice quadro
  TArray _prosp_e1;      // Righe prospetto e1
  
public:
  void add_riga(const TRectype& scheda, const TRectype& riga);
  
  const TRectype* prospetto_e1(char caus);
  
  TRighe_pagamento(const char* quadro);
  virtual ~TRighe_pagamento() { }
};

TRighe_pagamento::TRighe_pagamento(const char* quadro)
                : _quadro(quadro)
{ }

const TRectype* TRighe_pagamento::prospetto_e1(char caus)
{
  const int index = caus - 'C';
  return (const TRectype*)_prosp_e1.objptr(index);
}

void TRighe_pagamento::add_riga(const TRectype& scheda, const TRectype& riga)
{ 
  TString16 chiave;
  
  const char causqua = toupper(scheda.get_char(SPR_CAUSQUA));
  chiave << causqua;
  if (_quadro == "C")
    chiave << scheda.get(SPR_FLAGTS); else
  if (_quadro == "E1")
  {                    
    // Le righe del prospetto vengono trattate a parte
    if (causqua >= 'C')
    {                    
      const int index = causqua - 'C';
      TRectype* rec = (TRectype*)_prosp_e1.objptr(index);
      if (rec)
        *rec += riga;
      else
        _prosp_e1.add(riga, index);
      return;
    }
    chiave << riga.get("PERC");
  }  
  
  TRectype* rec = (TRectype*)objptr(chiave);
  if (rec)
  {
    *rec += riga;
    if (_quadro == "C") // Nel caso di quadro C somma anche i giorni detr dip.
    {
      const int gglav = rec->get_int(PAG_GIOLAVDIP) + riga.get_int(PAG_GIOLAVDIP);
      rec->put(PAG_GIOLAVDIP,gglav);
    }
  }
  else
  {
    rec = new TRectype(riga);
    add(chiave, rec);
  }  
    
  if (_quadro == "DB")  
  { 
    // Calcola il flag per il contributo del 10%
    // Esso deve essere A se tutte le righe sono A, 
    // C se tutte sono C, B in tutti gli altri casi  
    char cod10 = toupper(riga.get_char(PAG_COD10));   // Valore scheda attuale
    if (cod10 < 'A' || cod10 > 'C')                   // Mette a posto archivi incompleti
      cod10 = 'B';                                  
    char lcq = rec->get_char(PAG_COD10);              // Valore ultima scheda
    switch (lcq)  
    {       
    case 'A':
      if (cod10 != 'A')
        lcq = 'B';
      break;
    case 'B':
      break;
    case 'C':
      if (cod10 != 'C')
        lcq = 'B';
      break;
    default:
      lcq = cod10;
      break;
    }  
    rec->put(PAG_COD10, lcq);                       // Aggiorna valore
  }
}

///////////////////////////////////////////////////////////
// Gestione quadri C - E2
///////////////////////////////////////////////////////////

class TQuadroC_E2 : public TRelation_application
{
private:                                             
  TString8   _quadro;    // Codice del quadro in gestione        
  int        _file;
  bool       _registra;  // Se TRUE fa i riporti
  TRelation* _rel;
  TMask*     _msk, *_mskp;
  long       _codditta;    
  
private:               
  bool QuadroC()    const { return _quadro == "C"; }  
  bool QuadroD()    const { return _quadro == "D"; }  
  bool QuadroDbis() const { return _quadro == "DB"; }  
  bool QuadroD1()   const { return _quadro == "D1"; }  
  bool QuadroE()    const { return _quadro == "E"; }  
  bool QuadroE1()   const { return _quadro == "E1"; }  
  bool QuadroE2()   const { return _quadro == "E2"; }  
  bool QuadroLA()   const { return _quadro == "LA"; }  
                    
protected:
  virtual bool user_create();
  virtual bool user_destroy();         
  virtual int  read(TMask& m);
  virtual int  rewrite(const TMask& m);
  virtual int  write  (const TMask& m);  
  virtual bool remove();
  virtual TRelation* get_relation() const { return _rel; }
  virtual bool changing_mask(int mode) { return FALSE; }
  virtual TMask* get_mask(int mode) { return _msk; }
  virtual void init_query_mode (TMask&);
  virtual void init_query_insert_mode (TMask&);
  virtual void init_insert_mode (TMask&);
  virtual void init_modify_mode (TMask&);
                                 
protected: 
  void fill_sheet(const TMask& m); 
  void pack_sheet(const TMask& m);
  
  TSheet_field& find_sheet(const TMask& m) const;
  void read_sheet(TMask& m) const;
  int write_sheet(const TMask& m, bool re) const;
  int remove_sheet(const TMask& m) const;
  
  void genera_aliquota(TRectype& quadro, const char* aliquota, 
                       const char* imponibile, const char* imposta) const;
  void genera_c(TRectype& quadro, const TRectype& riga) const;
  void genera_d(TRectype& quadro, const TRectype& riga) const;
  void genera_d_bis(TRectype& quadro, const TRectype& riga) const;
  void genera_d1(TRectype& quadro, const TRectype& riga) const;
  void genera_e(TRectype& quadro, const TRectype& riga) const;
  void genera_e1(TRectype& quadro, const TRectype& riga) const;
  void genera_la(TRectype& quadro, const TRectype& riga) const;
  void genera_righe(TRighe_pagamento& righe) const;
  void distruzione() const;
  void generazione();
  
  static bool codice_handler(TMask_field& f, KEY key);
  static bool genera_handler(TMask_field& f, KEY key);
  static bool prospbtn_handler(TMask_field& f, KEY key);
  
  static bool ricalcola_imposte_c(TMask_field& f, KEY key);
  static bool ricalcola_imposte_d(TMask_field& f, KEY key);
  static bool ricalcola_imposte_dbis(TMask_field& f, KEY key);
  static bool ricalcola_imposte_e(TMask_field& f, KEY key);
  static bool ricalcola_imposte_la(TMask_field& f, KEY key);
  
  static bool ricalcola_imposte_e1(TMask_field& f, KEY key);
  static bool prospetto_e1_notify(TSheet_field& s, int r, KEY k);
//  void reset_prospetto_e1() const; 
  void read_prospetto_e1() const; 
  int write_prospetto_e1() const;
    
  static bool ricalcola_imposte_e2(TMask_field& f, KEY key);
  static bool ritenute_handler_e2(TMask_field& f, KEY key);

public:                    
  TQuadroC_E2(const char* quadro);
  virtual ~TQuadroC_E2() {};
};                    

inline TQuadroC_E2& app() { return (TQuadroC_E2&)main_app(); }

TQuadroC_E2::TQuadroC_E2(const char* quadro)
           : _msk(NULL), _mskp(NULL), _rel(NULL), _quadro(quadro), _file(0)
{  
}

TSheet_field& TQuadroC_E2::find_sheet(const TMask& m) const
{
  for (int f = m.fields()-1; f > 0; f--)
  {
    if (m.fld(f).is_kind_of(CLASS_SHEET_FIELD))
      break;
  }
  CHECK(f > 0, "Cant' find the spreadsheet");
  return (TSheet_field&)m.fld(f);
}

void TQuadroC_E2::read_sheet(TMask& m) const
{
  TSheet_field& sheet = find_sheet(m);
  sheet.destroy();
  TRectype key(get_relation()->curr());
  key.zero("NPROG");
  TRecord_array a(key, "NPROG");
      
  TMask& sm = sheet.sheet_mask();
  for (int r = 0; r < a.rows(); r++)
  {     
    const TRectype& rec = a.row(r+1);
    TToken_string& row = sheet.row(r);
    for (short id = 101; ; id++)
    {                              
      const int pos = sm.id2pos(id);
      if (pos >= 0)
      {
        TMask_field& mf = sm.fld(pos);
        const TFieldref* fr = mf.field();
        if (fr)
          row.add(fr->read(rec));
        else     
          row.add("");
      }  
      else
        break;
    }
    sheet.check_row(r);
  }
}

int TQuadroC_E2::write_sheet(const TMask& m, bool re) const
{
  TRectype rec(get_relation()->curr());
  rec.zero("NPROG");
  TRecord_array a(rec, "NPROG");
  a.destroy_rows();
      
  TSheet_field& sheet = find_sheet(m);
  TMask& sm = sheet.sheet_mask();
  
  TString val;
  for (int r = 0; r < sheet.items(); r++)
  {     
    TToken_string& row = sheet.row(r);
    rec.put("NPROG", r+1);
    for (short id = FIRST_FIELD; ; id++)
    {                              
      const int pos = sm.id2pos(id);
      if (pos >= 0)
      {
        TMask_field& mf = sm.fld(pos);
        const TFieldref* fr = mf.field();
        if (fr) 
        {     
          val = row.get(id - FIRST_FIELD);
          fr->write(val, rec);
        }  
      }  
      else
        break;
    }
    a.add_row(rec);
  }
  return a.write(re);
}

int TQuadroC_E2::remove_sheet(const TMask& m) const
{
  TSheet_field& sheet = find_sheet(m);
  sheet.destroy();
  return write_sheet(m, TRUE);
}

int TQuadroC_E2::rewrite(const TMask& m)
{
  pack_sheet(m);
  int err = TRelation_application::rewrite(m);
  if (err == NOERR)
    err = write_sheet(m, TRUE);
  if (err == NOERR)  
    _registra = TRUE;
  return err;
}

int TQuadroC_E2::read(TMask& m)
{
  int err = TRelation_application::read(m);
  if (err == NOERR)
    read_sheet(m);
  return err;
}

int TQuadroC_E2::write(const TMask& m)
{               
  pack_sheet(m);
  int err = TRelation_application::write(m);
  if (err == NOERR)
    err = write_sheet(m, FALSE);
  if (err == NOERR)  
  _registra = TRUE;
  return err;
}

bool TQuadroC_E2::remove()
{        
  bool ok = TRelation_application::remove();
  if (ok)
  {  
    remove_sheet(curr_mask());
    _registra = TRUE;
  }
  return ok;
}

bool TQuadroC_E2::user_create()
{                      
  _codditta = get_firm_770();
  _registra = FALSE;
  
  TString8 name("771230"); 
  name << _quadro;
  _msk = new TMask(name);
  
  _msk->first_focus(F_CODANAGR);
  set_search_field(F_CODANAGR);
  _msk->set_handler(F_CODANAGR, codice_handler);
  
  if (_msk->id2pos(F_GENERA) >= 0)
    _msk->set_handler(F_GENERA, genera_handler);

  TSheet_field& s = (TSheet_field&)_msk->field(F_RIGHE);
  TMask& m = s.sheet_mask();
  if (QuadroC())
  {
    _file = LF_QUAC;
    m.set_handler(102, ricalcola_imposte_c);
    m.set_handler(105, ricalcola_imposte_c);
    m.set_handler(107, ricalcola_imposte_c);
    m.set_handler(108, ricalcola_imposte_c);
  } else
  if (QuadroD()) // Obsoleto dal 2002: confluito in LA
  {
    _file = LF_QUAD;
    m.set_handler(102, ricalcola_imposte_d);
    m.set_handler(104, ricalcola_imposte_d);
    m.set_handler(105, ricalcola_imposte_d);
    m.set_handler(106, ricalcola_imposte_d);
    m.set_handler(107, ricalcola_imposte_d);
  } else
  if (QuadroD1()) // Obsoleto dal 2002: confluito in LA
  {
    _file = LF_QUAD1;
    m.set_handler(102, ricalcola_imposte_d);
    m.set_handler(104, ricalcola_imposte_d);
    m.set_handler(105, ricalcola_imposte_d);
    m.set_handler(106, ricalcola_imposte_d);
    m.set_handler(107, ricalcola_imposte_d);
  } else
  if (QuadroDbis())
  {
    _file = LF_QUADBIS;
    m.set_handler(102, ricalcola_imposte_dbis);
    m.set_handler(104, ricalcola_imposte_dbis);
    m.set_handler(105, ricalcola_imposte_dbis);
    m.set_handler(106, ricalcola_imposte_dbis);
    m.set_handler(107, ricalcola_imposte_dbis);
  } else
  if (QuadroE())
  {                
    _file = LF_QUAE;
    m.set_handler(103, ricalcola_imposte_e);
    m.set_handler(104, ricalcola_imposte_e);
  } else
  if (QuadroE1())
  {
    _msk->set_handler(F_PROSPBTN, prospbtn_handler);
    _file = LF_QUAE1;
    m.set_handler(105, ricalcola_imposte_e1);
    m.set_handler(106, ricalcola_imposte_e1);
    _mskp = new TMask("771230pr");
    TSheet_field& s = (TSheet_field&)_mskp->field(F_PROSPETTO);
    s.set_notify(prospetto_e1_notify);
    read_prospetto_e1();
  } else
  if (QuadroE2())
  {
    _file = LF_QUAE2;
    m.set_handler(103, ricalcola_imposte_e2);
    m.set_handler(104, ricalcola_imposte_e2);
    m.set_handler(105, ritenute_handler_e2);
  } else
  if (QuadroLA()) // Nuovo del 2002: riassume SC ed SE
  {
    _file = LF_QUALA;
    m.set_handler(102, ricalcola_imposte_la);
    m.set_handler(105, ricalcola_imposte_la);
    m.set_handler(106, ricalcola_imposte_la);
    m.set_handler(107, ricalcola_imposte_la);
    m.set_handler(108, ricalcola_imposte_la);
  }

  _rel = new TRelation(_file);
  
  return TRUE;
}

bool TQuadroC_E2::user_destroy()
{ 
  if (_registra)
  {
    TRiporti rip;
    rip.set(_quadro);
  }

  delete _rel; 
  delete _msk;
  if (_mskp)
    delete _mskp;
  
  return TRUE;
}

void TQuadroC_E2::init_query_mode(TMask& m)
{
  m.set(F_CODDITTA, _codditta);
  
  if (_msk->id2pos(F_GENERA) >= 0)
    m.show(F_GENERA);
  
  m.show(F_CODANAGR);
  m.hide(H_CODANAGR);
  
  TSheet_field& sf = (TSheet_field&)m.field(F_RIGHE);
  sf.destroy();
}

void TQuadroC_E2::init_query_insert_mode(TMask& m)
{
  m.set(F_CODDITTA, _codditta);
  m.show(H_CODANAGR);
  m.hide(F_CODANAGR);
}

void TQuadroC_E2::init_insert_mode(TMask& m)
{              
  if (m.id2pos(F_GENERA) >= 0)
    m.hide(F_GENERA);
  fill_sheet(m);
}

void TQuadroC_E2::init_modify_mode(TMask& m)
{
  if (m.id2pos(F_GENERA) >= 0)
    m.hide(F_GENERA);
  fill_sheet(m);
}

void TQuadroC_E2::fill_sheet(const TMask& m)
{
  TSheet_field& sf = (TSheet_field&)m.field(F_RIGHE);
  for (int r = sf.items(); r < 16; r++)
    sf.row(r);
  
  if (QuadroD() || QuadroDbis())
  {
    TLocalisamfile anagr(LF_ANAG);  
    anagr.put(ANA_TIPOA, m.get(F_TIPOA));
    anagr.put(ANA_CODANAGR, m.get(F_CODANAGR));
    bool estero = FALSE;
    if (anagr.read() == NOERR)
      estero = anagr.get_bool(ANA_SOGGNRES);
    TMask& sm = sf.sheet_mask();
    sm.enable(106, estero);          // Somme non sogg. reg. conv.
    sf.enable_column(106, estero);
  }
}

void TQuadroC_E2::pack_sheet(const TMask& m)
{
  TSheet_field& sf = (TSheet_field&)m.field(F_RIGHE);
  for (int r = sf.items(); r >= 0; r--)
  {
    TToken_string& row = sf.row(r);
    if (row.empty_items())
      sf.destroy(r);
  }  
} 

void TQuadroC_E2::distruzione() const
{       
  TWait_cursor hourglass;
  TRelation rel(_file);
  TRectype& curr = rel.curr();
  curr.put("CODDITTA", _codditta);
  
  const char* filter = "";
  if (curr.exist("GENERATA")) 
    filter = "GENERATA=\"X\"";
  
  TCursor cur(&rel, filter, 1, &curr, &curr);
  long items = cur.items();
  cur.freeze();
  for (cur = 0L; cur.pos() < items; ++cur)
    rel.remove();
  cur.freeze(FALSE);
  
  if (QuadroE1())
  {
    TLocalisamfile prosp(LF_PROSPE1);
    prosp.put("CODDITTA", _codditta);
      
    for (int err = prosp.read(_isgteq); err == NOERR; err = prosp.next())
    {
      if (prosp.get_long("CODDITTA") != _codditta)
        break;
      prosp.remove();  
    }
  }

  if (curr.exist("NPROG"))
  {
    items = cur.items();
    cur.freeze();        
    TRectype last(_file);
    long nextnumber = 1;
    for (cur = 0L; cur.pos() < items; ++cur)
    {                    
      if (!curr.same_key(last,1,1))
      {
        nextnumber = 1;
        last = curr;
      }
      long nprog = curr.get_long("NPROG");
      if (nprog > nextnumber)
      {
        rel.remove();
        curr.put("NPROG", nextnumber);
        rel.write();
      }
      nextnumber++;
    }
  }
  //bool same_key(const TRectype& rec, int key = 1, int skip_last = 0) const
}

void TQuadroC_E2::genera_aliquota(TRectype& quadro, const char* aliquota, 
                                  const char* imponibile, const char* imposta) const
{
  real aliq = quadro.get_real(aliquota);
  if (aliq == ZERO)
  {
    const real impon = quadro.get(imponibile);
    if (impon != ZERO)
    {
      const real impos = quadro.get(imposta);
      aliq = impos * 100.0 / impon;
      if (aliq % real(1.0) == ZERO)  
        quadro.put(aliquota, aliq);
    }  
  }
}                                   

void TQuadroC_E2::genera_c(TRectype& quadro, const TRectype& riga) const
{   
  quadro.put(QUC_PERC, riga.get(PAG_PERC));

  real ammlordo = riga.get(PAG_IMPONIBILE);           
  ammlordo += riga.get_real(PAG_SOMNSRIT);
  ammlordo += riga.get_real(PAG_CONTROBB);
  ammlordo += riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUC_AMMLORDO, ammlordo);                    // 13

  quadro.put(QUC_CONTROBB, riga.get(PAG_CONTROBB));      // 14

  real somme = riga.get_real(PAG_COMPENSO);
  somme -= riga.get_real(PAG_IMPONIBILE);
  somme += riga.get_real(PAG_SPESA);
  somme -= riga.get_real(PAG_IMPCPA);
  somme -= riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUC_SOMNONSOGG, somme);                     // 15
  
  quadro.put(QUC_IMPONIBILE, riga.get(PAG_IMPONIBILE));  // 16
  quadro.put(QUC_IMPOSTA, riga.get(PAG_RITLORDA));       // 17
  quadro.put(QUC_DETCARFAM, riga.get(PAG_DETFAMIL));     // 18
  quadro.put(QUC_GGLAVDIP, riga.get(PAG_GIOLAVDIP));     // 19
  quadro.put(QUC_DETLAVDIP, riga.get(PAG_DETLAVDIP));    // 20
  quadro.put(QUC_TOTDET, riga.get(PAG_TOTDET));          // 21
  quadro.put(QUC_RITENUTE, riga.get(PAG_RITENUTA));      // 22
  
  genera_aliquota(quadro, QUC_PERC, QUC_IMPONIBILE, QUC_IMPOSTA);
}

void TQuadroC_E2::genera_d(TRectype& quadro, const TRectype& riga) const
{
  quadro.put(QUD_PERC, riga.get(PAG_PERC));

  real ammlordo = riga.get(PAG_IMPONIBILE);           
  ammlordo += riga.get_real(PAG_SOMNSRIT);
  ammlordo += riga.get_real(PAG_CONTROBB);
  ammlordo += riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUD_TOTALE, ammlordo);                      // 16

  real somme = riga.get_real(PAG_COMPENSO);
  somme -= riga.get_real(PAG_IMPONIBILE);
  somme += riga.get_real(PAG_SPESA);
  somme -= riga.get_real(PAG_IMPCPA);
  somme -= riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUD_SOMME, somme);                          // 17

  quadro.put(QUD_SOMREGCONV, riga.get(PAG_SOMREGCONV));  // 18
  quadro.put(QUD_IMPONIBILE, riga.get(PAG_IMPONIBILE));  // 19
  quadro.put(QUD_IMPORTO, riga.get(PAG_RITENUTA));       // 20
  
  genera_aliquota(quadro, QUD_PERC, QUD_IMPONIBILE, QUD_IMPORTO);
}

void TQuadroC_E2::genera_d_bis(TRectype& quadro, const TRectype& riga) const
{
  genera_d(quadro, riga);
  quadro.put("CONTR10", riga.get(PAG_COD10));
}

void TQuadroC_E2::genera_d1(TRectype& quadro, const TRectype& riga) const
{
  quadro.put(QD1_PERC, riga.get(PAG_PERC));

  real ammlordo = riga.get(PAG_IMPONIBILE);           
  ammlordo += riga.get_real(PAG_SOMNSRIT);
  ammlordo += riga.get_real(PAG_CONTROBB);
  ammlordo += riga.get_real(PAG_SOMREGCONV);
  quadro.put(QD1_TOTALE, ammlordo);                      // 12
  
  quadro.put(QD1_SPESEANT, riga.get_real(PAG_SPESA));    // 13
  
  real quota = riga.get_real(PAG_SOMNSRIT);
  quota -= riga.get_real(PAG_SPESA);
  quadro.put(QD1_QUOTAPRO, quota);                       // 14

  quadro.put(QD1_IMPONIBILE, riga.get_real(PAG_IMPONIBILE));            // 15
  quadro.put(QD1_IMPORTO, riga.get(PAG_RITENUTA));       // 16
  
  genera_aliquota(quadro, QD1_PERC, QD1_IMPONIBILE, QD1_IMPORTO);
}

void TQuadroC_E2::genera_e(TRectype& quadro, const TRectype& riga) const
{
  quadro.put(QUE_PERC, riga.get(PAG_PERC));

  quadro.put(QUE_IMPONIBILE, riga.get(PAG_IMPONIBILE));           // 12
  quadro.put(QUE_IMPORTO, riga.get(PAG_RITENUTA));                // 14
  
  real netto = riga.get(PAG_IMPONIBILE);
  netto -= riga.get_real(PAG_RITENUTA);
  quadro.put(QUE_NETTO, netto);                                   // 15   
  
  real nonsog = riga.get(PAG_COMPENSO);
  nonsog -= riga.get_real(PAG_IMPONIBILE);
  nonsog += riga.get_real(PAG_SPESA);
  quadro.put(QUE_SOMME, nonsog);                                  // 16

  genera_aliquota(quadro, QUE_PERC, QUE_IMPONIBILE, QUE_IMPORTO); // 13
}

void TQuadroC_E2::genera_e1(TRectype& quadro, const TRectype& riga) const
{
  quadro.put(QE1_PERC, riga.get(PAG_PERC));

  real somme = riga.get(PAG_COMPENSO);
  somme += riga.get_real(PAG_SPESA);
  quadro.put(QE1_SOMME, somme);                                   // 12
  
  quadro.put(QE1_AMMONTARE, riga.get(PAG_IMPONIBILE));            // 13
    
  quadro.put(QE1_IMPORTO, riga.get(PAG_RITENUTA));                // 15
    
  quadro.put(QE1_NETTO, riga.get(PAG_NETTO));                     // 16
  
  genera_aliquota(quadro, QE1_PERC, QE1_AMMONTARE, QUE_IMPORTO);  // 14
}

void TQuadroC_E2::genera_la(TRectype& quadro, const TRectype& riga) const
{
  quadro.put(QUD_PERC, riga.get(PAG_PERC));

  real ammlordo = riga.get(PAG_IMPONIBILE);           
  ammlordo += riga.get_real(PAG_SOMNSRIT);
  ammlordo += riga.get_real(PAG_CONTROBB);
  ammlordo += riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUD_TOTALE, ammlordo);                      // 16

  real somme = riga.get_real(PAG_COMPENSO);
  somme -= riga.get_real(PAG_IMPONIBILE);
  somme += riga.get_real(PAG_SPESA);
  somme -= riga.get_real(PAG_IMPCPA);
  somme -= riga.get_real(PAG_SOMREGCONV);
  quadro.put(QUD_SOMME, somme);                          // 17

  quadro.put(QUD_SOMREGCONV, riga.get(PAG_SOMREGCONV));  // 18
  quadro.put(QUD_IMPONIBILE, riga.get(PAG_IMPONIBILE));  // 19
  quadro.put(QUD_IMPORTO, riga.get(PAG_RITENUTA));       // 20
  
  genera_aliquota(quadro, QUD_PERC, QUD_IMPONIBILE, QUD_IMPORTO);
}


void TQuadroC_E2::genera_righe(TRighe_pagamento& righe) const
{                                       
  TLocalisamfile file(_file);
  TRectype& curr = file.curr();
  int nriga = 1;
  righe.restart();
  for (THash_object* ho = righe.get_hashobj(); ho; ho = righe.get_hashobj(), nriga++)
  {
    const TString& chiave = ho->key();
    const TRectype& riga = (const TRectype&)ho->obj();

    curr.zero();
    curr.put(PAG_CODDITTA, riga.get(PAG_CODDITTA)); 
    curr.put(PAG_TIPOA, riga.get(PAG_TIPOA));
    curr.put(PAG_CODANAGR, riga.get(PAG_CODANAGR));
    curr.put("NPROG", nriga);
    curr.put("CAUSALE", chiave[0]);
    curr.put("GENERATA", bool(TRUE));
    
    switch (_quadro[0]) 
    {
    case 'C':
      curr.put("TASSAZIONE", chiave[1]);
      genera_c(curr, riga);
      break;
    case 'D':
      switch(_quadro[1])
      {
      case '1': genera_d1(curr, riga); break;
      case 'B': genera_d_bis(curr, riga); break;
      default : genera_d(curr, riga); break;
      }
      break;
    case 'E':  
      if (_quadro[1] == '1') 
        genera_e1(curr, riga);
      else
      {
        if (_quadro[1] == '\0')
          genera_e(curr, riga);
      }    
      break;
    case 'L':  
      if (_quadro[1] == 'A')
        genera_la(curr, riga);
      break;
    default:
      CHECK(FALSE, "Quadro non generabile dalle schede");  
      break;
    }  
    
    int err = file.write();
    while (err == _isreinsert)
    {
      curr.put("NPROG",++nriga);
      err = file.write();
    }
    if (err != NOERR)
      error_box("Errore %d durante la scrittura della riga %d", err, nriga);
  }  
  
  // genera prospetto e1;    
  if (QuadroE1())  
  {                     
    TLocalisamfile prospe1(LF_PROSPE1);
    TRectype& rec = prospe1.curr();
    
    bool first = TRUE;
    for (char caus = 'C'; caus <= 'E'; caus++)
    {           
      const TRectype* riga = righe.prospetto_e1(caus);
      if (riga != NULL)
      {
        rec.put(PRE_CODDITTA, _codditta);
        rec.put(PRE_CODCAUS, caus);
        int err = prospe1.read();

        if (err != NOERR || first)
        {
          rec.put(PRE_CODDITTA, _codditta);
          rec.put(PRE_CODCAUS, caus);
          rec.zero(PRE_COMPENSO);
          rec.zero(PRE_IMPONIBILE);
          rec.zero(PRE_RITENUTA);
        }
        
        real val = rec.get_real(PRE_COMPENSO) + riga->get_real(PAG_COMPENSO) + riga->get_real(PAG_SPESA);
        rec.put(PRE_COMPENSO, val);
    
        val = rec.get_real(PRE_IMPONIBILE) + riga->get_real(PAG_IMPONIBILE);
        rec.put(PRE_IMPONIBILE, val);
    
        val = rec.get_real(PRE_RITENUTA) + riga->get_real(PAG_RITENUTA);
        rec.put(PRE_RITENUTA, val);
        
        if (err == NOERR)
          err = prospe1.rewrite();
        else
          err = prospe1.write();  
        
        if (err != NOERR)
          error_box("Errore %d durante la scrittura della riga %c del prospetto", 
                    err, caus);
      }
      
      first = FALSE;
    }
    read_prospetto_e1();
  }  
}

void TQuadroC_E2::generazione()
{                   
  TRelation rel(LF_SCPERC);
  rel.add(LF_RPAG, "CODDITTA=CODDITTA|TIPOA=TIPOA|CODANAGR=CODANAGR|NPROG=NPROG");
  rel.add("%CA7", "CODTAB=CODCAUS");

  TRectype rec(LF_SCPERC);
  rec.put(SPR_CODDITTA, _codditta);
  
  TCursor cur(&rel, NULL, 1, &rec, &rec);
  
  TString16 filter; filter.format("(%d->S1=\"%s\")", LF_TABCOM, (const char*)_quadronuovo);
  cur.setfilter(filter, TRUE);
  
  const int anno770 = anno_770();
  const long items = cur.items();                                            
  const TRectype& scheda = cur.curr();
  const TRectype& riga   = cur.curr(LF_RPAG);

  TProgind pi (items, "Generazionde da schede.", TRUE, TRUE, 60);
  
  distruzione();
  
  char last_type = ' ';
  long last_code = 0L;

  TRighe_pagamento righe(_quadro);

  for (cur = 0; cur.pos() < items; ++cur)
  {
    pi.addstatus(1);
    if (pi.iscancelled())
      break;
      
    const char tipoa = scheda.get_char(SPR_TIPOA);
    const long codanagr = scheda.get_long(SPR_CODANAGR);
    if (tipoa != last_type || codanagr != last_code)  
    {           
      if (righe.items() > 0)
      {
        genera_righe(righe);
        righe.destroy();
      }  
      last_type = tipoa;
      last_code = codanagr;
    }    
    
    bool ok = cur.is_first_match(LF_RPAG);
    while (ok)
    {          
      const TDate datapag = riga.get(PAG_DATAPAG);
      if (datapag.year() == anno770)
        righe.add_riga(scheda, riga);
      ok = cur.next_match(LF_RPAG);
    }
  }  
  
  if (righe.items() > 0)
    genera_righe(righe);
  _registra = TRUE;
}

bool TQuadroC_E2::codice_handler(TMask_field& f, KEY key)
{   
  bool ok = TRUE;
  if (key == K_TAB && f.to_check(key))
  {
    TEdit_field& e = f.mask().efield(H_CODANAGR);
    e.set(f.get());
    if (!e.check())
      return f.error_box(e.get_warning());
  }
  return TRUE;
}

bool TQuadroC_E2::genera_handler(TMask_field& f, KEY key)
{             
  if (key == K_SPACE)
  {
    if (yesno_box("Il quadro verr� completamente eliminato:\n"
                  "Confermare la generazione dalle schede"))
      app().generazione();
  }
  return TRUE;
}

bool TQuadroC_E2::prospbtn_handler(TMask_field& f, KEY key)
{
  if (key == K_SPACE)
  {
    if (app()._mskp->run() == K_ENTER)
      app().write_prospetto_e1();
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_c(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() || 
      key == K_ENTER && f.dlg() == 105)
  {
    TMask& m = f.mask();
    
    const real imponibile_v = m.get_real(105) - m.get_real(106) - m.get_real(107);
    real imponibile = m.get(108);
    if (imponibile.is_zero())
    { 
      imponibile = imponibile_v;
      m.set(108, imponibile_v);
    }
    else
    {
      if (key == K_ENTER && imponibile != imponibile_v)
        f.warning_box("L'imponibile dovrebbe essere %s", imponibile_v.string("."));
    }  
    
    const real imposta_v = m.get_real(102) * imponibile / 100.0;
    real imposta = m.get(109);
    if (imposta.is_zero())
    {                   
      imposta = imposta_v;
      m.set(109, imposta);
    }
    else
    {
      if (key == K_ENTER && imposta != imposta_v)
        f.warning_box("L'imposta dovrebbe essere %s", imposta_v.string("."));
    }       
      
    real totdet = m.get_real(110) + m.get_real(112);
    if (totdet > imposta) totdet = imposta;
    m.set(113, totdet);     

    const real ritenute_v = imposta - totdet;
    real ritenute = m.get(114);
    if (ritenute.is_zero())
    {                                   
      ritenute = ritenute_v;
      m.set(114, ritenute);
    }
    else  
      if (key == K_ENTER && ritenute != ritenute_v)
        f.warning_box("Le ritenute dovrebbero essere %s", ritenute_v.string("."));
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_d(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() ||
      key == K_ENTER && f.dlg() == 104)
  {
    TMask& m = f.mask();

    const real imponibile_v = m.get_real(104) - m.get_real(105) - m.get_real(106);
    real imponibile = m.get(107);
    if (imponibile.is_zero())
    {
      imponibile = imponibile_v;
      m.set(107, imponibile);
    }
    else
    {
      if (key == K_ENTER && imponibile != imponibile_v)
      {
        const TCurrency imponibile_c(imponibile_v);
        f.warning_box("L'imponibile dovrebbe essere %s", imponibile_c.string(TRUE));
      }
    }  
      
    const real imposta_v  = m.get_real(102) * imponibile / 100.0;
    real imposta = m.get(108);
    if (imposta.is_zero())
    {
      imposta = imposta_v;
      m.set(108, imposta);
    }
    else
    {
      if (key == K_ENTER && imposta != imposta_v)
      {
        const TCurrency imposta_c(imposta_v);
        f.warning_box("L'imposta dovrebbe essere %s", imposta_c.string(TRUE));
      }
    }       
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_dbis(TMask_field& f, KEY key)
{
  return ricalcola_imposte_d(f, key);
}

bool TQuadroC_E2::ricalcola_imposte_e(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() || key == K_ENTER && f.dlg() == 104)
  {
    TMask& m = f.mask();
    const real ritenuta_v = m.get_real(103) * m.get_real(104) / 100.0;
    real ritenuta = m.get(105);
    if (ritenuta.is_zero())
    {                   
      ritenuta = ritenuta_v;
      m.set(105, ritenuta);
    }
    else
    {
      if (key == K_ENTER && ritenuta != ritenuta_v)
        f.warning_box("L'imposta dovrebbe essere %s", ritenuta_v.string("."));
    }       
    
    const real somme_v = m.get_real(103) - ritenuta;
    real somme = m.get(106);
    if (somme.is_zero())
    {
      somme = somme_v;
      m.set(106, somme);
    }
    else
    {
      if (key == K_ENTER && somme != somme_v)
        f.warning_box("Il netto corrisposto dovrebbe essere %s", 
                      somme.string("."));
    }
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_e1(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() || key == K_ENTER && f.dlg() == 105)
  {
    TMask& m = f.mask();
    const real ritenuta_v = m.get_real(105) * m.get_real(106) / 100.0;
    real ritenuta = m.get(107);
    if (ritenuta.is_zero())
    {                   
      ritenuta = ritenuta_v;
      m.set(107, ritenuta);
    }
    else
    {
      if (key == K_ENTER && ritenuta != ritenuta_v)
        f.warning_box("L'imposta dovrebbe essere %s", ritenuta_v.string("."));
    }       
    
    const real somme_v = m.get_real(105) - ritenuta;
    real somme = m.get(108);
    if (somme.is_zero())
    {
      somme = somme_v;
      m.set(108, somme);
    }
    else
    {
      if (key == K_ENTER && somme != somme_v)
        f.warning_box("Il netto corrisposto dovrebbe essere %s", 
                      somme.string("."));
    }
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_e2(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() || key == K_ENTER && f.dlg() == 103)
  {
    TMask& m = f.mask();
    const real imposta_v = m.get_real(103) * m.get_real(104) / 100.0;
    real imposta = m.get(105);
    if (imposta.is_zero())
    {                   
      imposta = imposta_v;
      m.set(105, imposta);
    }
    else
    {
      if (key == K_ENTER && imposta != imposta_v)
        f.warning_box("L'imposta dovrebbe essere %s", imposta_v.string("."));
    }       
  }
  return TRUE;
}

bool TQuadroC_E2::ricalcola_imposte_la(TMask_field& f, KEY key)
{
  if (key == K_F8)
  {               
    f.reset();
    f.set_dirty();
    key = K_TAB;
  }

  if (key == K_TAB && f.focusdirty() ||
      key == K_ENTER && f.dlg() == 105)
  {
    TMask& m = f.mask();

    const real imponibile_v = m.get_real(105) - m.get_real(106) - m.get_real(107);
    real imponibile = m.get(108);
    if (imponibile.is_zero())
    {
      imponibile = imponibile_v;
      m.set(108, imponibile);
    }
    else
    {
      if (key == K_ENTER && imponibile != imponibile_v)
      {
        const TCurrency imponibile_c(imponibile_v);
        f.warning_box("L'imponibile dovrebbe essere %s", imponibile_c.string(TRUE));
      }
    }  
      
    const real imposta_v  = m.get_real(102) * imponibile / 100.0;
    real imposta = m.get(109);
    if (imposta.is_zero())
    {
      imposta = imposta_v;
      m.set(109, imposta);
    }
    else
    {
      if (key == K_ENTER && imposta != imposta_v)
      {
        const TCurrency imposta_c(imposta_v);
        f.warning_box("L'imposta dovrebbe essere %s", imposta_c.string(TRUE));
      }
    }       
  }
  return TRUE;
}

bool TQuadroC_E2::ritenute_handler_e2(TMask_field& f, KEY key)
{
  if (key == K_TAB && f.focusdirty() || key == K_ENTER)
  {
    TMask& m = f.mask();
    real imposta = m.get_real(103) * m.get_real(104) / 100.0;
    real imp     = f.get();
    if (imposta != imp)
      f.warning_box("Importo ritenuta non corretto");
  }
  return TRUE;
}


bool TQuadroC_E2::prospetto_e1_notify(TSheet_field& s, int r, KEY k)
{
  bool ok = TRUE;
  if (k == K_INS || k == K_DEL)
    ok = FALSE;
  return ok;
}

void TQuadroC_E2::read_prospetto_e1() const
{
  if (_mskp == NULL)
    return;
  TSheet_field& s = (TSheet_field&)_mskp->field(F_PROSPETTO);
  TLocalisamfile prosp(LF_PROSPE1);
  TRectype& curr = prosp.curr();
  curr.put("CODDITTA", _codditta);
  for (int r = 0; r < 3; r++)
  {
    TToken_string& row = s.row(r);
    row.cut(0);
    row << char('C'+r);
    curr.put("CODCAUS", char('C'+r));
    if (prosp.read() == NOERR)
    {
      row.add(curr.get("COMPENSO"));
      row.add(curr.get("IMPONIBILE"));
      row.add(curr.get("RITENUTA"));
    }
  }
}

int TQuadroC_E2::write_prospetto_e1() const
{  
  if (_mskp == NULL)
    return NOERR;
  int error = NOERR;
  TSheet_field& s = (TSheet_field&)_mskp->field(F_PROSPETTO);
  TLocalisamfile prosp(LF_PROSPE1);
  TRectype& curr = prosp.curr();
  for (int r = 0; r < 3; r++)
  { 
    TToken_string& row = s.row(r);
    real compenso   = row.get(1);
    real imponibile = row.get();
    real ritenuta   = row.get();
    bool empty = compenso.is_zero() && imponibile.is_zero() && ritenuta.is_zero();

    curr.put("CODDITTA", _codditta);
    curr.put("CODCAUS", char('C'+r));
    if (!empty)
    {           
      curr.put("COMPENSO", compenso);
      curr.put("IMPONIBILE", imponibile);
      curr.put("RITENUTA", ritenuta);
      int err = prosp.rewrite();
      if (err != NOERR)
        err = prosp.write();
      if (err != NOERR)
        error = err;
    }  
    else
      prosp.remove();
  }    
  
  return error;
}

int quadriC_E2(int argc, char* argv[])
{
  TString16 taitol;
  taitol << "Riepilogo ";
  const char* nome_quadro = argv[2];
  if (strnicmp(nome_quadro, "C", 1) == 0)    
    taitol << "C"; else
  if (strnicmp(nome_quadro, "DB", 2) == 0)
    taitol << "SG"; else
  if (strnicmp(nome_quadro, "D1", 2) == 0)
  {
    _quadronuovo = "SE";
    taitol << "SE";
  } else
  if (strnicmp(nome_quadro, "D", 1) == 0)    
  {
    _quadronuovo = "SC";
    taitol << "SC";
  } else         
  if (strnicmp(nome_quadro, "E1", 2) == 0)
  {
    _quadronuovo = "SG";
    taitol << "SG";
  } else
  if (strnicmp(nome_quadro, "E", 1) == 0)
  {
    _quadronuovo = "SF";
    taitol << "SF";
  }
  else 
  {                     
    _quadronuovo = nome_quadro;
    taitol << nome_quadro;
  }
    
  TQuadroC_E2 a(nome_quadro); 
  a.run(argc, argv, taitol);
  return TRUE;
}