#include <execp.h>
#include <progind.h>

#include <pconti.h>

#include "../cg/cg2101.h"
#include "calib01.h"
#include "../ve/velib04.h"

#include "fasi.h"
#include "movana.h"
#include "rmovana.h"
#include "rip.h"
#include "rrip.h"

#include "cacnva.h"

#define usage "Errore - uso : cacnv [0|1]"

//--------------------------------------------------------------
//    IMPORTO DESCRITTO (utilizzato nella conversione movimenti)
//--------------------------------------------------------------
class TImporto_descritto : public TImporto
{
  TString _descr;
public:
  const TString& descrizione() const {return _descr;}
  TImporto_descritto(const char* descr) : _descr(descr) {}
};

//----------------------------------------------------------
//    MASCHERA COVERSIONE
//----------------------------------------------------------
class TConversione_anal_msk : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);

public:
  TConversione_anal_msk() : TAutomask("cacnva") {}
};

bool TConversione_anal_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
  switch (o.dlg())
  {
  case F_DATAINI:
    if (e == fe_init)
    {
      const TDate data_att = ca_config().get("DtAttCa");
      if (data_att.ok())
        o.set(data_att.string());
    }
    if (e == fe_modify || e == fe_close)
    {
      //controllo sulla data attivazione Contabilita' analitica nel file di configurazione
      const TDate data_att = ca_config().get("DtAttCa");
      if (data_att.ok())
      {
        const TDate& dataini = get_date(F_DATAINI);
        if (dataini < data_att)
          return error_box(TR("La data inizio non puo' essere antecedente la data di attivazione"));
      }
    }
    break;
  case F_TIPOCONV:
    if (e == fe_modify)
    {
      const TDate data_att = ca_config().get("DtAttCa");
      set(F_DATAINI, data_att);
    }
    break;
  default: break;
  }  
  return true;
}

//---------------------------------------------------------
//    RIPARTITORE
//---------------------------------------------------------

class TAnal_rip : public TMultiple_rectype
{
public:
  TAnal_rip();
};

TAnal_rip::TAnal_rip() : TMultiple_rectype(LF_RIP)
{
  add_file(LF_RRIP, RRIP_NRIGA);
}
//----------------------------------------------------------
//    APPLICAZIONE
//----------------------------------------------------------

class TConversione_cm2ca : public TSkeleton_application
{
  virtual const char * extra_modules() const {return "cm";} //funziona anche con autorizzazione CM
  TCache_ripartizioni _cache_rip;

protected:
  virtual void main_loop();
  void create_new_movana(long numreg_cg, bool definitiva, TAssoc_array& cg_lines_to_anal);
  bool test_configuration();
  void ripartisci(TRectype& recpcon);
  void check_phase(const TRectype& analriga);

public:
  bool convert_clerks();
  bool convert_phases();
  bool set_anal();
  bool convert_movs(TConversione_anal_msk& mask);

  TConversione_cm2ca() {}
  ~TConversione_cm2ca() {}
};

bool TConversione_cm2ca::test_configuration()
{
  const TString& first_level = ca_config().get("Level(1)");
  return first_level.not_empty();
}

//gestione del menu (vari tipi di conversione)
void TConversione_cm2ca::main_loop()
{
  TConversione_anal_msk mask;
  while (mask.run() == K_ENTER)
  {
    if (mask.get_bool(F_TABELLE))
    {
      if (set_anal()) //setta il flag anal nel pcon
      {
        convert_clerks(); //da tabella cms a commesse
        convert_phases(); //da tabella fsc a fasi
      }
    }

    if (mask.get_bool(F_MOVIMENTI))
    {
      //controlla se compilata la configurazione della CA dul ditta.ini
      bool ok = test_configuration();
      if (!ok)
      {
        if (yesno_box(TR("Per procedere alla conversione e' necessario avere configurato\nla Contabilita' Analitica\nSi desidera procedere alla configurazione?")))
        {
          TExternal_app app("ca0 -2");
          app.run();
          ok = test_configuration();
        }
      }
      //solo se e' stata fatta la configurazione minima e' possibile procedere alla conversione
      if (ok)
        convert_movs(mask); //converte i movimenti di contabilita' (da CG a CA)
    } //end get_bool(F_MOVIMENTI)
  } //end while

}


