#include "halib.h"
#include "hacnvlib.h"
#include "hacnv400a.h"

#include <applicat.h>
#include <automask.h>
#include <progind.h>
//#include <reprint.h>
//#include <reputils.h>
//#include <tabutil.h>
#include <utility.h>

#include "../mg/mglib.h"
#include "../mg/movmag.h"
#include "../mg/rmovmag.h"

const char* const APPNAME = TR("Conversione movimenti di magazzino"); 

///////////////////////////////////////////////////////////
// Movimenti di magazzino
///////////////////////////////////////////////////////////

class THardy_movmag : public THardy_transfer
{
  int _anno;              // parametri per la query
  TDate _dadata, _adata;  // parametri per la query
  int _protocollo;        // numero protocollo del mov.mag. 
  TToken_string _cauape; // causali di magazzino per apertura

protected:
  bool scrivi_righe(TMov_mag& mov);
  bool scrivi_righe_lotti(TMov_mag& mov, const TRecordset& rigamov);
  bool scrivi_testata(const TRecordset& recset, TMov_mag& mov);
  void recset2rec(const TODBC_recordset& recset, TRectype& rec, const TString_array& lista_campi);
  void conto2campo(const TString& hd_tipoc, const TString& hd_key, TString4& tipoc, int& gr, int& co, long& so);
  void get_lotto(const int kmovmag, TString& idlotto);
public:
  virtual bool trasferisci();
  THardy_movmag(const int anno, const TDate dadata, const TDate adata);
};

// carica il record campo con il record hardy in base alla configurazione 
void THardy_movmag::recset2rec(const TODBC_recordset& recset, TRectype& rec, const TString_array& lista_campi)
{
	TString campo_dest, campo_orig, valore, str;
	FOR_EACH_ARRAY_ROW(lista_campi,i,row)
	{
		row->get(0, campo_dest); 
		row->get(1, campo_orig);
		if (campo_orig.full())
		{
			if (campo_orig[0] == '_')
			{
        if (campo_orig.starts_with("_SCONTO")) // � uno sconto (ca..o!)
        {
          valore.cut(0);
          real sconto;
          TString8 field;
        	for (int i = 1; i < 6; i++)
          {
            field.format("Sconto%1d",i);
            sconto = get_real(field);
            sconto.round(2);
            if (sconto != ZERO)
            {
              valore << sconto.string();
              valore << "+";
            }
          }
          if (valore.len()>0)
            valore = valore.left(valore.len()-1);
        } else
        if (campo_orig.starts_with("_REAL")) // � un real
        {
          const TString80 campo = campo_orig.after(','); 
          real r = recset.get(campo).as_real();
          valore = r.string();
        } else
        if (campo_orig.starts_with("_ROUND")) // arrotondo a due decimali
        {
          const TString80 campo = campo_orig.after(','); 
          real contenuto = recset.get(campo).as_real();
          contenuto.round(2);
          valore = contenuto.string();
        } else
        if (campo_orig.starts_with("_FISSO")) // valore fisso indicato in configurazione 
        {
  			  valore = campo_orig.after(','); 
          valore.trim();
        } else
				if (campo_orig.starts_with("_STREXPR")) // formato _STREXPR, espressione
				{
          TExpression expr(campo_orig.after(','), _strexpr);
          for (int v = 0; v < expr.numvar(); v++)
          {
            const char* varname = expr.varname(v);
            expr.setvar(v, recset.get(varname).as_string());
          }
  			  valore = expr.as_string();
          valore.trim();
				}	else 
				if (campo_orig.starts_with("_TAB")) // formato _TAB,<tabella da leggere>,<valore CODTAB>, <campo da leggere>
				{
  				TToken_string elabora(campo_orig, ',');
					const TString4 tab = elabora.get(1); // tabella da leggere
          const TString16 codtab = recset.get(elabora.get()).as_string();
					const TString16 campotab = elabora.get();
					valore = cache().get(tab, codtab, campotab);
        } else
				if (campo_orig.starts_with("_TRADUCI"))
        {
          const TString80 campo = campo_orig.after(','); 
          const TString80 contenuto = recset.get(campo).as_string();
         	TConfig& ini = config();
          valore = ini.get(contenuto,campo);
        }
        else
          valore.cut(0);
      }
      else
        valore = recset.get(campo_orig).as_string();
			rec.put(campo_dest, valore);
		}
	}
}

