// 771232.cpp - Quadri G
#include <relapp.h>
#include <msksheet.h>
#include <execp.h>
#include <defmask.h> 
#include <recarray.h>

#include "77lib.h"
#include "774200.h"
#include "771234a.h"   // 771234a.uml
#include "771232.h"
#include "quadrog.h"
#include "quadrogp.h"


// Aliquote prospetti 2  (I e II)
HIDDEN const char* aliq[] =
{
  "10",
  "10",
  "12.50",
  "15",
  "32.40",
  "NS",
  ""
};

#define DISTINTA_APP "771mod -6 4"

//771234b.uml
#define AMM_AZ    102
#define NUM_AZ    103
#define AMM_COMP  104

// 771234d.uml e 771234e.uml
#define UTILI1S   101
#define UTILI2S   102
#define ALIQUOTA  103
#define TITOLO    104
#define ROPE      105

HIDDEN  real __amm_az = ZERO;
HIDDEN  real __num_az = ZERO;  

class TQuadroG : public TRelation_application
{
  private:
    TRelation*        _rel;
    TMask*            _msk;
    long              _codditta;
    TRiporti          _rip;
    TString16         _quadro;
    TString80         _title;
    bool              _registra, _bUsatoDistinta;
    static bool     p1_notify(TSheet_field& s, int r, KEY k);
    static bool     p2_notify(TSheet_field& s, int r, KEY k);
    static bool     p3_notify(TSheet_field& s, int r, KEY k);
    static bool     calc_amm(TMask_field& f, KEY k);
    static bool     tit_hndlr(TMask_field& f, KEY k);
    static bool     calc_rit(TMask_field& f, KEY k);
    static bool     exec_distinta(TMask_field& f, KEY k);
    static void     update_totals(TSheet_field& f); 
    static bool     mainmsk_handler(TMask& m, KEY k);        
  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 TMask*  get_mask(int mode)       { return _msk; }
    virtual bool  changing_mask(int mode)  { return FALSE; }
    virtual void  init_query_mode (TMask&);
    virtual void  init_insert_mode (TMask&);
    void      read_prospetti_1();
    void      read_prospetti_2();
    void      read_prospetti();
    int       write_prospetti();
    int       remove_prospetti();
  public:                      
    const char*   taitol() { return (const char*)_title; }
    TMask&      main_mask() const { return (TMask&) *_msk; }
        
    TQuadroG(const char quadro='0');
    virtual ~TQuadroG() {};
};                    



TQuadroG::TQuadroG(const char quadro)
{
  _registra   = _bUsatoDistinta = FALSE;
  switch (quadro)
  {
    case '3':
      _quadro = "G";  
      _title  = "Quadro G";
      break;
    default:
      break;
  }
}

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

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

int TQuadroG::write(const TMask& m)
{
  int err = TRelation_application::write(m);
  _registra = err == NOERR;    
  if (_registra)
    err = write_prospetti();
  return err;
}

int TQuadroG::rewrite(const TMask& m)
{                         
  int err = TRelation_application::rewrite(m);
  _registra = err == NOERR;    
  if (_registra)
    err = write_prospetti();
  return err;
}

bool TQuadroG::remove()
{  
  _registra = TRelation_application::remove();
  remove_prospetti();
  return _registra;
}

void TQuadroG::read_prospetti_1()
{
  TRectype k(LF_QUAGP);
  TRecord_array ra(LF_QUAGP,"NPROG"); 
  TSheet_field& p1_I = (TSheet_field&)_msk->field(F_P1_I);
  TSheet_field& p1_II = (TSheet_field&)_msk->field(F_P1_II);

  // Prospetto 1 - I  Utili in denaro
  k.put(QGP_CODDITTA,_codditta);
  k.put(QGP_PROSPETTO,"1");
  k.put(QGP_SEZIONE,"1");
  ra.read(k);
  p1_I.destroy();
  if (ra.rows()>0)
  {
    const int items = ra.rows();
    for (int i = 0; i < items; i++)
    {
      const TRectype& r = ra.row(i+1);
      TToken_string& t = p1_I.row(i);
      t.add(r.get(QGP_DATADEL));
      t.add(r.get(QGP_UTILI1S));
      t.add(r.get(QGP_NUMQUOTE));
      t.add(r.get(QGP_UTILI2S));
    }
  }
  update_totals(p1_I);
  
  // Prospetto 1 - II  Utili in natura
  k.zero();
  k.put(QGP_CODDITTA,_codditta);
  k.put(QGP_PROSPETTO,"1");
  k.put(QGP_SEZIONE,"2");
  ra.read(k);
  p1_II.destroy();
  if (ra.rows()>0)
  {
    const int items = ra.rows();
    for (int i = 0; i < items; i++)
    {
      const TRectype& r = ra.row(i+1);
      TToken_string& t = p1_II.row(i);
      t.add(r.get(QGP_DESCRBENI));
      t.add(r.get(QGP_UTILI1S));
    }
  }
  update_totals(p1_II);
}

