#include <applicat.h>
#include <automask.h>
#include <progind.h>
#include <reprint.h>
#include <tabutil.h>

#include "ps0077700.h"
#include "ps0077700a.h"

///////////////////////////////////////////////////////////
// TGalileo_log
///////////////////////////////////////////////////////////

class TGalileo_log : public TRecordset
{
  struct TGalileo_row : public TObject
  {
    TVariant _sev, _msg;
  };

  TRecnotype _cur;
  TArray _log;
  TRecordset_column_info _info[2];

public:
  virtual TRecnotype items() const;
  virtual bool move_to(TRecnotype pos);
  virtual TRecnotype current_row() const;
  virtual void requery();
	virtual const TString& query_text() const { return EMPTY_STRING; }
  virtual unsigned int columns() const;
  virtual const TRecordset_column_info& column_info(unsigned int column) const;
  virtual const TVariant& get(unsigned int column) const;

  void reset(const char* header);
  void log(long sev, const char* msg);

  TGalileo_log();
  virtual ~TGalileo_log();
};

TRecnotype TGalileo_log::items() const
{ return _log.items(); }

bool TGalileo_log::move_to(TRecnotype pos)
{
  _cur = pos;
  return pos >= 0 && pos < items();
}

TRecnotype TGalileo_log::current_row() const
{ return _cur; }

void TGalileo_log::requery()
{ _cur = -1; }

unsigned int TGalileo_log::columns() const
{ return 2; }

const TRecordset_column_info& TGalileo_log::column_info(unsigned int i) const
{ return _info[i % columns()]; }

const TVariant& TGalileo_log::get(unsigned int column) const
{
  if (_cur >= 0 && _cur < items())
  {
    const TGalileo_row& row = (const TGalileo_row&)_log[_cur];
    switch(column)
    {
    case  0: return row._sev;
    case  1: return row._msg;
    default: return NULL_VARIANT;
    }
  }
  return NULL_VARIANT;
}

void TGalileo_log::reset(const char* header)
{ 
  set_var("#HEADER", header, true);
  _log.destroy(); 
}

void TGalileo_log::log(long sev, const char* msg)
{
  TGalileo_row* row = new TGalileo_row;
  row->_sev = sev;
  row->_msg = msg;
  _log.add(row);
}

TGalileo_log::TGalileo_log() : _log(NULL)
{
  _info[0]._name = "SEVERITY";
  _info[0]._width = 1;
  _info[0]._type = _intfld;

  _info[1]._name = "MESSAGE";
  _info[1]._width = 80;
  _info[1]._type = _alfafld;
}

TGalileo_log::~TGalileo_log()
{
}

///////////////////////////////////////////////////////////
// TGalileo_iteretor
///////////////////////////////////////////////////////////

bool TGalileo_iterator::cancelled() const
{
  return _pi != NULL && _pi->iscancelled();
}

bool TGalileo_iterator::ok() const
{
  if (cancelled())
    return _pt->log_cancelled();
  return _rec >= 0 && _rec < _pt->recordset().items();
}

TGalileo_iterator& TGalileo_iterator::operator=(TRecnotype n) 
{ 
  if (_pi != NULL)
    _pi->setstatus(n+1);
  _pt->recordset().move_to(_rec = n); 
  return *this;
}

TGalileo_iterator& TGalileo_iterator::operator++() 
{ 
  return *this = ++_rec; 
}

TGalileo_iterator::TGalileo_iterator(TGalileo_transfer* pt) : _pt(pt), _pi(NULL)
{
  const TRecnotype tot = _pt->recordset().items();
  TString title;
  title << _pt->title() << ": " << tot << ' ' << TR("righe");
  if (tot > 1)
    _pi = new TProgind(tot, title, true, true);
  else
    ::begin_wait();

  if (tot > 0)
    _pt->log(title);

  _rec = -1;
}

