#include <config.h>
#include <defmask.h>
#include <msksheet.h>
#include <relapp.h>
#include <sheet.h>
#include <validate.h>

#include <pconti.h>
#include <clifo.h>   
#include <anagr.h>  
#include <anafis.h> 
#include <cfven.h>
#include <mov.h>
#include <indsp.h>

#include "cg0.h"
#include "cg0200.h"
#include "cg0201.h"

class TClifo_application : public TRelation_application
{
  TMask* _msk;
  TClifoVI* _rel;
  TLocalisamfile* _mov;
  TLocalisamfile* _anag; 
  TLocalisamfile* _fis;
  TLocalisamfile* _comuni;
  TLocalisamfile* _pcon;
  
  bool _lbcn, _gesven;
  bool _savenew;
  bool _ignoreven;
  
  TToken_string _tmp;

protected:
  bool user_create();
  bool user_destroy();
  virtual TMask* get_mask(int mode) { return _msk; }
  virtual bool changing_mask(int mode) { return FALSE; }
  virtual bool save_and_new() const { return _savenew; }
  virtual bool protected_record(TRectype &rec);
  virtual const char* get_next_key();
  void  init_pages(TMask& m);
  virtual void init_query_mode(TMask& m);
  virtual void init_query_insert_mode(TMask& m) {init_query_mode(m);}
  virtual void init_insert_mode(TMask& m) {init_query_mode(m);}
  virtual void on_config_change();
  
  ////////////
  static bool indsp_notify(TSheet_field& s, int r, KEY key); 
  static void indsp_sheet_rebuilder();
  virtual int write(const TMask& m);
  virtual int rewrite(const TMask& m);
  virtual int read(TMask& m);
  TSheet_field& indsp_sheet() const;
  TArray_sheet* field_sheet(const int n) const;
  void reset_sheet();
  void indsp_pack();
  void common_f(const TMask& m);
  
  static bool tipo_handler(TMask_field& f, KEY key);
  static bool percip_handler(TMask_field& f, KEY key);

public:
  virtual TRelation* get_relation() const {return (TRelation*)_rel;}
  TClifo_application(){}
};

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

bool TClifo_application::protected_record(TRectype &rec)

{
  TMask* m = get_mask(MODE_MOD);
  const TString16 tipocf(m->get(F_TIPOCF));
  const long codice = atol(m->get(F_CODCF));

  _mov->curr().zero();
  _mov->curr().put(MOV_TIPO, tipocf);
  _mov->curr().put(MOV_CODCF, codice);
  _mov->read();
  return tipocf == _mov->get(MOV_TIPO) &&
    codice == atol(_mov->get(MOV_CODCF));
  return FALSE;
}

const char* TClifo_application::get_next_key()

{
  TLocalisamfile& clifo = _rel->lfile() ;
  long  codcf = 1L ;
  const TString tipo(_msk->get(F_TIPOCF)) ;
  
  if (!clifo.empty())
  {
    clifo.zero() ;
    clifo.setkey(1) ;
    if ( tipo == TCLI )
    {
      clifo.put(CLI_TIPOCF, (const char* ) TFOR);
      clifo.read(_isgteq ) ;
      if (clifo.good())
        clifo.prev() ;
      clifo.setstatus(NOERR);
    }
    else clifo.last( ) ;
    if ( clifo.good() )
    {
      const TFixed_string tipocf(clifo.get(CLI_TIPOCF)); 
      if ( tipocf == tipo )
        codcf += clifo.get_long(CLI_CODCF);
    }
  }                 
  _tmp.format("%d|%s|%d|%ld", F_TIPOCF, (const char*) tipo, F_CODCF, codcf);
  return _tmp;
}

HIDDEN bool no_dup_fis(TMask_field& f, KEY key)
{
  TMask&        msk = f.mask() ;                                   
  
  if (msk.query_mode() || !f.to_check(key)) return TRUE;
  TLocalisamfile&       clifo = app().get_relation()->lfile(LF_CLIFO) ;

  if ( f.get().not_empty() && !clifo.empty() )
  {
    clifo.zero() ;
    const char t1 = msk.get(F_TIPOCF)[0] ;

    clifo.put(CLI_TIPOCF, t1);
    clifo.put(CLI_COFI, f.get());
    clifo.setkey(4) ;
    clifo.read() ;
    clifo.setkey(1) ;
    const char t = clifo.get_char(CLI_TIPOCF);
    const TFixed_string s = clifo.get(CLI_CODCF);
    const TFixed_string s1(msk.get(F_CODCF));

    if (clifo.good() && (t1 != t || s1 != s))
    {
      f.yesno_box("Codice fiscale gia' utilizzato per il codice : %c/%s",
                  t, (const char*) s);
      return FALSE;
    }
  }
  return TRUE ;
}