//-------------------------------------------------
//  ** TRASFERIMENTO DATI COMMESSE/FASI **
//-------------------------------------------------
//------------------------------------------------------------------------------------------------
// trasferisce i dati dalle tabelle Commesse e Fasi ai nuovi file di analitica (COMMESSE e FASI) 
//------------------------------------------------------------------------------------------------
bool TConversione_cm2ca::convert_clerks()
{
  TLocalisamfile commesse(LF_COMMESSE); //la conversione blocca in automatico gli altri utenti
                                      //non e' necessario un TSystemisamfile con _excllock
  const long items = commesse.items();
  //trasferimento dati possibile solo se il file di destinazione e' vuoto
  if (items > 0)
  {
    if (yesno_box(TR("File delle commesse non vuoto!\nSi desidera azzerarlo?")))
      if (yesno_box(TR("File delle commesse non vuoto!\nSi desidera veramente azzerarlo?")))
      {
        TSystemisamfile cms(LF_COMMESSE); //sono zappabili solo i Systemisamfiles
        cms.zap();
      }
      else
        return true;
    else
      return true;
  }

  TRelation relcms("CMS");
  TCursor curcms(&relcms);
  const TRectype& cms = relcms.curr();
  const long nrectab = curcms.items();
  curcms.freeze();
  TRectype& commesse_rec = commesse.curr();
  TProgind pi(nrectab, "Conversione tabella commesse");
  for (curcms = 0; curcms.pos() < nrectab; ++curcms)
  {
    pi.addstatus(1);
    commesse_rec.zero();  //azzerare il record prima di cominciare...
    commesse_rec.put("CODCMS", cms.get("CODTAB"));
    commesse_rec.put("DESCRIZ", cms.get("S0"));
    commesse_rec.put("CODCF", cms.get("I0"));
    commesse_rec.put("REGIVA", cms.get("S7"));
    commesse_rec.put("PUBBLICA", cms.get("B0"));
    commesse_rec.put("RENDIC", cms.get("B1"));
    commesse_rec.put("DATAINIZIO", cms.get("D0"));
    commesse_rec.put("DATAFINE", cms.get("D1"));
    commesse_rec.put("CHIUSA", cms.get("B2"));
    commesse_rec.put("PROROGA", cms.get("B4"));
		commesse_rec.put("DATAPROR", cms.get("D2"));
    commesse_rec.put("CODRESP", cms.get("S4"));

    commesse.write();
   }
   return true;
}

bool TConversione_cm2ca::convert_phases()
{
  //se sono gia' state configurate le fasi nel ditta.ini non procede oltre!
  //fara' la conversione delle fasi nel trasferimento dei movimenti
  const TString& fathfasi = ca_config().get( "FathFasi");
  if (fathfasi.not_empty())
    return false;

  TLocalisamfile fasi(LF_FASI);
  const long items = fasi.items();
  if (items > 0)
  {
    if (yesno_box(TR("File delle fasi non vuoto!\nSi desidera azzerarlo?")))
      if (yesno_box(TR("File delle fasi non vuoto!\nSi desidera veramente azzerarlo?")))
      {
        TSystemisamfile fsc(LF_FASI);
        fsc.zap();
      }
      else
        return true;
    else
      return true;
  }

  TRelation relfsc("FSC");
  TCursor curfsc(&relfsc);
  const TRectype& fsc = relfsc.curr();
  const long nrectab = curfsc.items();
  curfsc.freeze();
  TRectype& fasi_rec = fasi.curr();
  TProgind pi(nrectab, "Conversione tabella fasi");

  TRelation* relazione = NULL;
  TCursor* cursore = NULL;

  for (curfsc = 0; curfsc.pos() < nrectab; ++curfsc)
  {
    pi.addstatus(1);
    if (cursore == NULL)
    {
      fasi_rec.zero();
      fasi_rec.put("CODFASE", fsc.get("CODTAB"));
      fasi_rec.put("DESCRIZ", fsc.get("S0"));
      fasi.write();
    }
  }
  return true;
}

