// ba3700.cpp  - Tabella condizioni di pagamento

#include <relapp.h>       
#include <tabutil.h>
#include <msksheet.h>

#include "ba3700.h"
#include "../cg/pagament.h"

#define ALIAS 1

class BA3700_application : public TRelation_application
{   
  TRelation*   _rel;
  TMask*       _msk;
  TPagamento*   _pag;
  TSheet_field* _cs;
  int          _mode;              // Modo maschera corrente
  int          _interv_rate; 
  int          _numero_rate;
  int          _riga;

protected:

  virtual bool         user_create();
  virtual bool         user_destroy();
  
  // minchia di cristo
  virtual TRelation*   get_relation() const    { return _rel;  }
  virtual TMask*       get_mask(int mode)      { return _msk;  }
  virtual bool         changing_mask(int mode) { return FALSE; }

  // file intertface
  virtual bool         remove();
  virtual void         init_insert_mode(TMask&);
  virtual void         init_query_mode(TMask&);
  virtual int          rewrite(const TMask& m);
  virtual int          write(const TMask& m);
  virtual int          read(TMask& m);

  // notifier
  static bool          sheet_action(TSheet_field&, int r, KEY k);
  
  // handlers           
  static bool intervallo_rate     (TMask_field& f, KEY k);                  
  static bool rate_differenziate  (TMask_field& f, KEY k);                  
  static bool tipo_prima_rata     (TMask_field& f, KEY k);                  
  static bool numero_rate         (TMask_field& f, KEY k);                  
  static bool mese_commerciale    (TMask_field& f, KEY k);                  
  static bool fixed_scad          (TMask_field& f, KEY k);                  
  static bool tipo_rata           (TMask_field& f, KEY k);                  
  static bool ult_class           (TMask_field& f, KEY k);                  
  
  void*  _app_data;  
  
public:
  
  void   set_app_data(void* v) { _app_data = v;    }                
  static void* get_app_data()  { return ((BA3700_application &)main_app())._app_data; }
  
  BA3700_application() : TRelation_application() {} 
  virtual ~BA3700_application() {}
};

// app-data per handlers          
struct sht {
  TMask*        _msk;
  TPagamento*    _pag;
  TSheet_field* _sht;
  TArray*       _rws;
} shuttle;    

bool BA3700_application::user_create()
{
  _rel = new TRelation(TAB_CPG);
  _rel->add(TAB_RPG, "CODTAB[1,4]=CODTAB" ,1, 0, ALIAS);

  _interv_rate = 30;
  _pag = NULL;
  _msk = new TMask("ba3700a");
  _cs = &((TSheet_field&)_msk->field(F_SHEET_RPG));
  _cs->set_notify(sheet_action);
  
  _msk->set_handler (F_INT_RATE        , intervallo_rate);        
  _msk->set_handler (F_RATE_DIFF       , rate_differenziate);     
  _msk->set_handler (F_TIPO_PRIMA_RATA , tipo_prima_rata);        
  _msk->set_handler (F_NUM_RATE        , numero_rate);            
  _msk->set_handler (F_MESECOMM        , mese_commerciale);       
  _msk->set_handler (F_FIXSCAD_1       , fixed_scad);        
  _msk->set_handler (F_FIXSCAD_2       , fixed_scad);        
  _msk->set_handler (F_FIXSCAD_3       , fixed_scad);        
  _msk->set_handler (F_TIPO_RATA       , tipo_rata);        
  _msk->set_handler (F_ULT_CLASS       , ult_class);        
  
  shuttle._msk = _msk;
  shuttle._sht = _cs;
  
  set_app_data(&shuttle);
  
  return TRUE;
}

bool BA3700_application::user_destroy()
{
  delete _msk;
  delete _rel;
  if (_pag) delete _pag;
  return TRUE;
}