HIDDEN bool no_dup_iva(TMask_field& f, KEY key)
{
  TMask&                                        msk = f.mask() ;
  
  if (msk.query_mode() || !f.to_check(key)) return TRUE;
  
  TLocalisamfile&       clifo = app().get_relation()->lfile(LF_CLIFO) ;

  if ( f.get().not_empty() && !clifo.empty() )
  {
    clifo.zero() ;
    const char t1  = msk.get(F_TIPOCF)[0];
    
    clifo.put(CLI_TIPOCF, t1) ;
    clifo.put(CLI_STATOPAIV, msk.get(F_STATOPAIV)) ;
    clifo.put(CLI_PAIV, f.get()) ;
    clifo.setkey(5) ;
    clifo.read() ;
    clifo.setkey(1) ;
    const char t  = clifo.get_char(CLI_TIPOCF);
    const TFixed_string s = clifo.get(CLI_CODCF);
    const TFixed_string s1(msk.get(F_CODCF));
    
    if (clifo.good() && (t1 != t || s1 != s))
    {
      f.error_box("Partita iva gia' definita per il codice : %c/%s",
                  t, (const char*) s);
      return FALSE ;
    }
  }
  return TRUE ;
}

HIDDEN bool autoexit_rsoc_handler(TMask_field& f, KEY key)

{ 
  if (f.mask().query_mode() && key == K_TAB)
  {                  
    TString16 tmp;
    TArray parms;
    parms.add(tmp.format("%d", F_RAGSOC));
    parms.add(tmp.format("%d", F_RAGSOCA));
    ::validate(AUTOEXIT_FUNC, (TEdit_field&) f, key, parms);
  } 
  return TRUE;
}

HIDDEN bool autoexit_handler(TMask_field& f, KEY key)

{ 
  if (f.mask().query_mode())
  {
    if (key == K_TAB && f.focusdirty())
    {           
      TString16 tmp;
      TArray parms;
      parms.add(tmp.format("%d", f.dlg()));
      ::validate(AUTOEXIT_FUNC, (TEdit_field&) f, key, parms);
    } 
  }  
  else
  {
    if (f.dlg() == F_COFI && key == K_TAB && f.focusdirty())
    {
      const TString s1(f.get());

      if (s1.not_empty())
        f.mask().set(F_TIPOPERS, isdigit(s1[0]) ? "G" : "F");
    }
    if (f.to_check(key) && f.mask().get(F_ALLEG) != "4")
    {
      if (f.dlg() == F_COFI) return no_dup_fis(f, key);
      else 
        if (f.dlg() == F_PAIV) return no_dup_iva(f, key);
    }   
  }
  return TRUE;  
}

bool TClifo_application::tipo_handler(TMask_field& f, KEY key)
{
  TMask& m = f.mask();
  const bool fis = f.get() == "F";
  m.show(-5, app()._lbcn && fis);

  return TRUE;
}

