// quadb_b1.cpp
#include <relapp.h>
#include <urldefid.h>

#include "dipend.h"
#include "774200.h"
#include "77lib.h"   
#include "quadrob.h"
#include "quadrob1.h"
#include "77qb.h"
#include "77qb1.h"

class TQuadriBB1_application : public TRelation_application
{
    static bool codditta77_handler (TMask_field& m, KEY k);
    static bool PrimoNprogLibero   (TMask& m, const long codditta, const long coddip);
    static bool CodDipHandler      (TMask_field& m, KEY k);
    static bool NprogExitHandler   (TMask_field& m, KEY k);
    static bool QBTotRedImpHandler (TMask_field& f, KEY k);
    static bool QBAmmRopeHandler   (TMask_field& f, KEY k);
    static bool QBTotIndennHandler (TMask_field& f, KEY k);
    static bool QBCalcola37 			 (TMask_field& f, KEY k);
    static void BB1SettaCognomeNome(TMask& m);
    const char*   _maskname;
    int           _num;
    int			_pos_quadro;  // posizione nell'array dei quadri. Usato in set_comp
    TString16     _quadro;
    TRiporti      _rip;
    TRelation*    _rel;
    TMask*        _msk[2];
    bool          _registra;
    int			_anno_dic;
    int              _mode;    
    bool			_MaskConAnnoDic, _MaskConCodditta;
    bool			MaskConAnnoDic() const;
    bool			MaskConCodditta() const { return _MaskConCodditta; }
    bool			QuadroB()  const { return _num == LF_QUAB;  }
    bool			QuadroB1() const { return _num == LF_QUAB1; }
    bool 			CheckImporti(const TMask& m);            
    bool 			EsisteGiaCodDip(const TMask& m);
    bool 			EsisteGiaRecordDip(const TMask& m);
    long			_codditta;              
    long			_lCodDip;  
    int				_iNprog;
    TString			_sCognome, _sNome;
    void 			init_mask(TMask&);  

  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 void on_config_change();
    virtual TMask* get_mask(int);
    virtual bool changing_mask(int);           
    TMask*  load_mask(int n);
    virtual TRelation* get_relation() const { return _rel; }  
    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&);

  public:                                                                     
    TQuadriBB1_application(const char* name, const int num, const char* quadro);
};

TQuadriBB1_application::TQuadriBB1_application(const char* name, const int num, const char* quadro)
: _maskname(name), _num(num), _mode(0),
  _MaskConCodditta(FALSE), _MaskConAnnoDic(FALSE),
  _rel(NULL), _quadro(quadro) 
{
  memset(_msk, 0, sizeof(_msk));  
  switch (_num)
  {
    case LF_QUAB:
      _pos_quadro = B;
      break;
    case LF_QUAB1:
      _pos_quadro = B1;
      break;
  }
}

TQuadriBB1_application& app() { return (TQuadriBB1_application&)main_app(); }

bool TQuadriBB1_application::changing_mask(int mode)
{
  if ((mode == MODE_MOD) && (_mode == MODE_INS))
	return FALSE; 
 else	              
  return _mode != mode;
}
        
TMask* TQuadriBB1_application::get_mask(int mode)
{
  const int m = (mode == MODE_QUERY) ? 0 : 1;
  _mode = mode;
  return load_mask(m);
}

