// Rinumerazione movimenti e saldi
// fv 12/12/93
// -------------------------------------------------------------------------
// *TBI* Partenza dall'ultimo movimento stampato
// *TBI* Aggiornamento scadenziario
// *TBI* Aggiornamento cespiti
// -------------------------------------------------------------------------

#include <signal.h>

#include <applicat.h>
#include <isam.h>
#include <mask.h>
#include <progind.h>
#include <sort.h>
#include <urldefid.h>
#include <utility.h>

#define FLD_CG41_YEAR 100
#define MAX_CNT 300

#include <mov.h>
#include <rmov.h>
#include <rmoviva.h>
#include <saldi.h>
#include <causali.h>

#include "cglib.h"

struct therec {
  char DATAREG[9];
  char REG[4];
  char DATADOC[9];
  char NUMPROT[9];
  char ANNOES[5];
  char NUMREG[8];
};

class CG4100_App : public TApplication
{
  int  _year;
  char _optype;
  TMask* _msk;
  
public:
  
  virtual bool create();
  virtual bool destroy();

  bool set_parms();
  virtual bool menu(MENU_TAG m);

  void restore_mov(TSystemisamfile& a, TSystemisamfile& b, TSystemisamfile& c);
  void sort_all();
  bool sort_mov();
  bool sort_sal();

  CG4100_App() : TApplication(), _optype('S') {}
  virtual ~CG4100_App() {}
};


bool CG4100_App::create()
{
  TApplication::create();

  // UNIX: signal() per intercettare errori
#if XVT_OS == XVT_OS_SCOUNIX
  signal(SIGINT,SIG_IGN);
#endif                       

  if (fexist("__sal__.sav"))
    warning_box("Un'operazione di riordino saldi si e' conclusa"
                " impropriamente. Si raccomanda di rieseguirla");

  if (fexist("__mov__.sav"))
    warning_box("Un'operazione di riordino movimenti si e' conclusa"
                " impropriamente. Si raccomanda di rieseguirla");
  
  if (argc() > 2)
    _optype = toupper(argv(2)[0]);
  
  _msk = new TMask(_optype == 'S' ? "cg4100b" : "cg4100a");
  
  dispatch_e_menu(MENU_ITEM(1));
  return TRUE;
}

bool CG4100_App::destroy()
{
  // UNIX: resettare i segnali
#if XVT_OS == XVT_OS_SCOUNIX
  signal(SIGINT,SIG_DFL);
#endif
  delete _msk;
  return TApplication::destroy();
}

bool CG4100_App::set_parms()
{
  _msk->run();

  if (_optype == 'S')
    _year = _msk->get_int(FLD_CG41_YEAR);
  else 
    _year = 0;

  return _msk->last_key() == K_ENTER;
}


bool CG4100_App::menu(MENU_TAG)
{
  if (_optype == 'S')
    sort_sal();
  else
    sort_mov();

  return FALSE;
}


void CG4100_App::restore_mov(TSystemisamfile& mov, TSystemisamfile& rmov,
                             TSystemisamfile& rmoviva)
{
  long rn, rec;
  if (fexist("__mov__.ind"))
  {
    // rebuild all indexes
    mov.close(); rmov.close(); rmoviva.close();
    mov.packfile(); rmov.packfile(); rmoviva.packfile();
    mov.packindex(); rmov.packindex(); rmoviva.packindex();
    remove("__mov__.ind");
    return;
  }

  FILE* fp = fopen("__mov__.sav","r");
  if (feof(fp)) 
  { 
    warning_box("File di ripristino vuoto; il ripristino non e' necessario"); 
    remove("__mov__.sav");
    return; 
  }; 
  
  for (;;)
  {
    if (feof(fp)) break;
    fscanf(fp,"%ld %ld", &rn, &rec);
    
    mov.readat(rec);
    mov.put(MOV_NUMREG,rn);
    mov.rewrite();
    
    for (;;)
    {
      if (feof(fp)) break;
      fscanf(fp,"%ld",&rec);
      if (rec == -1l) break;
      rmov.readat(rec);
      rmov.put(RMV_NUMREG,rn);
      rmov.rewrite();
    }
    for (;;)
    {
      if (feof(fp)) break;
      fscanf(fp,"%ld",&rec);
      if (rec == -1l) break;
      rmoviva.readat(rec);
      rmoviva.put(RMI_NUMREG,rn);
      rmoviva.rewrite();
    }
  }
  
  fclose(fp);
  remove("__mov__.sav");  
}