bool TClifo_application::percip_handler(TMask_field& f, KEY key)
{
  TMask& m = f.mask();

  if (f.to_check(key) && m.get(F_CODANAGPER).not_empty())
  {     
    const TRectype& anag = m.efield(F_CODANAGPER).browse()->cursor()->file().curr();
    TString80 c(m.get(F_COFI)), p(m.get(F_PAIV));

    if ((c.not_empty() && c != anag.get(ANA_COFI)) || 
        (p.not_empty() && p != anag.get(ANA_PAIV))) 
      return error_box("Percipiente non corretto: codice fiscale o partita IVA diversa");
    
    const TString80 r(anag.get(ANA_RAGSOC));
    if (key == K_TAB && m.get(F_RAGSOC).empty() && 
        yesno_box("Ragione sociale mancante: assumo %s", (const char*)r))
    {
      m.set(F_RAGSOC, r.left(30), TRUE);
      m.set(F_RAGSOCA, r.mid(30), TRUE);
    }  
    
    if (m.get(F_INDCF).empty()) m.set(F_INDCF, anag.get(ANA_INDRES));
    if (m.get(F_CIVCF).empty()) m.set(F_CIVCF, anag.get(ANA_CIVRES));
    if (m.get(F_CAPCF).empty()) m.set(F_CAPCF, anag.get(ANA_CAPRES));
    if (m.get(F_COMCF).empty()) 
    {
      m.set(F_STATOCF, anag.get(ANA_STATORES), TRUE);
      m.set(F_COMCF, anag.get(ANA_COMRES), TRUE);
    }
    if (c.empty()) m.set(F_COFI, anag.get(ANA_COFI));
    if (p.empty()) m.set(F_PAIV, anag.get(ANA_PAIV));
    if (m.get(F_TIPOAPER) == "F")
    {
      m.show(-5, app()._lbcn);
      if (app()._lbcn)
      {
        TLocalisamfile fis(LF_ANAGFIS);
        
        fis.zero();
        fis.put(ANF_CODANAGR, anag.get(ANA_CODANAGR));
        if (fis.read() == NOERR)
        {
          if (m.get(F_DATANASC).empty()) m.set(F_DATANASC, fis.get(ANF_DATANASC));
          if (m.get(F_COMNASC).empty())
          {
            m.set(F_STATONASC, fis.get(ANF_STATONASC), TRUE);
            m.set(F_COMNASC, fis.get(ANF_COMNASC), TRUE);
          }     
        }
      } 
    }
  }
  return TRUE;                                  
}


HIDDEN bool alleg_handler(TMask_field& f, KEY key)

{ 
  if (f.to_check(key))
  {
    TMask& m = f.mask();
    const int tipoall = atoi(f.get());

    if (tipoall == 0 || tipoall == 1 || tipoall == 4) 
      m.enable(F_CODALLEG);
    else
    {
      m.disable(F_CODALLEG);
      m.reset(F_CODALLEG);
      m.reset(F_RAGSOCALLEG);
    }
    m.set(F_OCCASIONALE, (tipoall == 2) ? "X" : " ");
    m.field(F_COFI).set_dirty(TRUE);
    m.field(F_PAIV).set_dirty(TRUE);
  }
  return TRUE;
}

HIDDEN bool occas_handler(TMask_field& f, KEY key)
{ 
  if (f.to_check(key))
  {
    const bool occas = f.get().not_empty();
    TMask& m = f.mask();

    if (occas) 
      m.set(F_ALLEG, "2");
    else
      if (m.get_int(F_ALLEG) == 2)  
        m.reset(F_ALLEG);
  }
  return TRUE;
}

HIDDEN bool codalleg_handler(TMask_field& f, KEY key)
{ 
  if (f.to_check(key))
  {
    const TString16 cod(f.get());

    if (cod.not_empty())
    {
      TMask& m = f.mask();
      if (cod == m.get(F_CODCF))
        return error_box("Il codice per allegato coincide con il codice anagrafico");
      
      const char tipo = m.get(F_TIPOCF)[0];

      TLocalisamfile clifo(LF_CLIFO);
      clifo.zero() ;
      clifo.put(CLI_TIPOCF, tipo);
      clifo.put(CLI_CODCF, cod);
      clifo.read() ;
      if (clifo.bad()) return FALSE;
      
      if (clifo.get(CLI_CODALLEG).not_empty())
        return error_box("Codice non utilizzabile: contiene a sua volta un codice per allegato");
      
      if (clifo.get(CLI_PAIV).empty())
        return error_box("Codice non utilizzabile: privo di  partita IVA");
      
      const TString& tipoall = clifo.get(CLI_ALLEG);
      if (tipoall.not_empty() && tipoall != "1" && tipoall != "4")
        return error_box("Codice non utilizzabile: codice inserimento allegato non corretto");
    }
  }
  return TRUE;
}

void TClifo_application::on_config_change()
{
  TConfig cnf(CONFIG_DITTA);
  _gesven = _ignoreven ? FALSE : cnf.get_bool("GesVen"); 
  _lbcn = cnf.get_bool("GsLbCn");
  init_pages(*_msk);
}