int BA3700_application::read(TMask& m)
{
  m.autoload(_rel);

  TString code(m.get(F_CODICE));
  int ir = m.get_int(F_INT_RATE); if (ir == 0) ir = -1;
  if (_pag != NULL) delete _pag;
  shuttle._pag = _pag = new TPagamento(code);
  _pag->set_sheet(*_cs, ir);
  if (_pag->n_rate() > 1)
    _interv_rate = _pag->scad_rata(_pag->n_rate() - 1);
  else _interv_rate = 30;
  
  TArray* arr = new TArray;
  if (shuttle._rws != NULL) delete shuttle._rws;
  (*arr) = _cs->rows_array();
  shuttle._rws = arr;  
  
  shuttle._msk->set(F_INT_RATE,_interv_rate);
  shuttle._msk->set(F_NUM_RATE,_pag->n_rate());
  shuttle._msk->set(F_RATE_DIFF, _pag->rate_differenziate() ? "1" : "2", TRUE);
  
  return NOERR;
}

void BA3700_application::init_insert_mode(TMask& m)
{
  TString code(m.get(F_CODICE));
  shuttle._pag = _pag = new TPagamento(code);
  _pag->set_sheet(*_cs);
  TArray* arr = new TArray;
  if (shuttle._rws != NULL) delete shuttle._rws;
  (*arr) = _cs->rows_array();
  shuttle._rws = arr;       
  shuttle._msk->field(F_INT_RATE).set("30");
  shuttle._msk->field(F_INIZIOSCAD).set("F");
  shuttle._msk->field(F_NUM_RATE).set("1"); 
  shuttle._msk->set(F_RATE_DIFF, "2", TRUE);
}

void BA3700_application::init_query_mode(TMask& m)
{
  _cs->reset(); _cs->force_update();
  if (shuttle._rws != NULL) delete shuttle._rws;
  shuttle._rws = new TArray;
}

// handlers

bool BA3700_application::intervallo_rate(TMask_field& f, KEY k)
{          
  // ricalcola tutte le scadenze
  // occorre pag->set_intervallo_rate(intervallo)       
  if (k != K_TAB || f.mask().query_mode() || !f.focusdirty()) return TRUE;
  
  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk;
  
  if (!pag || msk->get(F_INT_RATE).empty()) return TRUE;

  pag->set_intervallo_rate(msk->get_int(F_INT_RATE));
                                                 
  if (pag->dirty())
  {
    pag->set_sheet(*shf);  
    (*(s->_rws)) = shf->rows_array(); 
    msk->field(F_MESECOMM).set(pag->mese_commerciale() ? "X" : "");
  }  
  else 
  {
    char r[8]; 
    sprintf(r, "%d", pag->intervallo_rate());
    f.set(r);
  }  
  
  return TRUE;
}

bool BA3700_application::rate_differenziate(TMask_field& f, KEY k)                  
{
  // se erano differenziate e non lo sono piu' occorre riaggiustare
  // il riaggiustabile; altrimenti si lascia cosi'
  // pag->set_rate_differenziate() 
  if (k != K_TAB || f.mask().query_mode()) return TRUE;

  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk;
  TArray*       rws = s->_rws;
  
  if (!pag) return TRUE;
  pag->set_rate_differenziate(msk->get_int(F_RATE_DIFF));
  if (pag->dirty())
  {
    pag->set_sheet(*shf);
    (*rws) = shf->rows_array(); 
  }
  return TRUE;
}                                                                 

bool BA3700_application::tipo_prima_rata(TMask_field& f, KEY k)                  
{   
  // aggiunge o toglie se necessario rata 0, lasciando 
  // le altre e shiftando le scadenze 
  if (f.mask().query_mode())
    return TRUE;
  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk;
  TArray*       rws = s->_rws;
  
  if (!pag || pag->n_rate() == 0) return TRUE;

  int ir = msk->get_int(F_INT_RATE);
  if (ir == 0) ir = -1;

  pag->set_tipo_prima_rata(msk->get_int(F_TIPO_PRIMA_RATA),ir);
  if (pag->dirty())
  {
    pag->set_sheet(*shf);  
    (*rws) = shf->rows_array(); 
    msk->set(F_NUM_RATE, pag->n_rate());
  }
  return TRUE;
}