//------------------------------------------------------------------------------------------------
// mette il flag di ANALITICA nei gr.co.stc. aventi codcms e/o codfsc
//------------------------------------------------------------------------------------------------
void TConversione_cm2ca::ripartisci(TRectype& recpcon)
{
  const int gruppo = recpcon.get_int(PCN_GRUPPO);
  const int conto = recpcon.get_int(PCN_CONTO);
  const long sottoconto = recpcon.get_long(PCN_SOTTOCONTO);
  const TString80 codcms = recpcon.get(PCN_CODCMS);
  const TString16 fascms = recpcon.get(PCN_FASCMS);

	if (codcms.empty() && fascms.empty())
		return;
		//cerca nel file rip se esiste gia' un record con la medesima chiave (chiave 3!!)
  TLocalisamfile rip_file(LF_RIP);
	rip_file.last();
  rip_file.put(RIP_TIPO, "I");
  rip_file.put(RIP_CODICE, "ZZZZZZZZ");
	if (rip_file.read(_isgreat) == NOERR)
		rip_file.prev();
	const long last_cod = atol(rip_file.get(RIP_CODICE)) + 1L;
  rip_file.setkey(3);

  rip_file.put(RIP_GRUPPO, gruppo);
  rip_file.put(RIP_CONTO, conto);
  rip_file.put(RIP_SOTTOCONTO, sottoconto);

  if (rip_file.read() != NOERR)
  {
    TAnal_rip rip;
		TString80 cod;

    cod.format("%08ld", last_cod);
		rip.head().put(RIP_TIPO, "I");
		rip.put(RIP_CODICE, cod);
    rip.put(RIP_GRUPPO, gruppo);
    rip.put(RIP_CONTO, conto);
    rip.put(RIP_SOTTOCONTO, sottoconto);


    TRectype& rrip = rip.new_row();
    rrip.put(RRIP_RIPARTO, 100);
    rrip.put(RRIP_CODCMS, codcms);
    rrip.put(RRIP_CODFASE, fascms);
    if (ca_config().get_bool("UsePdcc"))  //solo se in CA si usa il piano dei conti contabile..
		{
			TString80 codconto;

			codconto.format("%03d%03d%06ld", gruppo, conto, sottoconto);
			rrip.put(RRIP_CODCONTO, codconto);
		}

    rip.write();  //scrive sia rip che rrip con nuova chiave 1 (TIPO+CODICE)
  }

}

bool TConversione_cm2ca::set_anal()
{
  TRelation relpcon(LF_PCON);
  TCursor curpcon(&relpcon);
  TRectype& recpcon = relpcon.curr();

  if (!recpcon.exist(PCN_ANALITICA)) //check se gia' avvenuta la conversione con aggiunta del campo ANAL
    return error_box(TR("Prima del controllo e' necessario eseguire una conversione archivi"));
  else
  {
    const long nrecpcon = curpcon.items();
    curpcon.freeze();
    TProgind pi(nrecpcon, "Controllo commesse e fasi sul piano dei conti");
    for (curpcon = 0; curpcon.pos() < nrecpcon; ++curpcon)
    {
      pi.addstatus(1);
      if (recpcon.get(PCN_CODCMS).not_empty() || recpcon.get(PCN_FASCMS).not_empty())
      {
        recpcon.put(PCN_ANALITICA, "X");
        relpcon.rewrite();
        //deve creare una testata e una riga di ripartizione (se non esistono con lo stesso gr/co/sott)
        ripartisci(recpcon);
      }
    }
    return true;
  }
}