TMask* TQuadriBB1_application::load_mask(int n)
{
  if (_msk[n] != NULL) 
    return _msk[n]; 
    
  TFilename name("77qb"); 
  
  if (n == 0) 
  { 
    switch (_num) 
    {
      case LF_QUAB:       
        name << 'a';  
        break; 
      case LF_QUAB1:      
        name << "1a";  
        break;
      default:
        break;
    }
  }
  else 
  {
    switch (_num)
    {
      case LF_QUAB:       
        name << 'b';
        break;
      case LF_QUAB1:      
        name << "1b";
        break;
      default:
        break;
    }
  }  
  
  TMask* m = new TMask(name);
  m->set_handler(CODDITTA77,   codditta77_handler);  

  switch (n)
  {                                   
    case 0:           
      if (QuadroB())                                    
      {
        m->set_handler(QBF_CODDIP_QB,   CodDipHandler);    
        m->set_handler(QBF_CODDIP_ANAG,   CodDipHandler);    
        set_search_field(QBF_NPROG);
      }                               
      else
      {
        m->set_handler(QB1F_CODDIP_QB1,  CodDipHandler);    
        m->set_handler(QB1F_CODDIP_ANAG,  CodDipHandler);        
        set_search_field(QB1F_NPROG);  
      }
      m->set_handler(QuadroB() ? QBF_NPROG : QB1F_NPROG,   NprogExitHandler);    
      break;
    case 1:                                 
      if (m)
        if (QuadroB())
        {           
          m->set_handler(QBF_TOTIMP, QBTotRedImpHandler);
          m->set_handler(QBF_ROPE,   QBAmmRopeHandler);
          m->set_handler(QBF_AMMNETTO,  QBTotIndennHandler);
          m->set_handler(QBF_AMMNETTO2, QBTotIndennHandler);    
          m->set_handler(QBF_CONTLAV,   QBTotIndennHandler);    
          m->set_handler(QBF_TFR7494,   QBTotIndennHandler);    
          m->set_handler(QBF_INDEN7494, QBTotIndennHandler); 
          m->set_handler(QBF_TIND7494, 	QBCalcola37);  // 28
          m->set_handler(QBF_TRID, 			QBCalcola37);  // 29
        }                                       
        m->disable(DLG_FINDREC);
      break;
    default:
      break;  
  }        
  return _msk[n] = m;
}

bool TQuadriBB1_application::QBCalcola37(TMask_field& f, KEY k)
{
  TMask& m=f.mask();
  if (k==K_TAB && m.is_running())
  {       
    real c28=m.get_real(QBF_TIND7494);
    real c29=m.get_real(QBF_TRID);
    real c37 = c28 - c29;
    if (c37 < ZERO)
      c37 = ZERO;
    TString c37s(c37.string());
    m.set(QBF_TOTIMP,c37s);
  }
  return TRUE;
}

bool TQuadriBB1_application::MaskConAnnoDic() const
{
  return  _MaskConAnnoDic;
}

void TQuadriBB1_application::on_config_change()
{
  TConfig conf(CONFIG_STUDIO);
  _anno_dic = (int)conf.get_long(ANNO_SEL, NULL, -1, TDate(TODAY).year());
}
                                    
bool TQuadriBB1_application::user_create()
{           
  _registra = FALSE;
  _rel      = new TRelation(_num);
  _codditta = get_firm_770();
  return TRUE;
}

bool TQuadriBB1_application::user_destroy()
{  
  if (_quadro != "")
    if (_registra)
      _rip.set(_quadro);
  if (_msk[1] != NULL) delete _msk[1];
  if (_msk[0] != NULL) delete _msk[0];
  delete _rel;
  return TRUE;
}                         

// Q.B. Controlla che ci sia diverso da ZERO il tot.red.imp.
bool TQuadriBB1_application::CheckImporti(const TMask& m)
{
  real TotRedImp(m.get(QBF_TOTIMP));  
  return TotRedImp != ZERO;
}

// Controlla se esiste gia' un record con lo stesso cod.dip.
bool TQuadriBB1_application::EsisteGiaCodDip(const TMask& m)
{
  TLocalisamfile q(_num);
  const long codip = m.get_long(QuadroB()? QBF_CODDIP : QB1F_CODDIP);
  q.zero();
  q.put(QB_CODDITTA, _codditta);   
  q.put(QB_CODDIP,   codip);
  TRectype dep(q.curr());
  q.read(_isgteq);                      
  const bool bEq = q.curr() == dep;
  return bEq;
}

// Controlla se esiste gia' una chiave completa
bool TQuadriBB1_application::EsisteGiaRecordDip(const TMask& m)
{
  TLocalisamfile q(_num);               
  const long codip = m.get_long(QuadroB()? QBF_CODDIP : QB1F_CODDIP);
  const long nprog = m.get_long(QuadroB()? QBF_NPROG  : QB1F_NPROG);
  q.zero();
  q.put(QB_CODDITTA, _codditta);   
  q.put(QB_CODDIP,   codip);               
  q.put(QB_NPROG,    nprog);
  TRectype dep(q.curr());
  const bool bEq = q.read() == NOERR;
  return bEq;
}