bool BA3700_application::numero_rate(TMask_field& f, KEY k)                  
{
  // azzera tutto e ricrea da capo mantenendo le scadenze che ci sono 
  if (k != K_TAB || f.mask().query_mode()) return TRUE;

  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk;
  TArray*       rws = s->_rws;
  int nr = msk->get_int(F_NUM_RATE);
  if (!pag || nr == pag->n_rate() || msk->get(F_NUM_RATE).empty()) 
    return TRUE;
  int ir = msk->get_int(F_INT_RATE);
  if (ir == 0) ir = -1;
  
  pag->set_numero_rate(nr,ir);       
  if (pag->dirty())
  {
    pag->set_sheet(*shf);  
    (*rws) = shf->rows_array(); 
  }                              
  
  msk->set(F_NUM_RATE,pag->n_rate());
  return TRUE;
}

bool BA3700_application::mese_commerciale(TMask_field& f, KEY k)                  
{
  // setta mcomm e ricalcola le scadenze 
  // pag->set_mese_commerciale()
  //  if (k != K_ENTER) return FALSE;
  if (f.mask().query_mode())
    return TRUE;

  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk; 
  TArray*       rws = s->_rws;

  if (!pag) return TRUE;
  int ir = msk->get_int(F_INT_RATE);
  if (ir == 0) ir = -1;

  pag->set_mese_commerciale(msk->get_bool(F_MESECOMM),ir);
  if (pag->dirty())
  {
    pag->set_sheet(*shf);
    (*rws) = shf->rows_array(); 
    msk->set(F_INT_RATE,ir); 
  }
  return TRUE;
}

bool BA3700_application::fixed_scad(TMask_field& f, KEY k)                  
{
  // setta mcomm e ricalcola le scadenze 
  // pag->set_mese_commerciale()
  if (k != K_TAB || f.mask().query_mode()) return TRUE;
  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;

  if (!pag) return TRUE;                                                           
  
  int ir = 0; 
  if (f.dlg() == F_FIXSCAD_2)      ir = 1; 
  else if (f.dlg() == F_FIXSCAD_3) ir = 2; 

  pag->set_fixed_scad(atoi(f.get()),ir);

  return TRUE;
}

bool BA3700_application::tipo_rata(TMask_field& f, KEY k)                  
{
  if (f.mask().query_mode())
    return TRUE; 
  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field*  shf = s->_sht;

  if (k == K_TAB && pag)  
  {
    pag->set_default_type(atoi(f.get()));
    pag->set_sheet(*shf);
  }
  return TRUE;
}

bool BA3700_application::ult_class(TMask_field& f, KEY k)                  
{                            
  if (f.mask().query_mode())
    return TRUE; 
  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field*  shf = s->_sht;

  if (k == K_TAB && pag && f.focusdirty())  
  {
    pag->set_default_ulc(f.get());
    pag->set_sheet(*shf);
  }
  return TRUE;
}