//----------------------------------------------------------
//  ** CONVERSIONE MOVIMENTI CONTABILI **
//----------------------------------------------------------

//----------------------------------------------------------------------------------------------------
// trasferisce i movimenti e le righe relative (MOV,RMOV) nei nuovi file di analitica (MOVANA,RMOVANA)
// ---------------------------------------------------------------------------------------------------
void TConversione_cm2ca::check_phase(const TRectype& analriga)
{
  const TString16 codfase = analriga.get(RMOVANA_CODFASE);
  if (codfase.blank())
    return;
  const TString& fathfasi = ca_config().get("FathFasi");
  if (fathfasi.blank())
    return;

  TLocalisamfile file_fasi(LF_FASI);
  if (fathfasi == "CDC")
    file_fasi.put(FASI_CODCMSFAS, analriga.get(RMOVANA_CODCCOSTO));
  else  //se non e' "CDC", il FathFasi puo' essere solo "CMS"
    file_fasi.put(FASI_CODCMSFAS, analriga.get(RMOVANA_CODCMS));

  file_fasi.put(FASI_CODFASE, codfase);

  const int err = file_fasi.read();
  if (err != NOERR)
  {
    const TString& descrfase = cache().get("FSC", codfase, "S0");
    file_fasi.put(FASI_DESCRIZ, descrfase);
    file_fasi.write();
  }
}

