// cg5300.cpp
// modifica parametri contabilita' relativi alla liquidazione

#include <config.h>
#include <msksheet.h>
#include <relapp.h>
#include <tabutil.h>
#include <urldefid.h>
#include <utility.h>   

#include "cg5.h"
#include "cg5300a.h"

#include <attiv.h>
#include <nditte.h>

#define TAB_LIA "%LIA"                                
#define TAB_PLA "%PLA"                                

class TParaliq_app : public TRelation_application
{ 
  TRelation *       _rel;
  TMask *           _msk;
  TLocalisamfile *  _attiv;
  TLocalisamfile *  _ditte;
  int               _yearliq;
  TTable *          _pla;

protected: // Applicat
  virtual void on_config_change();

protected: // Relapp
  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; }

  // file intertface
  virtual bool         remove()                    { return TRUE;  }
  virtual bool         protected_record(TRectype&) { return TRUE;  }
  virtual void         init_query_mode(TMask&);
  virtual void         init_insert_mode(TMask& m);
  virtual int          rewrite(const TMask& m);
  // non si possono aggiungere record, se non ci sono vengono
  // creati automaticamente
  virtual int          write(const TMask& m) { return rewrite(m);}
  virtual int          read(TMask& m);  

protected:
  void        check_registers(int year);
  void        init_array(TMask& m, bool update);
  static bool sheet_action(TSheet_field& s, int r, KEY k);
  
public:
  
  TParaliq_app() {}
  virtual ~TParaliq_app() {}    
};


void TParaliq_app::check_registers(int year)
{
  // controlla che per ogni data attivita' esistano almeno un registro
  // acquisti, vendite e giornale; warning appropriato in caso negativo 
  TSheet_field& sf = (TSheet_field&)_msk->field(F_SHEET_PLA);
  TTable reg("REG");
  TRecfield reg_year(reg.curr(), "CODTAB", 0,3);
  
  const byte R_ACQ = 0x01;
  const byte R_VEN = 0x02;
  const byte R_ALL = R_ACQ | R_VEN;

  byte flags = 0x00;      

  for (int i = 0; i < sf.items(); i++)
  {
    const TString16 att(sf.row(i).get(0));
    for (reg.first(); !reg.eof(); reg.next())
    {      
      if (atoi(reg_year) != year || att != reg.get("S8")) 
        continue;
      
      switch (reg.get_int("I0"))
      {
      case 1:    // vendite 
        flags |= R_VEN;
        break;
      case 2:    // acquisti
        flags |= R_ACQ;
        break;
      default:
        break;  
      }
      if (flags ==  R_ALL) break;
    } 
    if (flags < R_ALL)
    {      
      TString wrn("I seguenti registri non esistono per l'attivita' "); 
      wrn << att << "(" << year << "):";
      if ((flags & R_VEN) == 0x00) wrn << "\n\tregistro vendite";
      if ((flags & R_ACQ) == 0x00) wrn << "\n\tregistro acquisti";
      warning_box(wrn);
    }
  } 
}                                      


void TParaliq_app::init_array(TMask& m, bool update)
{                       
  TSheet_field& sf = (TSheet_field&)m.field(F_SHEET_PLA);

  const long newditta = m.get_long(F_CODDITTA);

  _attiv->zero();
  _attiv->put(ATT_CODDITTA, newditta);
  TRectype r(_attiv->curr());
  
  int i = 0;
  for(_attiv->read(_isgteq); 
      _attiv->good() && _attiv->curr() == r; 
      _attiv->next(), i++)
  {                         
    TToken_string& tt = sf.row(i);
    
    // istanzia array _atts on le attivita' della ditta corrente
    tt = "";
    tt.add(_attiv->get(ATT_CODATT));
    tt.add(_attiv->get(ATT_TIPOATT));
    tt.add("");
    tt.add("");
    tt.add("");
    tt.add("");
  } 
  
  if (update)
  {
    sf.force_update();
    
    TString16 freq;
    _ditte->put(NDT_CODDITTA, newditta);
    if (_ditte->read() == NOERR)
      freq = _ditte->get(NDT_FREQVIVA);
    m.set(F_FREQ_VERS, freq);
  }   
}


void TParaliq_app::on_config_change()
{
  TConfig d(CONFIG_DITTA);
  _yearliq = (int)d.get_long("AnLiIv");
}

bool TParaliq_app::user_create()
{
  _rel     = new TRelation(TAB_LIA);
  _pla     = new TTable(TAB_PLA);
  _attiv   = new TLocalisamfile(LF_ATTIV);
  _ditte   = new TLocalisamfile(LF_NDITTE);
  _msk     = new TMask("cg5300a");
  
  ((TSheet_field&)_msk->field(F_SHEET_PLA)).set_notify(sheet_action);
  return TRUE;
}

bool TParaliq_app::user_destroy()  
{               
  delete _rel;
  delete _attiv;
  delete _ditte;
  delete _msk;
  delete _pla;
  return TRUE;
}

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

void  TParaliq_app::init_query_mode(TMask& m)
{
  // svuota tutto
  TSheet_field& sh = (TSheet_field&)m.field(F_SHEET_PLA);
  sh.reset();
}