int TQuadriBB1_application::rewrite(const TMask& m)
{
  m.autosave(*_rel);
  const int err = _rel->rewrite();      
  _registra = err == NOERR;
  return err;
}

/*
int TQuadriBB1_application::read(TMask& m)
{
  int err;
  _rel->lfile().put("CODDITTA", (long)_codditta);
  _rel->lfile().put("CODDIP",   (long)_lCodDip);
  _rel->lfile().put("NPROG",    _iNprog);
  err = _rel->read();
  return err;
}  
*/

int TQuadriBB1_application::write(const TMask& m)
{
  m.autosave(*_rel);
  if (QuadroB1())
    if (EsisteGiaRecordDip(m))
      return warning_box("E' gi� presente un record per questo dipendente");
  const int err = _rel->write();
  _registra = err == NOERR;
  return err;
}

bool TQuadriBB1_application::remove()
{
  _registra = TRUE;
  return TRelation_application::remove();
}

void TQuadriBB1_application::init_mask(TMask& m)
{
  if (QuadroB())
  {                                
// leggi dalla maschera di query, che' dovrebbero li' esservi sempre..  
    const long codditta = _msk[0]->get_long(QBF_CODDITTA);
    const long codip    = _msk[0]->get_long(QBF_CODDIP);
    if (codip==0L)
      return;
    if (is_erede(codditta,codip)) // && modifica(m))
    {
      m.disable(-GROUP_ALL);    
      m.enable(-GROUP_EREDE);   
    }
    else
    {
      m.enable(-GROUP_ALL);   
      if (is_deceduto(codditta,codip) || is_dipendente(codditta,codip))
        m.disable(-GROUP_DIPDEC);
      else
        m.enable(-GROUP_DIPDEC);
    }
  }
}

void TQuadriBB1_application::init_modify_mode(TMask& m)
{
  init_mask(m);                     
/*  
  if (QuadroB())
  {
    m.set(QBF_CODDIP,  	_lCodDip);
    m.set(QBF_COGNOME, 	_sCognome);
    m.set(QBF_NOME,		_sNome);
    m.set(QBF_NPROG,	_iNprog);
  }
  else
  {
    m.set(QB1F_CODDIP,  	_lCodDip);
    m.set(QB1F_COGNOME, 	_sCognome);
    m.set(QB1F_NOME,		_sNome);
    m.set(QB1F_NPROG,		_iNprog);
  }*/
}

void TQuadriBB1_application::init_insert_mode(TMask& m)
{
  init_mask(m);
}

void TQuadriBB1_application::init_query_mode(TMask& m)
{                   
  m.set(ANNODIC77, _anno_dic);               
  if (QuadroB())
  {
    m.show(-QBG_QUADROB);
    m.hide(-QBG_ANADIP);
  }
  else
  {
    m.show(-QB1G_QUADROB);
    m.hide(-QB1G_ANADIP);
  }  
}

void TQuadriBB1_application::init_query_insert_mode(TMask& m)
{                                            
  m.set(ANNODIC77, _anno_dic);               
  if (QuadroB())
  {    
    m.hide(-QBG_QUADROB);
    m.show(-QBG_ANADIP);
  } 
  else
  {
    m.hide(-QB1G_QUADROB);
    m.show(-QB1G_ANADIP);
  }
}

bool TQuadriBB1_application::codditta77_handler(TMask_field& f, KEY k)
{
  if (k == K_TAB)
  {
	  TMask& m = f.mask();
	  TString16 codditta; codditta << app()._codditta;
	  if (codditta != "0")        
	  {
	    m.set(CODDITTA77, codditta);
	    m.field(CODDITTA77).check();
	  }
  }
  return TRUE;
}