void TQuadroG::read_prospetti_2()
{
  TRectype k(LF_QUAGP);
  TRecord_array ra(LF_QUAGP,"NPROG"); 
  TSheet_field& p2_I = (TSheet_field&)_msk->field(F_P2_I);
  TSheet_field& p2_II = (TSheet_field&)_msk->field(F_P2_II);

  k.zero();
  k.put(QGP_CODDITTA,_codditta);
  k.put(QGP_PROSPETTO,"2");
  p2_I.destroy();
  p2_II.destroy();
  for (int h = 1; h<=2; h++)
  {
    k.put(QGP_SEZIONE,h == 1 ? "1" : "2");
    ra.read(k);
    TSheet_field& f = h == 1 ? p2_I : p2_II;
    if (ra.rows()>0)
    {
      const int items = ra.rows();
      for (int i = 0; i < items; i++)
      {
        const TRectype& r = ra.row(i+1);
        TToken_string& t = f.row(i);
        t.add(r.get(QGP_UTILI1S));
        t.add(r.get(QGP_UTILI2S));
        t.add(r.get(QGP_ALIQUOTA));
        t.add(r.get(QGP_TITOLO));
        t.add(r.get(QGP_ROPE));
        if (i < 6)
        {
          f.disable_cell(i,2);
          f.disable_cell(i,3);
          if (i == 5)
          {
            t.add("NS",2);
            f.disable_cell(i,4);
          }
        }
      }
    }
    else // Non vi sono righe di prospetto, aggiunge quelle standard
    {
      for (int i=0; ;i++)
      {
        if (aliq[i][0] == '\0')
          break;
        f.disable_cell(i,2);
        f.disable_cell(i,3);
        TToken_string& t = f.row(i);
        t.add("");t.add("");
        t.add(aliq[i]); 
        char c = ' ';
        if (aliq[i][0] == 'N')
          f.disable_cell(i,4);
        else
          c = i == 0 ? 'A' : 'I'; // L'acconto e'solo per la prima riga (aliquota 10%)
        t.add(c);
      }
    }
  }
}

void TQuadroG::read_prospetti()
{
  read_prospetti_1();
  // Prospetto 2 - I  Utili in denaro
  // Prospetto 2 - II  Utili in natura
  read_prospetti_2();
}