void  TParaliq_app::init_insert_mode(TMask& m)
{
  // Inizializza array delle attivita'                            
  init_array(m, TRUE);
}


int TParaliq_app::rewrite(const TMask& m)
{                  
  // scrive %LIA
  // scrive tutte le righe di %PLA a partire dalle righe sheet  
  static int oldyear;
  
  TSheet_field& sf = (TSheet_field&)m.field(F_SHEET_PLA);
  const long firm = m.get_long(F_CODDITTA);
  const int year = m.get_int(F_YEAR);
  
  int err = NOERR;
  bool was = FALSE;
  
  for (int i = 0; err == NOERR && i < sf.items(); i++)
  {                      
    TToken_string& tt = sf.row(i);
    const TString16 att = tt.get(0);
    const TString16 tips(tt.get(1));
    const TString16 codtab(format("%05ld%4d%s1", firm, year, (const char*)att));
    
    _pla->zero();
    _pla->put("CODTAB", codtab);
    was =_pla->read() == NOERR; 
    if (!was) _pla->zero();
    
    real prorata = _pla->get_real("R8");
    real es_a8   = _pla->get_real("R5");
    real es_a8b  = _pla->get_real("R6");
    real es_a9   = _pla->get_real("R7");
    
    _pla->put("CODTAB", codtab);
    // scrive i campi (vedi a read() per i nomi) 
    // in base alla riga sheet  
    _pla->put("S7", tips);         // tipo attivita'
    _pla->put("R8", tt.get());     // prorata
    _pla->put("R5", tt.get());     // plafond art. 8
    _pla->put("R6", tt.get());     // plafond art. 8bis
    _pla->put("R7", tt.get());     // plafond art. 9
    
    err = (was ? _pla->rewrite() : _pla->write());  
    
    // se si e' cambiato qualcosa..
    if (prorata != _pla->get_real("R8") ||
        es_a8   != _pla->get_real("R5") ||
        es_a8b  != _pla->get_real("R6") ||
        es_a9   != _pla->get_real("R7") ||
        m.field(F_CRED_PREC).dirty())
    {
      // invalida la prima liquidazione calcolata se ce n'e'
      TTable lim("LIM");

      TRecfield lim_anno(lim.curr(),"CODTAB",0,3);

      for (lim.first(); !lim.eof(); lim.next())
      {
        if (year == atoi(lim_anno))
        {
          lim.put("B0","");
          lim.rewrite();
          break;
        }
      }
    }
  }
  
  TTable& lia = (TTable&)_rel->lfile();
  lia.put("CODTAB", format("%05ld%d", firm, year));
  was = lia.read() == NOERR;
  if (!was) lia.zero();
  m.autosave(_rel);
  if (err == NOERR) err = (was ? lia.rewrite() : lia.write());
  if (err == NOERR && year == _yearliq) 
  {
    _ditte->put(NDT_CODDITTA, firm);
    if (_ditte->read() == NOERR)
    {
      _ditte->put(NDT_FREQVIVA, m.get(F_FREQ_VERS));
      _ditte->rewrite();
    }
  }              
  
  // per ogni anno liquidazione controlla (una volta) l'esistenza
  // dei registri fondamentali
  if (year != oldyear && err == NOERR)
    check_registers(year);
  oldyear = year;
  
  return err;
}

int   TParaliq_app::read(TMask& m)
{
  // legge da LIA (si istanziano i campi credito prec. e Freq. Vers
  // prende le attivita' una per una da _atts e 
  // crea le righe sheet
  m.autoload(get_relation()); 

  const long firm = m.get_long(F_CODDITTA);
  const int year  = m.get_int(F_YEAR);
  
  TSheet_field& sf = (TSheet_field&)m.field(F_SHEET_PLA);
  sf.reset();

  const TString16 ctab = format("%05ld%4d", firm, year);
  _pla->put("CODTAB", ctab);
  TToken_string tt(80);
  
  init_array(m, FALSE);                     // Carica tutti i codici attivita'
  
  for (_pla->read(_isgteq); _pla->good(); _pla->next())
  {
    if (strncmp(ctab, _pla->get("CODTAB"), 9) == 0)
    {      
      tt = _pla->get("CODTAB").mid(9,5);    // codice attivita'   

      for (int i = 0; i < sf.items(); i++)  // Cerca riga corrispondente sullo sheet
        if (tt == sf.row(i).get(0)) break; 
      
      tt.add(_pla->get("S7"));              // tipo attivita'
      tt.add(_pla->get("R8"));              // prorata
      tt.add(_pla->get("R5"));              // plafond art. 8
      tt.add(_pla->get("R6"));              // plafond art. 8bis
      tt.add(_pla->get("R7"));              // plafond art. 9
      sf.row(i) = tt;
    }
    else break;
  }
  sf.force_update();
  
  return NOERR;
}


int cg5300(int argc, char* argv[])
{
  TParaliq_app a;
  a.run(argc, argv, "Parametri liquidazione");
  return 0;
}

















