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

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

//#if XVT_OS == XVT_OS_SCOUNIX
#include <signal.h>
//#endif

#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"

// for access()
#if XVT_OS == XVT_OS_DOS || XVT_OS == XVT_OS_WIN
#include <io.h>
#else
#include <unistd.h>
#endif

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

class CG4100_App : public TApplication
{
  TString _year;

public:
  
  virtual bool create();
  virtual bool destroy();

  bool set_parms(bool year);
  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(), _year(4)
  { }
  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");

  return TRUE;
}

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

  return TApplication::destroy();
}

bool CG4100_App::set_parms(bool year)
{
  TMask m("cg4100a");

  if (!year)
    m.hide(FLD_CG41_YEAR);

  m.run();

  _year = m.get(FLD_CG41_YEAR);

  return m.last_key() == K_ENTER;
}


bool CG4100_App::menu(MENU_TAG m)
{
  switch (m)
  {
  case BAR_ITEM(1):
    sort_mov();
    break;
  case BAR_ITEM(2):
    sort_sal();
    break;
  }
  return TApplication::menu(m);
}


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(FALSE))
    return FALSE;

  TSystemisamfile mov(LF_MOV);
  TSystemisamfile rmov(LF_RMOV);
  TSystemisamfile rmoviva(LF_RMOVIVA);

  if (mov.open(_excllock) || rmov.open(_excllock) ||
      rmoviva.open(_excllock))
  {
    warning_box("Gli archivi sono in uso. Operazione interrotta");
    return FALSE;
  }

  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.NUMDOC  - (char*)&rbuf, 6);
  sort.addsortkey(rbuf.DATADOC - (char*)&rbuf, 8);

  sort.init();

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


  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);
    strcpy(rbuf.NUMDOC,  mov.get(MOV_NUMDOC));
    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);


      while (!rmov.eof() && rgn == rmov.get(RMV_NUMREG))
      {
        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);

      while (!rmoviva.eof() && rgn == rmoviva.get(RMV_NUMREG))
      {
        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(TRUE))
    return FALSE;

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

  TLocalisamfile rmov(LF_RMOV);
  TLocalisamfile mov(LF_MOV);
  TLocalisamfile causali(LF_CAUSALI);
  TSaldo_agg sal;
  int gruppo, conto;
  const int year = atoi(_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);
  while (!rmov.eof())
  {
    if (_year == rmov.get(RMV_ANNOES))
    {
      const long 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)
      {
        oldnumreg = numreg;
        mov.zero();
        mov.put(MOV_NUMREG, numreg);
        mov.read();
        CHECK(mov.good(),"Archivi movimenti e righe inconsistenti");

        const char* codcaus = mov.get(MOV_CODCAUS); 

        // cerca causale
        causali.zero();
        if (*codcaus)
        {
          causali.put(CAU_CODCAUS, codcaus);
          causali.read();
          CHECK(causali.good(),"Archivi causali e movimenti inconsistenti");
        }
      }
      const char sezione = rmov.get(RMV_SEZIONE)[0];
      real importo(rmov.get(RMV_IMPORTO));

      sal.set_movap(causali.get(CAU_MOVAP) == "A");
      sal.set_movprovv(mov.get(MOV_PROVVIS).not_empty());
      sal.aggiorna(gruppo, conto, sottoconto, importo, sezione);
      if (sal.items() > MAX_CNT)
      {
        sal.registra();
        sal.reset();
        sal.set_anno_es(atoi(_year));
      }
    }
    rmov.next();
    prnd.addstatus(1);
    do_events();
  }
  if (sal.items() > 0)
    sal.registra();
  remove("__sal__.sav");
  return TRUE;
}


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