int TQuadroG::write_prospetti()
{
  int err = NOERR, i, j;
  TSheet_field& p1_I  = (TSheet_field&)_msk->field(F_P1_I);
  TSheet_field& p1_II = (TSheet_field&)_msk->field(F_P1_II);
  TSheet_field& p2_I  = (TSheet_field&)_msk->field(F_P2_I);
  TSheet_field& p2_II = (TSheet_field&)_msk->field(F_P2_II);
  TRectype k(LF_QUAGP);

  k.put(QGP_CODDITTA,_codditta);
  k.put(QGP_PROSPETTO,"1");
  k.put(QGP_SEZIONE,"1");
  TRecord_array ra(LF_QUAGP,"NPROG"); 
  ra.set_key((TRectype*)k.dup());
  
  int items = p1_I.items();
  // Prospetto 1 - I  Utili in denaro
  for (i = 0,j = 1; i < items; i++)
  {
    TToken_string& t = p1_I.row(i);
    if (!t.empty_items())
    {
      TRectype& r   = ra.row(j++,TRUE);
      r.put(QGP_DATADEL,t.get(0));
      r.put(QGP_UTILI1S,t.get(1));
      r.put(QGP_NUMQUOTE,t.get(2));
      r.put(QGP_UTILI2S,t.get(3));
    }
  }
  err = ra.rewrite();  // Esegue una write se i record non ci sono, cancella tutti i rimanenti
  if (err != NOERR) return err;
  
  // Prospetto 1 - II  Utili in natura
  items = p2_I.items();
  k.put(QGP_SEZIONE,"2");
  ra.destroy_rows();
  ra.set_key((TRectype*)k.dup());
  for (i = 0, j = 1; i < items; i++)
  {
    TToken_string& t = p1_II.row(i);
    if (!t.empty_items())
    {
      TRectype& r = ra.row(j++,TRUE);
      r.put(QGP_DESCRBENI,t.get(0));
      r.put(QGP_UTILI1S,t.get(1));
    }
  }
  err = ra.rewrite(); // Esegue una write se i record non ci sono, cancella tutti i rimanenti
  if (err != NOERR) return err;

  // Prospetto 2 - I  Utili in denaro
  // Prospetto 2 - II  Utili in natura
  const char* al;
  for (int h = 1; h<=2; h++)
  {
    TSheet_field& f = h == 1 ? p2_I : p2_II;
    items = f.items();
    k.put(QGP_PROSPETTO,"2");
    k.put(QGP_SEZIONE,h == 1  ? "1" : "2");
    ra.destroy_rows();
    ra.set_key((TRectype*)k.dup());
    for (i = 0, j = 1; i < items; i++)
    {
      TToken_string& t = f.row(i);
      if (!t.empty_items())
      {
        TRectype& r      = ra.row(j++,TRUE);
        r.put(QGP_UTILI1S,t.get(0));
        r.put(QGP_UTILI2S,t.get(1));
        al = t.get(2);
        if (al[0] != 'N')
          r.put(QGP_ALIQUOTA,al);
        r.put(QGP_TITOLO,t.get(3));
        r.put(QGP_ROPE,t.get(4));
      }
    }
    err = ra.rewrite(); // Esegue una write se i record non ci sono, cancella tutti i rimanenti
    if (err != NOERR) return err;
  }  
  return NOERR;
}

int TQuadroG::remove_prospetti()
{
  TRectype k(LF_QUAGP);
  TRecord_array ra(LF_QUAGP,"NPROG"); 
  k.put(QGP_CODDITTA,_codditta);
  k.put(QGP_PROSPETTO,"2");
  for (int h = 1; h<=2; h++)
  {
    k.put(QGP_SEZIONE,h == 1 ? "1" : "2");
    ra.read(k);
    ra.remove();
  }
  return NOERR;
}

void TQuadroG::init_insert_mode (TMask& m)
{
  read_prospetti_2(); // Read it void
}

void TQuadroG::init_query_mode (TMask& m)
{
  TString16 codditta;
  codditta << _codditta;
  TMask_field& f = m.field(F_CODDITTA);
  f.set(codditta);
  f.check();
  m.send_key(K_AUTO_ENTER,0);
}

void TQuadroG::update_totals(TSheet_field& f)
{
  int i = 0;
  TMask& m = f.mask();
  short dlg = f.dlg();
  switch (dlg)
  {
    case F_P1_I:
    {
      real tot_numq, tot_amm;
      tot_numq = tot_amm = ZERO;
      const int items = f.items();
      // Calcolo il totale
      for (i = 0;  i < items; i++)
      {
        TToken_string& r = f.row(i);
        real numq(r.get(2));
        real amm (r.get(3));     
        tot_numq += numq;
        tot_amm  += amm;
      } 
      // totali...
      m.set(F_P1_I_TOT1,tot_numq);
      m.set(F_P1_I_TOT2,tot_amm);
    }       
    break;
  case F_P1_II:
    {
      real tot_valult;
      const int items = f.items();
      // Calcolo il totale
      for (i = 0;  i < items; i++)
      {
        TToken_string& r = f.row(i);
        real val(r.get(1));
        tot_valult  += val;
      }
      // totali...
      m.set(F_P1_II_TOT,tot_valult);
    }       
    break;
  default:
    break;
  }
}

