// 771233.cpp - distinta quadro G
#include <msksheet.h>
#include <progind.h>
#include <relapp.h>
#include <recarray.h>

#include "77lib.h"
#include "774200.h"
#include "771232.h"    
#include "77qgd.h"

#include "quadrogd.h"
#include "rpag.h"
#include "scperc.h"

///////////////////////////////////////////////////////////
// Comodo array per sommare e raggruppare le righe distinta
///////////////////////////////////////////////////////////

class TRighe_distinta : public TAssoc_array
{
public:
  void add_riga(const TRectype& riga);
  void write();
  
  TRighe_distinta() { }
  virtual ~TRighe_distinta() { }
};

void TRighe_distinta::add_riga(const TRectype& riga)
{ 
  TString16 chiave = riga.get(PAG_NQUOTE);
  
  TRectype* rec = (TRectype*)objptr(chiave);
  if (rec != NULL)
  {
    for (int i = rec->items()-1; i >= 0; i--)
    {              
      const char* name = rec->fieldname(i);
      if (rec->type(name) == _realfld && rec->length(name) >= 9)
      {
        real num = rec->get_real(name);
        num += riga.get_real(name);
        rec->put(name, num);
      }
    }
  }  
  else
    add(chiave, riga);
}

void TRighe_distinta::write()
{       
  TLocalisamfile file(LF_QUAGD);
  TRectype& curr = file.curr();

  int nriga = 1;
  restart();                                                      
  for (TRectype* rec = (TRectype*)get(); rec; rec = (TRectype*)get(), nriga++)
  {
    curr.put(QGD_NUMQUOTE,   rec->get(PAG_NQUOTE));
    curr.put(QGD_CODDITTA, rec->get(PAG_CODDITTA));
    curr.put(QGD_TIPOA,    rec->get(PAG_TIPOA));
    curr.put(QGD_CODANAGR, rec->get(PAG_CODANAGR));
    curr.put(QGD_NPROG,    nriga);
    curr.put(QGD_UTSPETT,  rec->get(PAG_UTSPETT));
    curr.put(QGD_ROPESPET, rec->get(PAG_RITUTSPE));
    curr.put(QGD_UTPAG,    rec->get(PAG_UTPAGATI));
    curr.put(QGD_ROPE,     rec->get(PAG_RITUTPAG));
    
    int err = file.write();
    if (err != NOERR)
      error_box("Errore %d nella scrittura della riga %d della distinta", err, nriga);
  }
}

///////////////////////////////////////////////////////////
// Applicazione per la gestione della distinta del quadro G
///////////////////////////////////////////////////////////

class TDistintaQuadroG : public TRelation_application
{
  TRelation* _rel;
  TMask*     _msk;
  int        _anno_dic;  // anno dichiarazione
  long       _codditta;
    
  bool       _registra;
  TString16  _quadro;
    
protected:
  static bool genera_handler(TMask_field& f, KEY k);

  void distruzione();
  void generazione();

  void fill_sheet(const TMask& m);  
  void pack_sheet(const TMask& m);  
  TSheet_field& find_sheet(const TMask& m) const;
  void read_sheet(TMask& m) const;
  int write_sheet(const TMask& m, bool re) const;
  int remove_sheet(const TMask& m) const;
    
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_query_insert_mode (TMask&);    
  virtual void init_insert_mode (TMask&);
  virtual void init_modify_mode (TMask&);    
  virtual void on_config_change();    
    
public:
  TDistintaQuadroG();
  virtual ~TDistintaQuadroG() {};
};                    

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

TDistintaQuadroG::TDistintaQuadroG(): _rel(NULL)
{
  _quadro = "GD";
}

void TDistintaQuadroG::fill_sheet(const TMask& m)
{
  TSheet_field& sf = (TSheet_field&)m.field(F_RIGHE);
  for (int r = sf.items(); r < 16; r++)
    sf.row(r);   
}