void TConversione_cm2ca::create_new_movana(long numreg_cg, bool definitiva, TAssoc_array& cg_lines_to_anal)
{
  TLocalisamfile f(LF_MOVANA);
	TAnal_mov analmov;  //testata movimento analitico
  //riempie le righe di testata del movimento prima nota mov
  TMovimentoPN mov;
  TRectype& mov_head = mov.curr();
  mov_head.put(MOV_NUMREG, numreg_cg);
  mov.read();

  analmov.put(MOVANA_ANNOES, mov_head.get(MOV_ANNOES));
  analmov.put(MOVANA_DATAREG, mov_head.get(MOV_DATAREG));
  analmov.put(MOVANA_DATACOMP, mov_head.get(MOV_DATACOMP));
  analmov.put(MOVANA_DATADOC, mov_head.get(MOV_DATADOC));
  analmov.put(MOVANA_NUMREGCG, mov_head.get(MOV_NUMREG));
  analmov.put(MOVANA_NUMDOC, mov_head.get(MOV_NUMDOC));
  analmov.put(MOVANA_TIPODOC, mov_head.get(MOV_TIPODOC));
  analmov.put(MOVANA_DESCR, mov_head.get(MOV_DESCR));
  analmov.put(MOVANA_CODCAUS, mov_head.get(MOV_CODCAUS));
	if (definitiva)
		analmov.put(MOVANA_TIPOMOV, " "); 
	else
		analmov.put(MOVANA_TIPOMOV, "T"); //deve mettere "Temporaneo" (conversione NON definitiva)

	const char provv = mov_head.get_char(MOV_DPROVV);
	analmov.put(MOVANA_DPROVV, provv);
	const int danno = mov_head.get_int(MOV_DANNO);
	analmov.put(MOVANA_DANNO, danno);
	const TString4 dcodnum = mov_head.get(MOV_DCODNUM);
	analmov.put(MOVANA_DCODNUM, dcodnum);
	const long dndoc = mov_head.get_long(MOV_DNDOC);
	analmov.put(MOVANA_DNDOC, dndoc);
	
  //MOVANA_TOTDOC e' il totale di tutte le sue righe;ancora non si conosce;sara' compilato..
  //..successivamente utilizzando importone

  //deve scorrere tutte le righe del movimento e sommare gli importi di quelle che hanno la..
  //..stessa chiave CODCMS+CODFSC
  TAssoc_array righe_cms; //array con le righe del movimento che sono da trasferire
  TToken_string chiave;

  //scansione righe movimentoPN 
  for (int l = 0;  l < mov.cg_items(); l++)
  {
    const TRectype& rmov = mov.cg(l);
    chiave = "";
    chiave.add(rmov.get("CODCMS"));
    chiave.add(rmov.get("FASCMS"));

    //se ci sono la commessa e/o la fase nella riga movimento e la riga iva non e' tipo T..
    //..procede al calcolo dell'importo
    if (!chiave.empty_items() && rmov.get(RMV_ROWTYPE) != "T")
    {
      //alla chiave va aggiunto il vecchio gr/co/stc
      TString16 conto_cg;
      conto_cg.format("%03d|%03d|%06ld", rmov.get_int(RMV_GRUPPO), rmov.get_int(RMV_CONTO), rmov.get_long(RMV_SOTTOCONTO));
      chiave.add(conto_cg);
      TImporto_descritto* importo = (TImporto_descritto*)righe_cms.objptr(chiave);
      if (importo == NULL)  //la chiave non esisteva nell'assoc
      {
        importo = new TImporto_descritto(rmov.get(RMV_DESCR)) ;
        righe_cms.add(chiave, importo);
      }
      const char sezione = rmov.get_char(RMV_SEZIONE);
      const real valore = rmov.get(RMV_IMPORTO);
      *importo += TImporto(sezione, valore);  //crea un importo e lo somma a quello dell'array

      //aggiunge gr/co/sottoc all'assoc_array dei conti da trasformare in analitici sul piano dei conti
      cg_lines_to_anal.add(conto_cg, NULL);
    }
  }

  TImporto importone; //importo totale del movimento (totale di testata)

  FOR_EACH_ASSOC_OBJECT(righe_cms, m, n, a) //giro sull'assoc array delle righe movimento da trasferire
  {
    //aggiunge l'importo della riga all'importo totale
    TImporto_descritto& importo = *(TImporto_descritto*)a;
    importo.normalize();
    importone += importo;

    chiave = n; //chiave = commessa|fase|gruppo|conto|sottoconto
    const int gruppo = chiave.get_int(2);
    const int conto = chiave.get_int();
    const long sottoconto = chiave.get_long();
		const TBill zio(gruppo, conto, sottoconto);
    //controlla se il gr/co/stc del movimento deve essere ripartito;in caso affermativo procede..
    //..alla ripartizione delle righe del movimento
    //Per prima cosa crea l'array delle righe di ripartizione con questo gr/co/stc/annoes
		const int annoes = mov_head.get_int(MOV_ANNOES);
    const TAnal_ripartizioni_batch& rrip = _cache_rip.righe(zio, annoes);

    const int righe_ripartizione = rrip.rows();
    const bool ripartisci = righe_ripartizione > 0;

    if (ripartisci)  //ci sono righe ripartizione: da 1 riga mov CG a N righe mov CA
    {
      // Importo totale da distribuire arrotondato ai decimali della valuta di conto
      TGeneric_distrib distrib(importo.valore(), TCurrency::get_firm_dec());

      // Calcola tutte le percentuali da ripartire
      int i;
      for (i = 1; i <= rrip.rows(); i++)
        distrib.add(rrip[i].get_real(RRIP_RIPARTO));

      //Compila le righe del movimento di analitica in base alle righe ripartizione
      for (i = 1; i <= rrip.rows(); i++)
      {
        const TRectype& riga_rip = rrip.row(i);

        TRectype& analriga = analmov.new_row();
        const real imp = distrib.get(); // Legge la quota da distribuire
        analriga.put(RMOVANA_SEZIONE, importo.sezione());
        analriga.put(RMOVANA_IMPORTO, imp);  //e la mette nella nuova riga
        analriga.put(RMOVANA_DESCR, importo.descrizione());

        analriga.put(RMOVANA_ANNOES, analmov.get(MOVANA_ANNOES));
        analriga.put(RMOVANA_DATACOMP, analmov.get(MOVANA_DATAREG));

        //parametri da prendere dalle righe ripartizione!!
        analriga.put(RMOVANA_CODCCOSTO, riga_rip.get(RRIP_CODCOSTO));
        analriga.put(RMOVANA_CODCMS, riga_rip.get(RRIP_CODCMS));
        analriga.put(RMOVANA_CODFASE, riga_rip.get(RRIP_CODFASE));
        analriga.put(RMOVANA_CODCONTO, riga_rip.get(RRIP_CODCONTO));
        
        //controlla la coppia fase/(cdc-commessa) e decide se aggiungerla al file delle fasi
        check_phase(analriga);
      }
    }
    else  //nessuna riga ripartizione -> da 1 riga movimento CG ad 1 riga movimento CA
    {
      if (ca_config().get_bool("UsePdcc"))  //solo se in CA si usa il piano dei conti contabile..
      {                                       //..e' possibile costruire la riga movimento
        //Compila la riga del movimentodi analitica
        TRectype& analriga = analmov.new_row();

        analriga.put(RMOVANA_SEZIONE, importo.sezione());
        analriga.put(RMOVANA_IMPORTO, importo.valore());
        analriga.put(RMOVANA_DESCR, importo.descrizione());

        analriga.put(RMOVANA_ANNOES, analmov.get(MOVANA_ANNOES));
        analriga.put(RMOVANA_DATACOMP, analmov.get(MOVANA_DATAREG));

        analriga.put(RMOVANA_CODCMS, chiave.get(0));
        analriga.put(RMOVANA_CODFASE, chiave.get(1));

        TString16 codconto;
        codconto.format("%03d%03d%06ld", gruppo, conto, sottoconto);
        analriga.put(RMOVANA_CODCONTO, codconto);

        //controlla la coppia fase/(cdc-commessa) e decide se aggiungerla al file delle fasi
        check_phase(analriga);
      }
      else  //qui va aggiunta la lista dei conti che non hanno ripartizione quando NON si usa il..
            //..piano dei conti contabile in analitica
        error_box(TR("Manca la ripartizione di un conto"));
    }
  } //end FOR_EACH..

  //e alla fine riesce a mettere anche l'importone in testata
  importone.normalize();  //x evitare problemi di segno...
  analmov.put(MOVANA_SEZIONE, importone.sezione());
  analmov.put(MOVANA_TOTDOC, importone.valore());

  //Seconda parte del trasferimento: compatta e riscrive i movimenti(+righe) originali!
  //Se e' riuscita la scrittura dei movimenti di analitica (MOVANA,RMOVANA)ed e' una conversione..
  //..DEFINITIVA,riordina le righe e le testate dei movimenti originari (MOV,RMOV,RMOVIVA).. 
  //..riscrivendole
  if (analmov.write(f) == NOERR && definitiva)
	{
		//se la chiave del documento origine e' completa puo' completare tale documento riempiendo il..
		//..campo NUMREGCA (con lo stesso numero di NUMREG di analmov, in generale != da NUMREGCG
		if (provv != ' ' && danno > 0 && dcodnum.not_empty() && dndoc > 0)
		{
			TDocumento dadoc(provv, danno, dcodnum, dndoc);
			dadoc.put(DOC_NUMREGCA, analmov.get(MOVANA_NUMREG));
			dadoc.rewrite();
		}
		//RIGHE MOVIMENTI CONTABILI
		TArray cg_records;
		for (int m = 0;  m < mov.cg_items(); m++)
		{
			const TRectype& rmov = mov.cg(m);
			int add_to = -1;
			//se la riga movimento contabile ha un ROWTYPE...
			if (rmov.get(RMV_ROWTYPE).not_empty())
			{
				//cerca nell'array dei record riga mov(cg_records) partendo dall'ultima a scalare..
				for(add_to = cg_records.last(); add_to >=0; add_to--)
				{
					//prende il record add_to-esimo..
					const TRectype& rec = (TRectype&)cg_records[add_to];
					//se i campi gr.co.sottoc. di un record dell'array(cg_records) = a quelli della riga 
					//movimento contabile in esame(rmov) -> esce con add_to = al numero del record dell'
					//array che soddisfa la condizione (quindi add_to > 0)
					if (rmov.get_int(RMV_GRUPPO) == rec.get_int(RMV_GRUPPO) && 
						rmov.get_int(RMV_CONTO) == rec.get_int(RMV_CONTO) &&
						rmov.get_long(RMV_SOTTOCONTO) == rec.get_long(RMV_SOTTOCONTO))
						break;
				}
			}
			//se add_to e' rimasto = -1 (la condizione di eguaglianza gr.co.sott. non e' stata soddisfatta 
			//da alcuna riga dell'array cg_records)..
			if (add_to < 0)
			{
				TRectype* rec = new TRectype(rmov);
				//azzera i campi codice commessa e fase in RMOV di origine...
				rec->zero("CODCMS");
				rec->zero("FASCMS");
				//e aggiunge all'array cg_records il nuovo record ripulito
				cg_records.add(rec);
				rec->put(RMV_NUMRIG, cg_records.items());
			}
			//se ivece add_to > 0 (vedi test su condizione gr.co.sott. sopra)..
			else
			{
				//prende il record(rec) dell'array che soddsfaceva la condizione e somma ad esso importo e sezione
				//di quello in esame(rmov)
				TRectype& rec = (TRectype&)cg_records[add_to];
				TImporto imp_tot(rec.get_char(RMV_SEZIONE), rec.get_real(RMV_IMPORTO));
				TImporto imp_original(rmov.get_char(RMV_SEZIONE), rmov.get_real(RMV_IMPORTO));
				imp_tot += imp_original;
				imp_tot.normalize();
				rec.put(RMV_SEZIONE, imp_tot.sezione());
				rec.put(RMV_IMPORTO, imp_tot.valore());
				//notare che i campi descrittivi resteranno sempre quelli del primo record di cg_records
				//che ha gr.co.sottoc. soddisfacenti la condizione sopra!
			}
		}
		//cancella solo le righe contabili del movimento originale..
		mov.destroy_cg_row(-1);
		//e le sostituisce con le nuove che sono contenute (compattate) in cg-records
		FOR_EACH_ARRAY_ITEM(cg_records, cg_i, cg_obj)
		{
			mov.cg(cg_i) = *(TRectype*)cg_obj;
		}

		//RIGHE MOVIMENTI IVA (rifa' tutto il giochetto di prima per rmoviva)
		TArray iva_records;
		for (int n = 0;  n < mov.iva_items(); n++)
		{
			const TRectype& rmoviva = mov.iva(n);
			int add_to = -1;
			for(add_to = iva_records.last(); add_to >=0; add_to--)
			{
				const TRectype& rec = (TRectype&)iva_records[add_to];
				if (rmoviva.get_int(RMI_GRUPPO) == rec.get_int(RMI_GRUPPO) && 
					rmoviva.get_int(RMI_CONTO) == rec.get_int(RMI_CONTO) &&
					rmoviva.get_long(RMI_SOTTOCONTO) == rec.get_long(RMI_SOTTOCONTO) &&
					rmoviva.get(RMI_CODIVA) == rec.get(RMI_CODIVA) &&
					rmoviva.get_int(RMI_TIPODET) == rec.get_int(RMI_TIPODET))
					break;
			}
			if (add_to < 0)
			{
				TRectype* rec = new TRectype(rmoviva);
				rec->zero("CODCMS");
				rec->zero("FASCMS");
				iva_records.add(rec);
				rec->put(RMI_NUMRIG, iva_records.items());
			}
			else
			{
				TRectype& rec = (TRectype&)iva_records[add_to];
				//imponibile..
				real tot = rec.get_real(RMI_IMPONIBILE);
				real original = rmoviva.get_real(RMI_IMPONIBILE);
				tot += original;
				rec.put(RMI_IMPONIBILE, tot);
				//..e imposta
				tot = rec.get_real(RMI_IMPOSTA);
				original = rmoviva.get_real(RMI_IMPOSTA);
				tot += original;
				rec.put(RMI_IMPOSTA, tot);
			}
		}
		mov.destroy_iva_row(-1);

		FOR_EACH_ARRAY_ITEM(iva_records, iva_i, iva_obj)
		{
			mov.iva(iva_i) = *(TRectype*)iva_obj;
		}

		//puo' finalmente riscrivere i files di origine puliti e compattati (sia iva che non)
		mov.rewrite();
	}	//if(write=NOERR && definitiva...
}