// Quadro G prospetto 1 - I
// Calcola amm_complessivo = num_quote * amm_azione
bool TQuadroG::calc_amm(TMask_field& f, KEY k)
{
  if (k == K_TAB)
  {                    
    TMask& m = f.mask();
    real amm_az(m.get(AMM_AZ));
    real rNumAz = m.get_real(NUM_AZ);
    bool ricalcola = FALSE;
    real amm_comp(m.get(AMM_COMP));
    ricalcola = ( (__amm_az != amm_az) || (__num_az != rNumAz) );
    if (!ricalcola && amm_comp != ZERO)
      return TRUE;   
      
    // Calcola e setta il valore
    real amm = ZERO;
    amm = amm_az * rNumAz;
    amm.trunc();
    m.set(AMM_COMP, amm.string());   
    // Setta i flag usati per il confronto successivo
    __amm_az = amm_az;
    __num_az = rNumAz;
  }
  return TRUE;
}

bool TQuadroG::calc_rit(TMask_field& f, KEY k)
{
  if (k == K_TAB && f.to_check(k))
  {
    TMask& m = f.mask();
    real r1(m.get(UTILI1S));
    real r2(m.get(UTILI2S));
    TString16 al(m.get(ALIQUOTA));
    
    if (al == "NS") return TRUE;
    if (real::is_real(al))
    {
      const real a1 = al;                
      if (a1 != 0.0 && m.field(ALIQUOTA).enabled())
      {
        al = real::ita2eng(a1.string(".2"));
        m.set(ALIQUOTA,al);
      }
      if (a1 >= 0.0 && a1 <= 100.0)
      {
        real res = ((r1 + r2) / 100.0 * a1);
        res.round();
        m.set(ROPE,res);
      }
      else 
        return f.error_box("Aliquota non valida.");
    }
    else 
      return f.error_box("Aliquota non valida.");
    
    if (f.dlg() == ALIQUOTA && al.empty() && (r1 != 0.0 || r2 != 0.0))
      return f.error_box("Il campo aliquota e' obbligatorio.");
  }
  if (k == K_ENTER && f.dlg() == ALIQUOTA)
  {
    TMask& m = f.mask();
      
    TSheet_field& s = *m.get_sheet();
    const int selected = s.selected();
    TToken_string& row = s.row(selected);
    bool ok;
      
    if (selected > 5 && !row.empty_items())
    {
      const real aliquota = f.get();
      const char titolo = m.get(TITOLO)[0];
      for (int i = 0; i < s.items(); i++) if (i != selected)
      { 
        const real aliq = s.row(i).get(2);
        const char tit = m.get(TITOLO)[0];
        if (aliquota == aliq && titolo == tit)
        {
          ok = f.yesno_box("L'aliquota %s%%(%s) e' gia' stata utilizzata al rigo %d.\n"
                           "Si desidera sommare gli importi nello stesso rigo?", 
                           (const char*) aliq.string(".2"), titolo == 'I' ? "Imposta" : "Acconto", i+1);
          if (ok)
          { 
            // Forza aggiornamento riga corrente dello sheet con la maschera
            row.cut(0);                        
            for (short id = UTILI1S; id <= ROPE; id++)
              row.add(m.get(id));
              
            // Sceglie come destinazione la riga piu' in alto
            int src = selected, dst = i;
            if (src < dst)
            { int tmp = src; src = dst; dst = tmp; }
              
            // Righe conivolte nella somma  
            TToken_string& srcrow = s.row(src);
            TToken_string& dstrow = s.row(dst);
                
            for (int x = 0; x < 5; x++) if (x < 2 || x > 3)
            {
              real tot = dstrow.get(x);
              if (x < 2 || dst != 2)
              {
                tot += real(srcrow.get(x)); 
                dstrow.add(tot.string(), x);
              }
              if (dst == selected)
                m.set(UTILI1S+x, tot);
              else
                m.reset(UTILI1S+x);
            }
            if (src == selected)
            {
              m.reset(ALIQUOTA);
              m.set(TITOLO, " ");
              s.force_update(dst);
            }  
            else
            {
              srcrow.cut(0); 
              s.force_update(src);
            }  
          }
          break;
        }
      }
    }  
  }
  return TRUE;
}