///////////////////////////////////////////////////////////
// 2 modi :
//  RUN,773,-1,771230m,89,"Prospetto del Quadro E1","E1"    [771230i.uml]
// oppure
//  773 -1 menu_st "Stampe dichiarazioni" [prassi.mnu]
// QUADRO N:
// 773,-2,77qn,72,"Quadro N","N"
///////////////////////////////////////////////////////////
int quadriB_B1(int argc, char* argv[])
{
  TFilename mask;
  int num = 0;
  if (argc > 1) 
    mask = argv[2];
  num    = atoi(argv[3]);
  const char* title  = argv[4];             
  const char* quadro = argv[5];
  TQuadriBB1_application a(mask, num, quadro);
  a.run(argc, argv, title ? title : "Test Relation Application");
  return 0;
}

//
// CodDipHandler
// 
//   1 - Controlla che il codice dipendente esista
//   2 - Propone il primo progressivo disponibile per quel codice
//
bool TQuadriBB1_application::CodDipHandler(TMask_field& f, KEY k)
{
  TMask& m = f.mask();             
  if (!m.is_running()) return TRUE;  

  if (k == K_ENTER)
  {                                           
    const long codip = atol(f.get());
    if (codip==0L) 
      return TRUE;

    if (!esiste_dipendente(app()._codditta, codip))
      return f.warning_box("Dipendente inesistente");
  }
  
  if (k == K_TAB)
  {                                           
    const long codip = atol(f.get());
    if (codip==0L) 
      return TRUE;

    if (!esiste_dipendente(app()._codditta, codip))
      return f.warning_box("Dipendente inesistente");

    PrimoNprogLibero(m, app()._codditta, codip);
  }       
  return TRUE;
}

// Compila cognome e nome se vuoti
void TQuadriBB1_application::BB1SettaCognomeNome(TMask& m)
{
  const int iDlgCognome = app().QuadroB() ? QBF_COGNOME : QB1F_COGNOME;
  const int iDlgNome    = app().QuadroB() ? QBF_NOME    : QB1F_NOME;
  const int iDlgNProg   = app().QuadroB() ? QBF_NPROG   : QB1F_NPROG;
  const int iProg  = m.get_int(iDlgNProg);
  TString sCognome(m.get(iDlgCognome));
  TString sNome;
  if (app()._lCodDip != 0L) 
  {
    TLocalisamfile dip (LF_DIPEND);
    dip.zero();
    dip.put(DIP_CODDITTA, app()._codditta);
    dip.put(DIP_CODIP,    app()._lCodDip);
    if (dip.read() == NOERR)
    {
      sCognome = dip.get("COGNOME");
      sNome    = dip.get("NOME");    
      app()._sCognome = sCognome;
      app()._sNome    = sNome;
      app()._iNprog   = iProg;
      m.set(iDlgCognome, sCognome);
      m.set(iDlgNome,    sNome);
    }
  }  
}

bool TQuadriBB1_application::NprogExitHandler(TMask_field& f, KEY k)
{
  TMask& m = f.mask();
  if (!m.is_running()) return TRUE;

  if (k == K_CTRL+K_TAB)
  {
    f.set_dirty();
    return TRUE;
  }
    
  if (k == K_TAB)
  {
    TString nprog(f.get());
    if (nprog.not_empty())
    {
      const int ID_CODDIP = app().QuadroB()? QBF_CODDIP : QB1F_CODDIP;
      const long codip    = app()._lCodDip = m.get_long(ID_CODDIP);
      const long codditta = app()._codditta;
//      const long codip    = m.get_long(ID_CODDIP);
//      const long codditta = app()._codditta;

      if (codip==0L) 
        return TRUE;

// Nel B1 e nel B (per gli eredi) pu� esserci un solo record per dipendente
      if (app().QuadroB1() || (app().QuadroB() && is_erede(codditta,codip)) )
// Se esiste gia' un record per questo dipendente MA NON la chiave completa
// (ora presente nella maschera) rifiuta il record
// (impedisce cioe' di andare in inserimento, a meno che non sia la prima
//  volta, cioe' a meno che non esista ancora nessun record per il dip.
//  (questo caso e' segnalato dal fallimento della EsisteGiaCodDip) )
        if (app().EsisteGiaCodDip(m) && !app().EsisteGiaRecordDip(m))  
          return f.warning_box("Esiste gi� una riga per questo dipendente");    

// Compila cognome e nome se vuoti
      BB1SettaCognomeNome(m);
//      m.stop_run(K_AUTO_ENTER);
    }
  }
  return TRUE;
}