bool TConversione_cm2ca::convert_movs(TConversione_anal_msk& mask)
{
  //scandisce il file RMOV,alla ricerca dei record con codice fase o codice commessa compilato
  TRelation rel_rmov(LF_RMOV);
  //aggiunge MOV alla relazione per avere le DATACOMP da usare nel filtro
  rel_rmov.add(LF_MOV, "NUMREG==NUMREG");
  const bool definitiva = mask.get_int(F_TIPOCONV) != 0;
  //costruzione filtro con date (in caso di conversione provvisoria)
  TString filtro;
  filtro << "((CODCMS!='')||(FASCMS!=''))&&(ROWTYPE!='T')";

  const TDate dataini = mask.get_date(F_DATAINI);
  if (dataini.ok())
    filtro << "&&(ANSI(23->DATACOMP)>=" << dataini.string(ANSI) << ")";
  const TDate datafin = mask.get_date(F_DATAFIN);
  if (datafin.ok())
    filtro << "&&(ANSI(23->DATACOMP)<=" << datafin.string(ANSI) << ")";
  
  TCursor cur_rmov(&rel_rmov, filtro);
  TRectype& rec_rmov = rel_rmov.curr();
  const long rmov_items = cur_rmov.items();
  if (rmov_items > 0)
  {
    cur_rmov.freeze();
    TProgind pi(rmov_items, "Trasferimento righe movimenti", false);

    long last_numreg_cg = 0;  //numero registrazione originaria

    TAssoc_array cg_lines_to_anal; //record array da riempire con gr/co/sott delle righe trasferite

    for (cur_rmov = 0; cur_rmov.pos() < rmov_items; ++cur_rmov)
    {
      pi.addstatus(1);
      const long curr_numreg_cg = rec_rmov.get_long(RMV_NUMREG);
      if (curr_numreg_cg != last_numreg_cg)
      {
        //se il numreg di questa riga e' nuovo -> crea un nuovo movimento di analitica (testata)
        create_new_movana(curr_numreg_cg, definitiva, cg_lines_to_anal);
        last_numreg_cg = curr_numreg_cg;
      }
    }

    //aggiorna il piano dei conti flaggando i conti "analitici"
    if (cg_lines_to_anal.items() > 0)
    {
      TLocalisamfile pcon(LF_PCON);

      FOR_EACH_ASSOC_OBJECT(cg_lines_to_anal, h, k, object)
      {
        TToken_string tok = k;
        const int gruppo = tok.get_int(0);
        const int conto = tok.get_int(1);
        const long sottoconto = tok.get_long(2);
        //cerca il record con gr/co/sottoc sul file del piano dei conti...
        pcon.put(PCN_GRUPPO, gruppo);
        pcon.put(PCN_CONTO, conto);
        pcon.put(PCN_SOTTOCONTO, sottoconto);
        //..se lo trova e non e' gia' anale...
        if (pcon.read() == NOERR && !pcon.get_bool(PCN_ANALITICA))
        {
          pcon.put(PCN_ANALITICA, "X");     //..lo analizza!..
          pcon.rewrite();   //..e lo riscrive
        }
      }
    }
  } //end if(rmov_items>0)
  return true;
}

///////////////////////////////////////////////////////////
// Programma di conversione da CM a CA
///////////////////////////////////////////////////////////

int main(int argc,char** argv)
{
  TConversione_cm2ca a;
  a.run(argc,argv, "Trasferimento dati a Contabilita' Analitica");

  return 0;
}