// calcola conto campo a partire da conto hardy
void THardy_movmag::conto2campo(const TString& hd_tipoc, const TString& hd_key, TString4& tipoc, int& gr, int& co, long& so)
{
  TConfig& ini = config();
  char tipocc = hd_tipoc[0];
  switch (tipocc)
  {      
  case 'S':
    {
      tipoc = " ";
      hd_key2conto(hd_key, gr, co, so);
    }
    break;
  case 'C':
    {       
      tipoc = "C";
      so = hd_key2cli(hd_key);
      TToken_string key(tipoc);
      key.add(so);
      const TRectype rec_cf = cache().get(LF_CLIFO, key);
      gr = rec_cf.get_int(CLI_GRUPPO);
      co = rec_cf.get_int(CLI_CONTO);
      if (gr == 0)
      {
        gr = ini.get_int("CLI_GRUPPO", "Parametri");
        co = ini.get_int("CLI_CONTO", "Parametri");
      }
    }
    break;
  case 'F':
    {
      tipoc = "F";
      so = hd_key2for(hd_key);
      TToken_string key(tipoc);
      key.add(so);
      const TRectype rec_cf = cache().get(LF_CLIFO, key);
      gr = rec_cf.get_int(CLI_GRUPPO);
      co = rec_cf.get_int(CLI_CONTO);
      if (gr == 0)
      {
        gr = ini.get_int("FOR_GRUPPO", "Parametri");
        co = ini.get_int("FOR_CONTO", "Parametri");
      }
    }
    break;
  default:
    break;
  }
}

bool THardy_movmag::scrivi_testata(const TRecordset& recset, TMov_mag& mov)
{
  // cliente/fornitore
  const TString& key = recset.get("IdConto").as_string(); 
  TString4 hdtipoc = recset.get("IdContoTp").as_string();
  TString4 tipoc = " ";
  int gr, co;
  long so;
  gr = 0;
  co = 0;
  so = 0;
  conto2campo(hdtipoc, key, tipoc, gr, co, so);
  mov.zero();
  mov.put(MOVMAG_ANNOES, recset.get("Esercizio").as_int());
  mov.put(MOVMAG_DATAREG, recset.get("DataMovimento").as_string());
  mov.put(MOVMAG_DATACOMP, recset.get("DataCompetenza").as_string());
  mov.put(MOVMAG_CODCAUS, recset.get("IdCausale").as_string());
  mov.put(MOVMAG_TIPOCF, tipoc);
  mov.put(MOVMAG_CODINDSP, recset.get("IdDestinazione").as_string());
  mov.put(MOVMAG_CODCF, so);
  mov.put(MOVMAG_NUMREGST, recset.get("ProtGiornale").as_int());
  mov.put(MOVMAG_EXNUMDOC, recset.get("Protocollo").as_string());
  TString80 descr = "Rif.Doc. ";
  descr << recset.get("DataDocumento").as_string();
  descr << " ";
  descr << recset.get("RifDocumento").as_string();
  mov.put(MOVMAG_DESCR, descr);
  return true;
}