TGalileo_iterator::~TGalileo_iterator()
{
  if (_pi != NULL)
    delete _pi;
  else
    ::end_wait();
}

///////////////////////////////////////////////////////////
// Cache tabelle
///////////////////////////////////////////////////////////

class TCache_tab : public TCache_tp
{
protected:
  virtual TObject* key2obj(const char* key);

public:
  virtual const TString& decode(const TToken_string& cod_codtab);
  TCache_tab(TGalileo_transfer* pt) : TCache_tp(pt) {}
};

const TString& TCache_tab::decode(const TToken_string& cod_codtab) 
{
  TString4 cod; cod_codtab.get(0, cod);
  if (cod.full())
  {
    const TRectype& rec = *(const TRectype*)objptr(cod_codtab); 
    if (!rec.empty())
    {
      const char* field = "CODTAB";
      if (cod == "%TPM" || cod == "%TPP" || cod == "%TPI") // Tipo trasporto e porto 
        field = "S6";
      return rec.get(field);
    }
  }
  return EMPTY_STRING;
}

TObject* TCache_tab::key2obj(const char* key)
{
  TToken_string tok(key);
  TString4 tab = tok.get();  tab.upper();
  TString80 cod = tok.get(); cod.upper();

  if (tab == "%IVA")
  {
    // Campo non digerisce i codici IVA numerici di un solo carattere
    if (isdigit(cod[0]))
      cod.right_just(2, '0'); // per cui aggiungo uno 0 iniziale
  }

  TTable table(tab);
  table.put("CODTAB", cod);
  if (table.read() != NOERR)
  {
    table.zero();
    table.put("CODTAB", cod);
    table.put("S0", cod);
    test_write((TIsamfile &)table);
  }
  return table.curr().dup();
}

///////////////////////////////////////////////////////////
// TGalileo_transfer
///////////////////////////////////////////////////////////

void TGalileo_transfer::init(const char* title, const char* qry_hdr, TGalileo_log* log)
{
  _log = log;
  _log->reset(title);
  _query_header = qry_hdr;
  _write_enabled = true;
}

const TString& TGalileo_transfer::title() const
{
  return _log->get_var("#HEADER").as_string();
}

void TGalileo_transfer::log(const char* msg, int sev) const
{
  _log->log(sev, msg);
}

TRecordset& TGalileo_transfer::create_recordset(const char* query)
{
  if (_recset != NULL)
  {
    delete _recset;
    _recset = NULL;
  }
  if (_outset != NULL)
  {
    _outset->exec("COMMIT TRANS");
    delete _outset;
    _outset = NULL;
  }

  TString qry = query;
  if (!qry.starts_with("US") && !qry.starts_with("ODBC"))
    qry.insert(query_header());
  _recset = ::create_recordset(qry);
  return *_recset;
}
  
const TRecordset& TGalileo_transfer::recordset() const
{
  CHECK(_recset != NULL, "NULL recordset");
  return *_recset;
}

TRecordset& TGalileo_transfer::recordset()
{
  CHECK(_recset != NULL, "NULL recordset");
  return *_recset;
}

long TGalileo_transfer::odbc_exec(const char* cmd)
{
  long err = 0;
  if (_write_enabled)
  {
    if (_outset == NULL)
    {
      _outset = new TODBC_recordset(query_header());
      _outset->exec("BEGIN TRANS");
    }
    err = _outset->exec(cmd);
  }
  return err;
}

bool TGalileo_transfer::log_error(const char* msg)
{
  log(msg, 2);
  if (_write_enabled)
  {
    _write_enabled = false;
    log("");
    log(TR("LA SCRITTURA SUGLI ARCHIVI VIENE DISABILITATA DA QUESTO MOMENTO IN POI"), 2);
    log("");
  }
  return false;
}

bool TGalileo_transfer::log_cancelled()
{
  return log_error(TR("Procedura interrotta dall'utente"));
}