bool CG4100_App::sort_mov()
{
  if (!set_parms())
    return FALSE;

  TSystemisamfile mov(LF_MOV);  mov.open(_excllock); 
  TSystemisamfile rmov(LF_RMOV); rmov.open(_excllock);
  TSystemisamfile rmoviva(LF_RMOVIVA); rmoviva.open(_excllock);
  
  mov.indexoff(); rmov.indexoff(); rmoviva.indexoff();
  mov.first();

  TSort sort(sizeof(struct therec));

  if (fexist("__mov__.sav") || fexist("__mov__.ind"))
  {
    // previous operation failed
    if (yesno_box("Un riordinamento precedente e' fallito.\n"
                  " Ripristino la situazione iniziale ora?" ))
      restore_mov(mov, rmov, rmoviva);
    else return FALSE;
  }

  therec rbuf;

  sort.addsortkey(rbuf.DATAREG - (char*)&rbuf, 8);
  sort.addsortkey(rbuf.REG     - (char*)&rbuf, 3);
  sort.addsortkey(rbuf.NUMPROT  - (char*)&rbuf, 8);
  sort.addsortkey(rbuf.DATADOC - (char*)&rbuf, 8);
  sort.addsortkey(rbuf.NUMREG - (char*)&rbuf, 7);

  sort.init();

  TProgind prnd(mov.items(),
                "Riordino archivio movimenti in corso\nOrdinamento file movimenti...",
                FALSE,TRUE,30);
  TString16 s;

  while (!mov.eof())
  {
    do_events();
    TDate d(mov.get(MOV_DATAREG));
    strcpy(rbuf.DATAREG, d.string(ANSI));
    strcpy(rbuf.REG,     mov.get(MOV_REG));
    d = mov.get(MOV_DATADOC);
    s = mov.get(MOV_PROTIVA);
    if (s.len() > 0 && isdigit(s[s.len() - 1])) s << " ";
    s.right_just(8);
    strcpy(rbuf.NUMPROT,  (const char *) s);
    strcpy(rbuf.DATADOC, d.string(ANSI));
    strcpy(rbuf.ANNOES,  mov.get(MOV_ANNOES));
    strcpy(rbuf.NUMREG,  mov.get(MOV_NUMREG));

    sort.sort((char*)&rbuf);
    mov.next();
    prnd.addstatus(1);
  }
  sort.endsort();

  prnd.setstatus(0);
  prnd.set_text("Riordino archivio movimenti in corso\nRiscrittura file movimenti...");

  therec* rr;
  long num = 1;
  TRecnotype recno;

  while ((rr = (therec*)sort.retrieve()) != NULL)
  {
    do_events();
    if (atol(rr->NUMREG) != num)
    {
      // find record
      mov.curr().zero();
      mov.put(MOV_NUMREG, rr->NUMREG);

      mov.read();
      // should never happen
      CHECK(mov.good(), "Archivio movimenti inconsistente. Questo si' che e' un casino.");

      // retrieve and change NUMREG
      recno = mov.recno();
      TString rgn = rr->NUMREG;
      FILE* fsav  = fopen("__mov__.sav","a");
      fprintf(fsav,"%s %d ", (const char*)rgn, recno);
      fclose(fsav);

      mov.put(MOV_NUMREG,num);
      mov.rewriteat(recno);
      // update linked records

      rmov.curr().zero();
      rmov.put(RMV_NUMREG,rgn);
      rmov.read(_isgteq);

      int row = 0;

      while (!rmov.eof() && rgn == rmov.get(RMV_NUMREG) &&
             row++ < rmov.get_int(RMV_NUMRIG))
      {
        recno = rmov.recno();
        fsav = fopen("__mov__.sav","a");
        fprintf(fsav,"%ld ", recno);
        fclose(fsav);
        rmov.put(RMV_NUMREG,num);
        rmov.rewriteat(recno);
        rmov.next();
      }
      fsav = fopen("__mov__.sav","a");
      fprintf(fsav,"-1");  fclose(fsav);

      rmoviva.zero();
      rmoviva.put(RMI_NUMREG,rgn);
      rmoviva.read(_isgteq);

      row = 0;

      while (!rmoviva.eof() && rgn == rmoviva.get(RMV_NUMREG) &&
             row++ < rmoviva.get_int(RMV_NUMRIG))
      {
        recno = rmoviva.recno();
        fsav = fopen("__mov__.sav","a");
        fprintf(fsav,"%ld ", recno);
        fclose(fsav);
        rmoviva.put(RMI_NUMREG,num);
        rmoviva.rewriteat(recno);
        rmoviva.next();
      } 
      fsav = fopen("__mov__.sav","a");
      fprintf(fsav,"-1"); fclose(fsav);
    }
    num++;
    prnd.addstatus(1);
  }

  remove("__mov__.sav");

  FILE* fsav = fopen("__mov__.ind","w"); fclose(fsav);

  prnd.set_text("Riordino archivio movimenti in corso\nRicostruzione files indice...");

  // rebuild indexes
  mov.close(); rmov.close(); rmoviva.close();
  mov.indexon(); rmov.indexon(); rmoviva.indexon();
  mov.packfile(); rmov.packfile(); rmoviva.packfile();
  mov.packindex(); rmov.packindex(); rmoviva.packindex();

  remove("__mov__.ind");

  return TRUE;
}