// legge righe del movmag e le scrive nel TMov_mag
bool THardy_movmag::scrivi_righe(TMov_mag& mov)
{
  TString query_righe;
  query_righe << query_header();
  query_righe << "SELECT * "
	         "FROM dbo.MovMagazzino "
           "WHERE Esercizio="; 
  query_righe << _anno;
  query_righe << " AND Protocollo=";
  query_righe << _protocollo;
  TODBC_recordset recset_righe(query_righe);
  TLocalisamfile rmov(LF_RMOVMAG);
  TRectype& rec_rmov = rmov.curr();

  TString8 codcaus = mov.get(MOVMAG_CODCAUS);
  for (bool ok=recset_righe.move_first();ok;ok=recset_righe.move_next())
  {
    TString8 codcaus_riga = recset_righe.get("IdCausale").as_string();
    bool ins_riga = true;
    if (_cauape.find(codcaus_riga)>=0) 
      ins_riga = !(scrivi_righe_lotti(mov, recset_righe));
    if (ins_riga)
    {
      TRectype& rmov = mov.new_row();
      TString8 codcaus_riga = recset_righe.get("IdCausale").as_string();
      if (codcaus != codcaus_riga)
        rmov.put(RMOVMAG_CODCAUS, codcaus_riga);
      const int codmag = recset_righe.get("IdMagazzino1").as_int();   
      rmov.put(RMOVMAG_CODMAG, format("%02d", codmag));
      rmov.put(RMOVMAG_CODART, recset_righe.get("IdProdotto").as_string());
      rmov.put(RMOVMAG_QUANT, recset_righe.get("Quantita").as_string());
      TString4 um = recset_righe.get("IdUmDoc").as_string();
      if (um.blank())
      {
        TString80 key = recset_righe.get("IdProdotto").as_string();
        key << "|1";
        um = cache().get(LF_UMART, key, UMART_UM);
      }
      rmov.put(RMOVMAG_UM, um);
      rmov.put(RMOVMAG_PREZZO, recset_righe.get("PrezzoMov").as_string());
      const int kmovmag = recset_righe.get("KMovmag").as_int();   
      TString80 idlotto;
      get_lotto(kmovmag, idlotto);
      rmov.put(RMOVMAG_LIVGIAC, idlotto);
    }
  } 
  return true;
}

// legge righe del movmag e le scrive nel TMov_mag
bool THardy_movmag::scrivi_righe_lotti(TMov_mag& mov, const TRecordset& rigamov)
{
  TString80 codart = rigamov.get("IdProdotto").as_string();
  int codmag = rigamov.get("IdMagazzino1").as_int();
  TString query_lotti;
  query_lotti << query_header();
  query_lotti << "SELECT * "
	         "FROM dbo.LottiSaldi "
           "WHERE Esercizio="; 
  query_lotti << _anno;
  query_lotti << " AND IdProdotto=";
  query_lotti << codart;
  query_lotti << " AND IdMagazzino=";
  query_lotti << codmag;
  query_lotti << " AND RIQta<>0";
  TODBC_recordset recset_lotti(query_lotti);
  TLocalisamfile rmov(LF_RMOVMAG);
  TRectype& rec_rmov = rmov.curr();
  for (bool ok=recset_lotti.move_first();ok;ok=recset_lotti.move_next())
  {
    TRectype& rmov = mov.new_row();
    rmov.put(RMOVMAG_CODMAG, format("%02d", codmag));
    rmov.put(RMOVMAG_CODART, codart);
    rmov.put(RMOVMAG_QUANT, recset_lotti.get("RIQta").as_string());
    TString4 um = rigamov.get("IdUmDoc").as_string();
    if (um.blank())
    {
      TString80 key = codart;
      key << "|1";
      um = cache().get(LF_UMART, key, UMART_UM);
    }
    rmov.put(RMOVMAG_UM, um);
    rmov.put(RMOVMAG_PREZZO, rigamov.get("PrezzoMov").as_string());
    rmov.put(RMOVMAG_LIVGIAC, recset_lotti.get("IdLotto").as_string());
  } 
  return (recset_lotti.items()>0);
}

void THardy_movmag::get_lotto(const int kmovmag, TString& idlotto)
{
  TString query_lotto;
  query_lotto << query_header();
  query_lotto << "SELECT * "
	         "FROM dbo.DettQtaDoc "
           "WHERE KRigoDoc=";
  query_lotto << kmovmag;
  TODBC_recordset recset_lotto(query_lotto);
  for (bool ok=recset_lotto.move_first();ok;ok=recset_lotto.move_next())
    idlotto = recset_lotto.get("IdLotto").as_string();
}