bool TGalileo_transfer::test_write(TIsamfile& file, bool re)
{
  int err = NOERR;
  if (_write_enabled)
  {
    if (re)
      err = file.rewrite();
    else
    {
      TString80 code, desc;
      if (file.num() == LF_TAB || file.num() == LF_TABCOM)
      {
        code = file.get("CODTAB");
        desc = file.get("S0");
      }
      else
      {
        code = file.curr().build_key(1);
        desc = file.curr().build_key(2);
      }
      TString msg; 
      msg << TR("Inserimento ") << code << " (" << desc << ')'
          << TR(" nel file ") << file.num() << ' ' << file.description();
      log(msg, 1);

      err = file.write();
      if (err == _isreinsert)
      {
        msg.format(FR("Errore %d durante la scrittura sul file"), err);
        log(msg, 1);
        err = NOERR;
      }
    }
    if (err != NOERR)
    {
      TString msg; 
      msg.format(FR("Errore %d durante la scrittura sul file %d (%s)"), 
                 err, file.num(), file.description());
      log_error(msg);
    }
  }
  return err == NOERR;
}

const TString& TGalileo_transfer::get_str(const char* field) const
{
  return recordset().get(field).as_string();
}

const TString& TGalileo_transfer::get_real_str(const char* campo) const
{
  const real val = recordset().get(campo).as_real();
  if (val.is_zero())
    return EMPTY_STRING;
  return get_tmp_string() = val.string();
}

long TGalileo_transfer::get_long(const char* field) const
{
  return recordset().get(field).as_int();
}

const TString& TGalileo_transfer::decode_value(const char* tab, const TString& cod)
{
  if (cod.full())
  {
    if (_tab == NULL)
      _tab = new TCache_tab(this);
    TToken_string tok; tok.add(tab); tok.add(cod);
    return _tab->decode(tok);
  }
  return EMPTY_STRING;
}

const TString& TGalileo_transfer::decode_field(const char* tab, const char* field)
{
  const TString& cod = get_str(field);
  return decode_value(tab, cod);
}

const TString& TGalileo_transfer::build_insert_query(const char* table, const char* f, const char* v) const
{
  TString& qry = get_tmp_string();

  qry << "INSERT INTO " << table;

  TAuto_token_string fields(f);
  TToken_string values(v);
  if (fields.items() > 0)
  {
    qry << " (";
    FOR_EACH_TOKEN(fields, tok)
      qry << tok << ',';
    qry.rtrim(1);
    qry << ')';
  }
  qry << " VALUES (";

  TString tmp;
  FOR_EACH_TOKEN(values, tok)
  {
    tmp = tok;
    if (tmp.full() && !tmp.starts_with("0") && real::is_natural(tmp))
      qry << tok;
    else
    {
      if (tmp[0] != '\'')
      {
        for (int i = tmp.len()-1; i >= 0; i--)
        {
          if (tmp[i] == '\'')
            tmp.insert("'", i);
        }
        qry << '\'' << tmp << '\'';
      }
      else
        qry << tmp;
    }
    qry << ',';
  }
  qry.rtrim(1);
  qry << ')';

  return qry;
}

TGalileo_transfer::TGalileo_transfer() 
              : _log(NULL), _config("ps0077701a.ini"), _recset(NULL), _outset(NULL), _tab(NULL)
{}

TGalileo_transfer::~TGalileo_transfer()
{
  if (_tab != NULL)
    delete _tab;
  if (_outset != NULL)
  {
    _outset->exec("COMMIT TRANS");
    delete _outset;
  }
  if (_recset != NULL)
    delete _recset;
}

///////////////////////////////////////////////////////////
// TTrasferimentoGalileo_mask
///////////////////////////////////////////////////////////

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

public:
  void trasferisci();

  TTrasferimentoGalileo_mask();
  virtual ~TTrasferimentoGalileo_mask();
};