void TDistintaQuadroG::pack_sheet(const TMask& m)
{
  TSheet_field& sf = (TSheet_field&)m.field(F_RIGHE);
  for (int r = sf.items(); r >= 0; r--)
  {
    TToken_string& row = sf.row(r);
    if (row.empty_items())
      sf.destroy(r);
  }  
} 

TSheet_field& TDistintaQuadroG::find_sheet(const TMask& m) const
{
  int f;
  for (f = m.fields()-1; f > 0; f--)
  {
    if (m.fld(f).is_kind_of(CLASS_SHEET_FIELD))
      break;
  }
  CHECK(f > 0, "Cant' find the spreadsheet");
  return (TSheet_field&)m.fld(f);
}

void TDistintaQuadroG::read_sheet(TMask& m) const
{
  TSheet_field& sheet = find_sheet(m);
  sheet.destroy();
  TRectype key(get_relation()->curr());
  key.zero("NPROG");
  TRecord_array a(key, "NPROG");
      
  TMask& sm = sheet.sheet_mask();
  for (int r = 0; r < a.rows(); r++)
  {     
    const TRectype& rec = a.row(r+1);
    TToken_string& row = sheet.row(r);
    for (short id = 101; ; id++)
    {                              
      const int pos = sm.id2pos(id);
      if (pos >= 0)
      {
        TMask_field& mf = sm.fld(pos);
        const TFieldref* fr = mf.field();
        if (fr)
          row.add(fr->read(rec));
        else     
          row.add("");
      }  
      else
        break;
    }
    sheet.check_row(r);
  }
}

int TDistintaQuadroG::write_sheet(const TMask& m, bool re) const
{
  TRectype rec(get_relation()->curr());
  rec.zero("NPROG");
  TRecord_array a(rec, "NPROG");
  a.destroy_rows();
      
  TSheet_field& sheet = find_sheet(m);
  TMask& sm = sheet.sheet_mask();
  for (int r = 0; r < sheet.items(); r++)
  {     
    TToken_string& row = sheet.row(r);
    rec.put("NPROG", r+1);
    for (short id = 101; ; id++)
    {                              
      const int pos = sm.id2pos(id);
      if (pos >= 0)
      {
        TMask_field& mf = sm.fld(pos);
        const TFieldref* fr = mf.field();
        if (fr)
          fr->write(row.get(pos), rec);
      }  
      else
        break;
    }
    a.add_row(rec);
  }
  return a.write(re);
}

int TDistintaQuadroG::remove_sheet(const TMask& m) const
{
  TSheet_field& sheet = find_sheet(m);
  sheet.destroy();
  return write_sheet(m, TRUE);
}

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

int TDistintaQuadroG::rewrite(const TMask& m)
{
  pack_sheet(m);
  int err = TRelation_application::rewrite(m);
  if (err == NOERR)
    err = write_sheet(m, FALSE);
  if (err == NOERR)
    _registra = TRUE;
  return err;
}

int TDistintaQuadroG::write(const TMask& m)
{ 
  pack_sheet(m);
  int err = TRelation_application::write(m);
  if (err == NOERR)
    err = write_sheet(m, FALSE);
  if (err == NOERR)
    _registra = TRUE;
  return err;
}

bool TDistintaQuadroG::remove()
{
  bool ok = TRelation_application::remove();
  if (ok)
  {
    remove_sheet(curr_mask());
    _registra = TRUE;
  }
  return ok;
}

bool TDistintaQuadroG::user_create()
{                      
  _rel = new TRelation(LF_QUAGD);
  _msk = new TMask("77qgda");
  _msk->set_handler(DLG_GENERA, genera_handler);

  set_search_field(F_CODANAGRPERC);
  _registra = FALSE;
  
  return TRUE;
}

bool TDistintaQuadroG::user_destroy()
{ 
  delete _msk;
  delete _rel; 
  
  if (_registra)
  { 
    TRiporti rip;
    rip.set(_quadro);
  }  

  return TRUE;
}