// procedura principale di conversione
bool THardy_movmag::trasferisci()
{
  TConfig& ini = config();
  _cauape = ini.get("APERTURA", "CausaliMagazzino");

  // query su testate movimenti 
  TString16 dastr, astr;
  dastr.format("%4d-%2d-%2d", _dadata.year(), _dadata.month(), _dadata.day());
  astr.format("%4d-%2d-%2d", _adata.year(), _adata.month(), _adata.day());

  TString query = 
    "SELECT * "
		"FROM dbo.MovMagazzinoT "
    "WHERE Esercizio=";
  query << _anno;
  query << " AND DataMovimento>= '";
  query << dastr;
  query << "' AND DataMovimento<= '";
  query << astr;
  query << "' ORDER BY DataMovimento ";

  TRecordset& recset = create_recordset(query);
  TMov_mag mov;
  TLocalisamfile movmag(LF_MOVMAG);
  THardy_iterator hi(this);
  while (++hi)
  {
    _protocollo = recset.get("Protocollo").as_int(); // numero protocollo testata
    scrivi_testata(recset, mov);
    scrivi_righe(mov);
    mov.write(movmag);
  }
  return true;
}

THardy_movmag::THardy_movmag(const int anno, const TDate dadata, const TDate adata) : _anno(anno), _dadata(dadata), _adata(adata)
{
}

///////////////////////////////////////////////////////////
// TConvMovMagHardy_mask
///////////////////////////////////////////////////////////

class TConvMovMagHardy_mask : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  void serialize(bool bSave);

public:
  void trasferisci();

  TConvMovMagHardy_mask();
  virtual ~TConvMovMagHardy_mask();
};

// Funzione di trasferimento dati da/verso file .ini con lo stesso nome della maschera
// Andrebbe messo in libreria
void TConvMovMagHardy_mask::serialize(bool bSave)
{
  TFilename n = source_file(); n.ext("ini");  // Construisce il nome del .ini in base al .msk
  TConfig cfg(n, "Main");                     // Crea il file di configurazione
  TString4 id; 
  for (int i = fields()-1; i >= 0; i--)       // Scandisce tutti i campi della maschera ...   
  {
    TMask_field& f = fld(i);
    if (f.active() && f.is_loadable())        // ... selezionando solo quelli editabili
    {
      id.format("%d", f.dlg());
      if (bSave)                              // A seconda del flag di scrittura ... 
        cfg.set(id, f.get());                 // ... o scrive sul .ini 
      else 
        f.set(cfg.get(id));                   // ... o legge dal .ini
    }
  }
}

void TConvMovMagHardy_mask::trasferisci()
{
  TString query_header;
  query_header << "ODBC(" << get(F_DSN) << ',' << get(F_USR) << ',' << get(F_PWD) << ")\n";

  const int anno = get_int(F_ANNO);
  const TDate dadata = get_date(F_DADATA);
  const TDate adata = get_date(F_ADATA);
  if (anno!=0)
  {
    THardy_log log;
    THardy_movmag pc(anno, dadata, adata);
    pc.init(TR("Movimenti di magazzino"), query_header, log);
    pc.trasferisci();
  }
}

bool TConvMovMagHardy_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  switch (o.dlg())
  {
  case DLG_OK:
    if (e == fe_button)
      serialize(true);
    break;
  default:
    break;
  }
  return true;
}

TConvMovMagHardy_mask::TConvMovMagHardy_mask() : TAutomask("hacnv400a")
{
  serialize(false);
}

TConvMovMagHardy_mask::~TConvMovMagHardy_mask()
{ 
}

///////////////////////////////////////////////////////////
// TConvMovMagHardy
///////////////////////////////////////////////////////////

class TConvMovMagHardy : public TSkeleton_application
{
protected:
  virtual void main_loop();
};

void TConvMovMagHardy::main_loop()
{
  TConvMovMagHardy_mask mask;
  while (mask.run() == K_ENTER)
    mask.trasferisci();
}

int hacnv400(int argc, char* argv[])
{
  TConvMovMagHardy ih;
  ih.run(argc, argv, APPNAME);
  return 0;
}