// Funzione di tarsferimento dati da/verso file .ini con lo stesso nome della maschera
// Andrebbe messo in libreria
void TTrasferimentoGalileo_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 TTrasferimentoGalileo_mask::trasferisci()
{
  TReport_book book;
  TReport rep; rep.load("ps0077700a");
  TGalileo_log* log = new TGalileo_log;
  rep.set_recordset(log);

	const TDate data = get(F_DATA);

	bool rep_to_print = false;
  bool go_on = true;
  
	if (get_bool(F_CLIFO))
  {
		TString80 dsn = get(F_DSN1);
		if (dsn.empty())
		{
			TFilename path = get(F_PATH);

			path << "clifo.txt";

			TSystemisamfile clifo(LF_CLIFO);

			clifo.overwrite(path);
		}
		else
		{
			TString query_header;

			query_header << "ODBC(" << get(F_DSN1) << ',' << get(F_USR1) << ',' << get(F_PWD1) << ")\n";
			TGalileo_clifo pc;
			pc.set_data_limite(get_date(F_DATA));
			pc.set_path(get(F_PATH));
			pc.init(TR("Clienti/Fornitori"), query_header, log);
			go_on = pc.trasferisci();
			book.add(rep);
			pc.dump();
			rep_to_print = true;
		}
	}
	if (go_on && get_bool(F_ARTICOLI))
	{
		TString80 dsn = get(F_DSN2);
		if (dsn.empty())
		{
			TFilename path = get(F_PATH);

			path << "anamag.txt";
			TSystemisamfile anamag(LF_ANAMAG);
			anamag.overwrite(path);
			TSystemisamfile umart(LF_UMART);
			path = get(F_PATH);
			path << "umart.txt";
			umart.overwrite(path);
		}
		else
		{
			TString query_header;

			query_header << "ODBC(" << get(F_DSN2) << ',' << get(F_USR2) << ',' << get(F_PWD2) << ")\n";
			TGalileo_articoli pc;
			pc.init(TR("Articoli"), query_header, log);
			pc.set_data_limite(get_date(F_DATA));
			pc.set_path(get(F_PATH));
			go_on = pc.trasferisci();

			TString80 dsnc = get(F_DSN3);

			if (dsnc.full())
			{
				TString query_header_c;

				query_header_c << "ODBC(" << get(F_DSN3) << ',' << get(F_USR3) << ',' << get(F_PWD3) << ")\n";
			
				TGalileo_articoli pcc;
				TString80 ditta(get(F_DITTA));
				TString80 cms(get(F_CMS));
				TString80 can(get(F_CANT));

				pcc.init(TR("Costi"), query_header_c, log);
				pcc.set_path(get(F_PATH));
				go_on = pcc.trasferisci_costi(ditta, cms, can);
			}
			book.add(rep);
			pc.dump();
			rep_to_print = true;
		}
	}
  if (rep_to_print && book.pages() > 0)
		book.preview();
}

bool TTrasferimentoGalileo_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;
}

TTrasferimentoGalileo_mask::TTrasferimentoGalileo_mask() : TAutomask("ps0077700a")
{
  serialize(false);
}

TTrasferimentoGalileo_mask::~TTrasferimentoGalileo_mask()
{ }

///////////////////////////////////////////////////////////
// TTrasferimentoGalileo
///////////////////////////////////////////////////////////

class TTrasferimentoGalileo : public TSkeleton_application
{
protected:
  virtual const char * extra_modules() const {return "ve";}
  virtual void main_loop();
};

void TTrasferimentoGalileo::main_loop()
{
  TTrasferimentoGalileo_mask mask;
  while (mask.run() == K_ENTER)
    mask.trasferisci();
}

int ps0077700(int argc, char* argv[])
{
  TTrasferimentoGalileo tg;
  tg.run(argc, argv, TR("Trasferimento Galileo"));
  return 0;
}