void TClifo_application::init_pages(TMask& m)
{
  _rel->gestione_vendite(_gesven);

  m.show(-5, _lbcn);

  // Se non e' abilitata la gestione delle vendite disabilita le
  // maschere dalla 4 in poi
  if (!_ignoreven)
    for (int j = 3; j < 8;j++)
      m.enable_page(j, _gesven);
}

void TClifo_application::init_query_mode(TMask& m)

{
  if (_gesven)
    reset_sheet();

  if (argc() > 2 && *argv(2) == 'F') 
    m.set(F_TIPOCF, "F");
}

int TClifo_application::read(TMask& m)
{
  TRelation_application::read(m);           
  
  if (_gesven)
  {
    TToken_string riga(240);
    indsp_sheet().reset();
    for (int i=0; i< _rel->indirizzi_items();i++)
    {
      TRectype& rec=_rel->indirizzo(i);
      riga.cut(0);
      riga.add(rec.get(IND_RAGSOC));
      riga.add(rec.get(IND_INDIR));
      riga.add(rec.get(IND_CIV));
      riga.add(rec.get(IND_LOCALITA));
      riga.add(rec.get(IND_CAP));
      riga.add(rec.get(IND_STATO));
      riga.add(rec.get(IND_COM));
      riga.add(rec.get(IND_PTEL));
      riga.add(rec.get(IND_TEL));
      riga.add(rec.get(IND_PFAX));
      riga.add(rec.get(IND_FAX));
      riga.add(rec.get(IND_IVARID));
      riga.add(rec.get(IND_CODIND));
      indsp_sheet().row(i)=riga;
      
      // Load the sheets of CODINDDOC, CODINDSP, CODINDEFF.
      riga.cut(0);
      riga.add(rec.get(IND_CODIND));
      riga.add(rec.get(IND_RAGSOC));
      riga.add(rec.get(IND_INDIR));
      riga.add(rec.get(IND_CIV));
      riga.add(rec.get(IND_LOCALITA));
      field_sheet(F_CODINDDOC)->add(riga);
      field_sheet(F_CODINDSP)->add(riga);
      field_sheet(F_CODINDEFF)->add(riga);
    }
  }   
  return _rel->status();
}

int TClifo_application::rewrite(const TMask& m)
{
  common_f(m);
  return TRelation_application::rewrite(m);
}

int TClifo_application::write(const TMask& m)
{
  common_f(m);
  return TRelation_application::write(m);
}

TArray_sheet* TClifo_application::field_sheet(const int n) const
{
  TEdit_field& f=(TEdit_field&) _msk->field(n);
  TArray_sheet* ss=(TArray_sheet*) f.sheet()->sheet();
  return ss;
}

TSheet_field& TClifo_application::indsp_sheet() const
{
  TSheet_field& o_sheet=(TSheet_field&) _msk->field(F_SHEET_G_VEN);
  return o_sheet;
}

void TClifo_application::reset_sheet()
{
  const TToken_string nulla("|**Nessuno**||||");

  app().field_sheet(F_CODINDDOC)->destroy();
  app().field_sheet(F_CODINDDOC)->add(nulla);
  app().field_sheet(F_CODINDSP)->destroy();
  app().field_sheet(F_CODINDSP)->add(nulla);
  app().field_sheet(F_CODINDEFF)->destroy();
  app().field_sheet(F_CODINDEFF)->add(nulla);
}

void TClifo_application::indsp_pack()
{
  TArray& rows = indsp_sheet().rows_array();
  int nr=rows.items();

  for (int i=0; i<nr; i++)
  {
    TToken_string& riga=(TToken_string&)rows[i];
    if (riga.empty_items())
      rows.destroy(i,FALSE);
  }
  rows.pack();
}