// qui viene il belloccio                  
bool BA3700_application::sheet_action(TSheet_field&, int r, KEY k)                                                                                
{                                              
  bool doit = TRUE, m_perc = FALSE, m_pag = FALSE;
  bool m_scad = FALSE, m_tipo = FALSE, m_ulc = FALSE, mod = FALSE;
  word ahiahi = P_OK;                                

  sht* s = (sht*)get_app_data();
  TPagamento*    pag = s->_pag;
  TSheet_field* shf = s->_sht;
  TMask*        msk = s->_msk;
  TArray*       rws = s->_rws;
  
  if (!pag) return TRUE;

  TString news(15), newp(15), newt(1), newu(1);                                  
  TToken_string ts(36), ns(36);
  bool recalc = TRUE;                
  
  switch (k)
  {
  case K_SPACE:
    break;
  case K_ENTER:
  {     
    ns  = shf->row(r);     
    ts  = (TToken_string&)(*rws)[r];    
    
    news = ns.get(0);
    newp = ns.get();
    newt = ns.get();                                            
    newu = ns.get();                                            
    
    // qui viene il bello, si fa per dire 
    if (ts.get_int(0) != atoi(news))  // modificata scadenza
    {                            
      mod  = m_scad = TRUE;        
    }
    const real p0(ts.get(1));
    const real p1(newp);

    if (p0 != p1)  // modificata percentuale
      mod  = m_perc = TRUE;        

    if (strcmp(ts.get(2),newt) != 0)  // modificato tipo pagamento
      mod  = m_tipo = m_ulc = TRUE;      
    
    if (strcmp(ts.get(3),newu) != 0)  // modificata ulteriore classificazione
      mod  = m_ulc = TRUE;      
  }
    break;
  case K_DEL:
  case K_INS:
    doit = FALSE;
    break;
  default:
    break;
  }          
  
  // settato da recalc_rate se occorre ridefinire lo sheet
  // aggiungendo o togliendo righe
  bool need_recalc = FALSE;      

  if (k == K_ENTER) 
  {
    if (mod && recalc)
    {
      // ricalcola sheet come sai fare tu
      int rdiff = atoi(msk->get(F_RATE_DIFF));
      ahiahi = pag->recalc_rate(r, m_perc, 
                                (m_perc ? (const char*)newp : NULL),
                                (m_scad ? (const char*)news : NULL),
                                (m_tipo ? (const char*)newt : NULL),  
                                (m_ulc  ? (const char*)newu : NULL), 
                                rdiff, 
                                pag->mese_commerciale(),
                                need_recalc);
      // see if parameters changed                          
      msk->set(F_RATE_DIFF, pag->rate_differenziate() ? "1" : "2", TRUE);
      msk->set(F_MESECOMM, pag->mese_commerciale()   ? "X" : "");
    }
    if (!recalc)
    {                              
      ahiahi = P_OK;
      // put data as they are
      TToken_string& trw = pag->rata(r);
      TToken_string  srw = trw;
      if (m_scad)  trw.add(news,0);
      if (m_perc)  trw.add(newp,1);
      if (m_tipo)  trw.add(newt,2);
      if (m_ulc)   trw.add(newu,3);
      // validate the payment
      if ((ahiahi = pag->validate()) != P_OK)
        pag->rata(r) = srw;
    }
    if (ahiahi)
      // rimetti le righe com'erano prima
    {  
      TString s(256);
      pag->strerr(ahiahi,s);
      warning_box(s);
      shf->row(r) = (TToken_string&)(*rws)[r]; 
      shf->force_update(-1); 
      msk->set(F_NUM_RATE, pag->n_rate());
    } 
    
    else if (recalc && mod && need_recalc) 
    {                                   
      // ridefinisci lo sheet sulla base delle nuove rate
     pag->set_sheet(*shf);
     shf->force_update(-1);         
     rws->destroy();
    (*rws) = shf->rows_array();      
    }                                                 

    msk->set(F_NUM_RATE, pag->n_rate()); 
  }

  return doit;
}


int BA3700_application::rewrite(const TMask& m)
{
  TTable& tab_cpg = (TTable&)_rel->lfile();
  TTable& tab_rpg = (TTable&)_rel->lfile(-ALIAS);
  const int err = _pag->rewrite(tab_rpg); 
  if (err != NOERR) return err; 
  m.autosave(_rel);
  tab_cpg.put("B1", _pag->rate_differenziate() ? "X" : "");
  return _rel->lfile().rewrite();
}

int BA3700_application::write(const TMask& m)
{
  TTable& tab_cpg = (TTable&)_rel->lfile();
  TTable& tab_rpg = (TTable&)_rel->lfile(-ALIAS);  
  const int err = _pag->write(tab_rpg);  
  if (err != NOERR) return err; 
  m.autosave(_rel);      
  tab_cpg.put("B1", _pag->rate_differenziate() ? "X" : "");
  return _rel->lfile().write();
}

bool BA3700_application::remove()
{
  TTable& tab_rpg = (TTable&)_rel->lfile(-ALIAS);
  return _pag->remove(tab_rpg) == NOERR && _rel->lfile().remove() == NOERR;
}

int ba3700(int argc, char* argv[])
{
  BA3700_application a;
  a.run(argc, argv, "Condizioni di pagamento");
  return 0;
}