bool CG4100_App::sort_sal()
{
  if (!set_parms())
    return FALSE;

  TSystemisamfile saldi(LF_SALDI);  saldi.open(_excllock);
  TLocalisamfile rmov(LF_RMOV);
  TLocalisamfile causali(LF_CAUSALI);
  TLocalisamfile mov(LF_MOV);
  TSaldo_agg sal;

  FILE* fp = fopen ("__sal__.sav","w");
  fclose(fp);

  int gruppo, conto;
  const int year = _year;
  long oldnumreg = 0L, sottoconto;
  TProgind prnd(rmov.items(),
                "Riordino archivio saldi in corso\nLettura archivio movimenti...",
                FALSE,TRUE,30);

  causali.zero();
  mov.setkey(1);
  rmov.first(); 
  sal.reset();
  sal.set_anno_es(year);
  sal.clear_saldi(year);
  long numreg = 0L;
  bool apertura = FALSE, provvis = FALSE;
  TDate datareg;
  
  while (!rmov.eof())
  {
    if (_year == rmov.get_int(RMV_ANNOES))
    {
      numreg = rmov.get_long(RMV_NUMREG);

      gruppo = rmov.get_int(RMV_GRUPPO);
      conto = rmov.get_int(RMV_CONTO);
      sottoconto = rmov.get_long(RMV_SOTTOCONTO);
      if (numreg != oldnumreg)
      {
        if (oldnumreg !=0)
        {
          if (sal.items() > 0)
            sal.registra();
        }
        oldnumreg = numreg;
        mov.zero();
        mov.put(MOV_NUMREG, numreg);
        mov.read();
        CHECK(mov.good(),"Archivi movimenti e righe inconsistenti");

        causali.zero();
        const char* codcaus = mov.get(MOV_CODCAUS); 
        // cerca causale
        if (*codcaus)
        {
          causali.put(CAU_CODCAUS, codcaus);
          causali.read();
          CHECK(causali.good(),"Archivi causali e movimenti inconsistenti");
          apertura = causali.get(CAU_MOVAP) == "A";
        }
        else apertura = FALSE;
        provvis = mov.get(MOV_PROVVIS).not_empty();
        datareg = mov.get_date(MOV_DATAREG);

        sal.reset();
        sal.set_anno_es(_year);
        sal.set_movap(apertura);
        sal.set_movprovv(provvis);
        sal.set_data_ulmov(datareg);
        sal.set_num_ulmov(oldnumreg);
      }
      const char sezione = rmov.get(RMV_SEZIONE)[0];
      real importo(rmov.get(RMV_IMPORTO));

      sal.aggiorna(gruppo, conto, sottoconto, importo, sezione);
    }
    rmov.next();
    prnd.addstatus(1);
    do_events();
  }

  if (sal.items() > 0)
    sal.registra();

  remove("__sal__.sav");
  saldi.close();
  return TRUE;
}


int cg4100(int argc, char* argv[])
{
  CG4100_App main_app;
  main_app.run(argc, argv, "Ricalcolo Saldi");
  return TRUE;
}