bool TQuadroG::tit_hndlr(TMask_field& f, KEY k)
{
  if (f.to_check(k))
  {
    TMask& m = f.mask();
    real r1(m.get(UTILI1S));
    real r2(m.get(UTILI2S));
    TString16 tit(f.get());

    if (tit.empty() && (r1 != 0.0 || r2 != 0.0))
      return f.error_box("Il campo titolo e' obbligatorio.");
  }
  return TRUE;
}

bool TQuadroG::exec_distinta(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TExternal_app zzz(DISTINTA_APP);
    zzz.run();
    f.set_focus();
    // Fai il ricalcolo    
    app()._bUsatoDistinta = TRUE;
  }
  return TRUE;
}

bool TQuadroG::user_create() 
{
  _msk = new TMask("771234a");
  _rel = new TRelation(LF_QUAG);
  _rel->add(LF_QUAGP,"CODDITTA=CODDITTA");
  _codditta = get_firm_770();  
  _msk->disable(DLG_CANCEL);   // disabilito Annulla nella toolbar
  _msk->disable(DLG_NEWREC);   // disabilito Nuovo   nella toolbar
  _msk->disable(DLG_DELREC);   // disabilito Elimina nella toolbar
  _msk->disable(DLG_FINDREC);  // disabilito Ricerca nella toolbar
  _msk->set_handler(DLG_DISTINTA, exec_distinta);  
  _msk->set_handler(mainmsk_handler);
  TSheet_field& p1_I = (TSheet_field&) _msk->field(F_P1_I);  
  p1_I.set_append(FALSE);
  p1_I.set_notify(p1_notify);                          
  p1_I.sheet_mask().set_handler(NUM_AZ, calc_amm);
  p1_I.sheet_mask().set_handler(AMM_AZ, calc_amm);  
  TSheet_field& p1_II = (TSheet_field&) _msk->field(F_P1_II);  
  p1_II.set_notify(p2_notify);                              
  p1_II.set_append(FALSE);
  TSheet_field& p2_I = (TSheet_field&) _msk->field(F_P2_I);  
  p2_I.sheet_mask().set_handler(UTILI1S, calc_rit);  
  p2_I.sheet_mask().set_handler(UTILI2S, calc_rit);  
  p2_I.sheet_mask().set_handler(ALIQUOTA, calc_rit);  
  p2_I.sheet_mask().set_handler(TITOLO, tit_hndlr);  
  p2_I.set_notify(p3_notify);                              
  TSheet_field& p2_II = (TSheet_field&) _msk->field(F_P2_II);  
  p2_II.sheet_mask().set_handler(UTILI1S, calc_rit);  
  p2_II.sheet_mask().set_handler(UTILI2S, calc_rit);  
  p2_II.sheet_mask().set_handler(ALIQUOTA, calc_rit);  
  p2_II.sheet_mask().set_handler(TITOLO, tit_hndlr);  
  p2_II.set_notify(p3_notify);                              
  return TRUE;
}

bool TQuadroG::user_destroy() 
{
  delete _rel; delete _msk;  
  if (_registra || _bUsatoDistinta)
    _rip.set(_quadro);  
  return TRUE;
}

bool TQuadroG::p1_notify(TSheet_field& s, int r, KEY k)
{
  switch(k)
  {                               
    case K_ENTER:
      __amm_az = ZERO;
      __num_az = ZERO;
      update_totals(s);    
      break;
    case K_SPACE: 
      {
      TToken_string& row = s.row(r);
      __num_az  = row.get(3);
      __amm_az  = row.get(4);
      }
      break;
    default:
      break;
  }
  return TRUE;
}

bool TQuadroG::p2_notify(TSheet_field& s, int r, KEY k)
{
  switch(k)
  {                               
    case K_ENTER:
      update_totals(s);
      break;
    default:
      break;
  }
  return TRUE;
}

bool TQuadroG::p3_notify(TSheet_field& s, int r, KEY k)
{
  if  (k == K_DEL)
   if (r > 8) 
     return TRUE;
   else
     return FALSE;
  return TRUE;
}

bool TQuadroG::mainmsk_handler(TMask& m, KEY k)
{ 
  if (k == K_ESC)
  {
    TOperable_field& f = m.focus_field();
    m.set_focus_field(f.dlg()); 
  } 
  return TRUE;
}

bool quadro_g(int argc, char* argv[])
{
  TQuadroG a('3');
  a.run(argc,argv,a.taitol());
  return TRUE;
}