void TClifo_application::common_f(const TMask& m)
{
  if (_gesven)
  {
    const char tipocf = m.get(F_TIPOCF)[0];
    const long codcf = m.get_long(F_CODCF);
    
    _rel->destroy_rows();
    indsp_pack();
    TArray& rows=indsp_sheet().rows_array();
    int n_items = rows.items();
    
    for (int i = 0; i < n_items; i++)
    {
      TToken_string& row=(TToken_string&)rows[i];
      TRectype& rec=_rel->indirizzo(i);
      row.restart();
      rec.zero();
      rec.put(IND_TIPOCF,tipocf);
      rec.put(IND_CODCF,codcf);
      rec.put(IND_RAGSOC,row.get());
      rec.put(IND_INDIR,row.get());
      rec.put(IND_CIV,row.get());
      rec.put(IND_LOCALITA,row.get());
      rec.put(IND_CAP,row.get());
      rec.put(IND_STATO,row.get_int());
      rec.put(IND_COM,row.get());
      rec.put(IND_PTEL,row.get());
      rec.put(IND_TEL,row.get());
      rec.put(IND_PFAX,row.get());
      rec.put(IND_FAX,row.get());
      rec.put(IND_IVARID,row.get());
      rec.put(IND_CODIND,i+1);
    }  
  }
}
void TClifo_application::indsp_sheet_rebuilder()
{
  TArray& righe=app().indsp_sheet().rows_array();
  const int n=righe.items();
  app().reset_sheet();
  // Rebuild Sheets
  for (int i=0; i<n; i++)
  {  
    TToken_string& riga=(TToken_string&)righe[i];
    TToken_string  rigav;
    rigav.add(riga.get(12));
    rigav.add(riga.get(0));
    rigav.add(riga.get());
    rigav.add(riga.get());
    rigav.add(riga.get());
    app().field_sheet(F_CODINDDOC)->add(rigav);
    app().field_sheet(F_CODINDSP)->add(rigav);
    app().field_sheet(F_CODINDEFF)->add(rigav);
  }         
}

bool TClifo_application::indsp_notify(TSheet_field& indsp, int r, KEY key)
{
  switch (key)
  {
  case K_SPACE: 
  {
    // Request to modify row #r
    // Disable field CODIND update # of row
    TMask& m = indsp.sheet_mask();
    if (m.get_int(F_CODINDI)==0)  // Is it a new row ?
      m.set(F_CODINDI,(long)(r+1));
    m.disable(F_CODINDI);
  }
  break;
 case K_INS: 
  // request to add the row #r
  // To avoid rewriting of existing record.
  // To avoid inserts in the middle of the sheet
  if (r != -1 && indsp.items() > (r+1))
  {
    error_box("Si possono aggiungere indirizzi solo alla fine");
    return FALSE;  //Refuse permission
  }
  break;
default:
  break;
}           
  if (key == K_ENTER || key == K_DEL)
    indsp_sheet_rebuilder();
  return TRUE;
}

bool TClifo_application::user_create() // initvar e arrmask
{
  _rel = new TClifoVI;

  _mov = new TLocalisamfile(LF_MOV);
  _anag = new TLocalisamfile(LF_ANAG);
  _fis = new TLocalisamfile(LF_ANAGFIS);
  _pcon = new TLocalisamfile(LF_PCON);
  _comuni = new TLocalisamfile(LF_COMUNI);

  _ignoreven = argc() > 2;
  const int max = _ignoreven ? 3 : -1;
  _msk = new TMask("cg0200a", 0, max) ;

  _msk->set_handler(F_OCCASIONALE, occas_handler);
  _msk->set_handler(F_RAGSOCA, autoexit_rsoc_handler);
  _msk->set_handler(F_COFI, autoexit_handler);
  _msk->set_handler(F_PAIV, autoexit_handler);
  _msk->set_handler(F_RICALT, autoexit_handler);
  _msk->set_handler(F_CODANAGPER, percip_handler);
  _msk->set_handler(F_TIPOPERS, tipo_handler);
  _msk->set_handler(F_ALLEG, alleg_handler);
  _msk->set_handler(F_CODALLEG, codalleg_handler);
  if (!_ignoreven)
  {
    TSheet_field& ind = (TSheet_field&) _msk->field(F_SHEET_G_VEN);
    ind.set_notify(indsp_notify);
  }  
  
  _mov->setkey(3);

  TConfig config(CONFIG_STUDIO);
  _savenew = !config.get_bool("Cg02SN");
  
  return TRUE;
}

bool TClifo_application::user_destroy() // releasev e arrmask
{
  delete  _msk;
  delete  _rel;
  delete  _mov;
  delete  _anag;
  delete  _fis;
  delete  _pcon;
  delete  _comuni;
  return TRUE;
}

int cg0200(int argc, char* argv[])
{
  TClifo_application a;

  a.run(argc, argv, "Clienti/Fornitori");
  return 0;
}