bool TQuadriBB1_application::PrimoNprogLibero(TMask& m, const long codditta, const long codip)
{
// Propone il primo numero disponibile
  if (codip != 0L)
  {
    long nprog = 0L;              
    const int id_nprog = app().QuadroB() ? QBF_NPROG : QB1F_NPROG;
    const bool erede   = is_erede(codditta,codip);
    bool EsisteGiaDip  = FALSE;
    TLocalisamfile qb(app()._num);
    qb.zero();
    qb.put(QB_CODDITTA, codditta);
    qb.put(QB_CODDIP,   codip);
    TRectype dep(qb.curr());       
    qb.read(_isgteq);
    TRecnotype lPosPrec = qb.recno();
    for ( ; !qb.eof(); qb.next())
    {
      if (qb.curr() > dep) break;
      EsisteGiaDip = TRUE;
      nprog = qb.get_long(QB_NPROG);
    }
    qb.readat(lPosPrec);    
    
// Nel B se e' un erede si puo' solo andare in modifica
// Nel B1 � consentito un solo record per dipendente
    if ( (nprog == 0) || (app().QuadroB1() && !EsisteGiaDip) ||
                         (app().QuadroB()  && !erede) )
      nprog++;

    TString16 nprog_str; nprog_str << nprog;
    m.set(id_nprog, nprog_str);
  }
  return TRUE;                   
}                         

///////////////////////////////////////////////////////////////////////////////////
// QUADRO B
///////////////////////////////////////////////////////////////////////////////////
bool TQuadriBB1_application::QBTotRedImpHandler(TMask_field& f, KEY k)             
{
  TMask& m = f.mask();
  if (k == K_ENTER && !ricerca(m))
  {
    const long codditta = m.get_long(QBF_CODDITTA);
    const long codip    = m.get_long(QBF_CODDIP);
    if (!is_erede(codditta,codip))
    {
      real totimp(f.get());
      if (totimp == ZERO)
        return f.warning_box("Il totale reddito imponibile non pu� essere nullo");
    }
  }
  return TRUE;
}

bool TQuadriBB1_application::QBAmmRopeHandler(TMask_field& f, KEY k)             
{
  TMask& m = f.mask();  
  if (k == K_ENTER && !ricerca(m))
  {
    TMask& m = f.mask();
    const long codditta = m.get_long(QBF_CODDITTA);
    const long codip    = m.get_long(QBF_CODDIP);
    if (!is_erede(codditta,codip))
    {
      real totimp(m.get(QBF_TOTIMP));
      real rope(f.get());            
      if (rope > totimp)
        return f.warning_box("Il totale ritenute non pu� essere maggiore del totale reddito imponibile");
    }
  }
  return TRUE;
}

// 23.5.96 Calcola totale indennit�
bool TQuadriBB1_application::QBTotIndennHandler(TMask_field& f, KEY k)             
{
  if (k == K_TAB)
  {
    const bool ricalcola = f.focusdirty();
    if (ricalcola)
    {
      TMask& m = f.mask();                             
      real c20 = m.get_real(QBF_AMMNETTO);
      real c24 = m.get_real(QBF_AMMNETTO2);
      real c25 = m.get_real(QBF_CONTLAV);
      real c26 = m.get_real(QBF_TFR7494);
      real c27 = m.get_real(QBF_INDEN7494);
      
      real c28 = c20 + c24 - c25 + c26 + c27;
      if (c28 < ZERO)
        c28 = ZERO;
      TString c28s(c28.string());
      m.set(QBF_TIND7494, c28s);         
// Ricalcola il 37 da qui perche' il 28 e' disabilitato
      QBCalcola37(f,k);
    }
  }
  return TRUE;
}