void TDistintaQuadroG::on_config_change()
{                                
  TConfig conf(CONFIG_STUDIO);
  _anno_dic = (int)conf.get_long(ANNO_SEL, NULL); 
  _codditta = get_firm_770();
}

void TDistintaQuadroG::init_query_mode(TMask& m)
{                     
  TSheet_field& righe = (TSheet_field&)m.field(F_RIGHE);
  righe.destroy();
  
  m.set(F_CODDITTA, _codditta);
  m.set(F_ANNODIC, _anno_dic);   
  
  m.show(DLG_GENERA);
  m.hide(-1);  // nasconde (hide) group 1 - Scelta ANAGR
  m.show(-2);  // abilita (show) group 2 - Ricerca su DATI PERC
  m.disable(F_RAGSOCCOM);
}

void TDistintaQuadroG::init_query_insert_mode(TMask& m)
{ 
  m.set(F_CODDITTA, _codditta);
  m.set(F_ANNODIC, _anno_dic);   

  m.hide(-2);  // group 2 Nasconde ricerca su PERC
  m.show(-1);  // group 1 Ricerca su ANAGR
  m.enable(F_RAGSOCCOM);
}

void TDistintaQuadroG::init_insert_mode(TMask& m)
{ 
  m.hide(DLG_GENERA);
  m.disable(F_RAGSOCCOM);
  fill_sheet(m);
}

void TDistintaQuadroG::init_modify_mode(TMask& m)
{ 
  m.hide(DLG_GENERA);
  fill_sheet(m);
}

bool TDistintaQuadroG::genera_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    if (yesno_box("La distinta verra' completamente eliminata:\n"
                  "Confermare la generazione dalle schede"))
      app().generazione();
  }
  return TRUE;
}

void TDistintaQuadroG::distruzione()
{  
  TWait_cursor hourglass;
  
  TLocalisamfile file(LF_QUAGD);
  file.put(QGD_CODDITTA, _codditta);
  
  for (int err = file.read(_isgteq); err == NOERR; err = file.next())
  {
    if (file.get_long(QGD_CODDITTA) != _codditta)
      break;
    file.remove();  
  }
}

void TDistintaQuadroG::generazione()
{
  TRelation rel(LF_SCPERC);
  rel.add(LF_RPAG, "CODDITTA=CODDITTA|TIPOA=TIPOA|CODANAGR=CODANAGR|NPROG=NPROG");
  rel.add("%CA7", "CODTAB=CODCAUS");

  TRectype rec(LF_SCPERC);
  rec.put(SPR_CODDITTA, _codditta);  // Filtra la ditta corrente
  
  TCursor cur(&rel, NULL, 1, &rec, &rec);
  
  TString16 filter; filter.format("(%d->S1=\"%s\")", LF_TABCOM, "G");
  cur.setfilter(filter, TRUE);
  
  const long items = cur.items();
  TProgind pi(items, "Generazione distinta quadro G", TRUE, TRUE, 60);
  
  distruzione();
  
  char last_type = ' ';
  long last_code = 0L;
  
  const TRectype& scheda = cur.curr();
  const TRectype& riga = cur.curr(LF_RPAG);
  
  TRighe_distinta righe;
  
  for (cur = 0; cur.pos() < items; ++cur)
  {
    pi.addstatus(1);
    if (pi.iscancelled())
      break;
      
    char tipoa = scheda.get_char(SPR_TIPOA);
    long codan = scheda.get_long(SPR_CODANAGR);
    
    if (tipoa != last_type || codan != last_code)
    {
      if (righe.items() > 0)
      {
        righe.write();
        righe.destroy();
      }
      last_type = tipoa;
      last_code = codan;
    }
    
    bool ok = cur.is_first_match(LF_RPAG);
    while (ok)
    {             
      righe.add_riga(riga);
      ok = cur.next_match(LF_RPAG);
    }
  }
  if (righe.items() > 0)
    righe.write();
}

bool distinta_quadro_g(int argc, char* argv[])
{
  TDistintaQuadroG a;
  a.run(argc,argv, "Distinta quadro G");
  return TRUE;
}