#include <applicat.h>
#include <config.h>
#include <currency.h>
#include <prefix.h>
#include <progind.h>
#include <relation.h>
#include <utility.h>
#include <tabutil.h>

#include "../cg/cglib01.h"

#include "baeur.h"

inline TEuro_app& app() { return (TEuro_app&)main_app(); }

///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////

// Confronta due nomi di directory
bool dir_equal(const char* dir1, const char* dir2)
{
  TFilename d1 = dir1; d1.strip("\\/");
  TFilename d2 = dir2; d2.strip("\\/");
  return d1 == d2;
}

void convert_import(TRectype& rec, const char* str, bool price)
{
  if (str && *str)
  {               
    const int dec = TCurrency::get_euro_dec(price);

    TToken_string list = str;
    FOR_EACH_TOKEN(list, tok)
    {
      real r = rec.get(tok);
      if (r != ZERO)
      {
        r /= EURO;
        r.round(dec);
        rec.put(tok, r);
      }
    }
  }
}

void zero_import(TRectype& rec, const char* str)
{   
  if (str && *str)
  {
    TToken_string list = str;
    FOR_EACH_TOKEN(list, tok)
      rec.zero(tok);
  }
}

void keep_import(TRectype& rec, const char* str)
{   
  if (str && *str)
  {      
    TAssoc_array old;
    TToken_string list = str;
    FOR_EACH_TOKEN(list, tok)
      old.add(tok, rec.get(tok));
    rec.zero();
    FOR_EACH_ASSOC_STRING(old, obj, key, val)
      rec.put(key, val);
  }
}


const TString& build_name(int logicnum, bool euro, long firm)
{
  TFilename dati, datie;
  app().get_aree_dati(dati, datie);

  TDir d; d.get(logicnum, _nolock, _nordir, _sysdirop);

  TString8 ditta = "com";
  TFilename name = d.filename();
  TFilename n = name.name();

  if (!d.is_com())
  {
    if (firm < 0) 
      firm = app().get_firm();
    if (firm > 0)  
      ditta.format("%05ldA", firm);
  }
  else
  {
    const TFilename n1 = d.name();
    if (n1[0] != '%')
    {
      ditta.cut(0);
      n = n1;
      n.ext("dbf");
    }
  }
  
  static TFilename _filename;
  _filename = euro ? datie : dati;
  _filename.add(ditta);
  _filename.add(n);
  _filename.insert("%", 0);
  
  return _filename;
}

bool dbf_exists(int logicnum, bool euro, long firm)
{
  TFilename n = build_name(logicnum, euro, firm);
  if (n[0] == '%') n.ltrim(1);
  return fexist(n);
}

///////////////////////////////////////////////////////////
// Base app
///////////////////////////////////////////////////////////

bool TEuro_app::get_aree_dati(TFilename& lit, TFilename& eur) const
{
  TConfig prassis(CONFIG_STUDIO, "Euro");
  lit = prassis.get("DatiLire");
  eur = prassis.get("DatiEuro");
  if (lit.blank())
  {
    lit = prefix().get_studio();
    lit.rtrim(1);
  }
  bool ok = eur.exist();
  return ok;
}

bool TEuro_app::goto_euro(long ditta)
{               
  TFilename lit, eur; 
  bool ok = get_aree_dati(lit, eur);
  if (ok)
  {
    TFilename cur = prefix().get_studio(); cur.rtrim(1);
    if (ditta < 0)
      ditta = get_firm();
    if (!dir_equal(cur, eur))
      ok = prefix().set_studio(eur, ditta);
    else
      prefix().set_codditta(ditta);
  }
  if (!ok)
    error_box("Impossibile utilizzare lo studio in euro '%s'", (const char*)eur);
  return ok;
}

bool TEuro_app::goto_lire(long ditta)
{
  TFilename lit, eur; 
  get_aree_dati(lit, eur);

  bool ok = !lit.blank() && fexist(lit);
  if (ok)
  {
    TFilename cur = prefix().get_studio(); cur.rtrim(1);
    if (ditta < 0)
      ditta = get_firm();
    if (!dir_equal(cur, lit))
      ok = prefix().set_studio(lit, ditta);
    else
      prefix().set_codditta(ditta);
  }
  if (!ok)
    error_box("Impossibile utilizzare lo studio in lire '%s'", (const char*)lit);
  return ok;
}

bool TEuro_app::save_round_bill(const TBill& b) const
{ 
  bool ok = b.ok();
  if (ok)
  {
    TFilename lit, eur; 
    ok = get_aree_dati(lit, eur);
    if (ok)
    {
      eur.add("config/prassis.ini");
      TConfig prassis(eur, "Euro");
      
      TString16 str;
      str.format("%d,%d,%ld", b.gruppo(), b.conto(), b.sottoconto());
      prassis.set("RoundBill", str);
    }
  }
  return ok;
}

bool TEuro_app::load_round_bill(TBill& b) const
{
  TFilename lit, eur; 
  bool ok = get_aree_dati(lit, eur);
  if (ok)
  {
    eur.add("config/prassis.ini");
    TConfig prassis(eur, "Euro");
    TToken_string str(prassis.get("RoundBill"), ',');
    const int g = str.get_int();
    const int c = str.get_int();
    const long s = str.get_long();
    b.set(g, c, s);
    ok = b.find();
  }
  return ok;
}

bool TEuro_app::copy_dir(const char* src, const char* dst) const
{
  bool ok = TRUE;
  if (!fexist(dst))
    make_dir(dst);
    
  TString_array files;
  TFilename file1, file2;
  file1 = src; file1.add("*.*");
  list_files(file1, files);
  
  TString str;
  str << "Copia da " << src << " a " << dst << "...";
  TProgind pi(files.items(), str, FALSE, TRUE);
  FOR_EACH_ARRAY_ROW(files, i, file)
  {
    pi.addstatus(1);
    file1 = *file;
    file2 = dst; file2.add(file1.name());
    ok &= fcopy(file1, file2);
  }  
  return ok;
}

bool TEuro_app::is_com_file(int lf) const
{
  TDir d;
  d.get(lf, _nolock, _nordir, _sysdirop);
  return d.is_com();
}

void TEuro_app::zap_file(int lf, bool euro, const char* filter) const
{ 
  TFilename name = build_name(lf, euro, -1);
  if (name[0] == '%') name.ltrim(1);
  if (name.exist())
  {
    if (filter && *filter)
    {
      TRelation rel(lf);
      rel.replace(new TEuroisamfile(lf, euro));
      TCursor cur(&rel, filter);
      const long items = cur.items();
      cur.freeze();
      for (cur = 0L; cur.pos() < items; ++cur)
        rel.remove();
    }
    else
    {
      TExternisamfile f(name);
      f.zap();
    }
  }
}

/*
void TEuro_app::zap_table(const char * tab, bool euro)
{             
  const int lf = tab && *tab == '%' ? LF_TABCOM : LF_TAB;
  TFilename name = build_name(lf, euro, -1);
 
  if (name[0] == '%') name.ltrim(1);
  TExternisamfile f(name);                
  if (!f.empty())
  {
    TString16 tabname(lf == LF_TAB ? tab : tab + 1);
  
    f.put("COD", tabname);
    for (f.read(_isgteq); f.good() && tabname == f.get("COD"); f.next())
      f.remove();
  }
}
*/
  
void TEuro_app::convert_file(int lf, const char* cnv, const char* res, const char* pri, 
                             record_handler rh, void* jolly, const char* filter)
{  
  if (!dbf_exists(lf, FALSE, -1)) // Non esiste il file da convertire
    return;                       // per cui...
  
  // Cursore su file in lire
  TRelation rel(lf);
  TCursor cur(&rel, filter);
  TRectype& curr = rel.curr();
    
  zap_file(lf, TRUE, filter); // Azzera file in euro
  
  // File destinazione in euro
  TEuroisamfile fileur(lf, TRUE);
  TRectype& receur = fileur.curr();
  
  TString str;
  str << "Conversione " << rel.lfile().description() << " ...";
    
  TToken_string conv(cnv);
  TToken_string azze(res);
  TToken_string pric(pri);
    
  const long items = cur.items();
  cur.freeze();
  TProgind pi(items, str, FALSE, TRUE);
  for (cur = 0L; cur.pos() < items; ++cur)
  {     
    pi.addstatus(1);
    receur = curr;
    convert_import(receur, conv, FALSE);
    convert_import(receur, pric, TRUE);
    zero_import(receur, azze);
      
    bool do_write = TRUE;
    if (rh != NULL)
      do_write = rh(receur, jolly);
    if (do_write)  
      fileur.write();
  }
}

/*
void TEuro_app::convert_table(const char *tab, const char* cnv, const char* res, record_handler rh, void* jolly)
{  
  // Cursore su file in lire
  TRelation rel(tab);
  TCursor cur(&rel);
  TRectype& curr = rel.curr();
  
  zap_table(tab, TRUE);

  // File destinazione in euro
  TEuroisamfile tabeur(tab && *tab == '%' ? LF_TABCOM : LF_TAB, TRUE);
  TRectype& receur = tabeur.curr();                  
  
  TString str;
  str << "Conversione " << rel.lfile().description() << " ...";
  
  TToken_string conv(cnv);
  TToken_string azze(res);
  
  const long items = cur.items();
  cur.freeze();
  TProgind pi(items, str, FALSE, TRUE);
  for (cur = 0L; cur.pos() < items; ++cur)
  {     
    pi.addstatus(1);
    receur = curr;
    convert_import(receur, conv);
    zero_import(receur, azze);
    
    bool do_write = TRUE;
    if (rh != NULL)
      do_write = rh(receur, jolly);
    if (do_write)  
      tabeur.write();
  }
}
*/

bool TEuro_app::data_adozione_euro(long firm, TDate& adozione, bool& inizio) const
{
  TFilename dati, datie;
  get_aree_dati(dati, datie);
  
  TString8 ditta; 
  ditta.format("%05ldA", firm <= 0 ? get_firm() : firm);

  TFilename inie = datie;
  inie.add(ditta);
  inie.add("prassid.ini");

  inizio = TRUE;  // Supponiamo che adotti l'euro ad inizio esercizio

  bool adotta = inie.exist();
  if (adotta)
  {
    TConfig prassid(inie, "Euro");
    adozione = prassid.get("DataAdozione");
    adotta = adozione.ok();
    if (adotta)
    {
      TEsercizi_contabili esc;
      const int anno = esc.date2esc(adozione);
      if (anno > 0)
        inizio = adozione == esc[anno].inizio();
    }
  }
  return adotta;
}


bool TEuro_app::create()
{
  old_study = prefix().get_studio();
  return TSkeleton_application::create();
}

bool TEuro_app::destroy()
{                               
  if (old_study != prefix().get_studio())
  {            
    TConfig ini(CONFIG_INSTALL, "Main");
    ini.set("Study", old_study);
  }
  return TSkeleton_application::destroy();
}

///////////////////////////////////////////////////////////
// TEuroisamfile
///////////////////////////////////////////////////////////

TEuroisamfile::TEuroisamfile(int logicnum, bool euro, long firm)
             : TIsamtempfile(logicnum, build_name(logicnum, euro, firm), FALSE, FALSE)
{           
}

///////////////////////////////////////////////////////////
// main
///////////////////////////////////////////////////////////

int main(int argc, char** argv)
{  
  TApplication::check_parameters(argc, argv);
  
  int a = 0;
  if (argc > 1)
  {
    a = toupper(argv[1][1]);
    if (isdigit(a))
      a -= '0';
    else
      a -= 'A'-10;
  }
  switch (a)
  { 
  case 1: baeur01(argc, argv); break;  // Conversione ditte
  case 2: baeur02(argc, argv); break;  // Conversione saldi infrannuale
  case 3: baeur03(argc, argv); break;  // Chiusura/Apertura conti in Euro
  case 4: baeur04(argc, argv); break;  // Conversione documenti
  case 5: baeur05(argc, argv); break;
  case 6: baeur06(argc, argv); break;
  case 7: baeur07(argc, argv); break;
  case 8: baeur08(argc, argv); break;
  case 9: baeur09(argc, argv); break;  // Ricalcolo saldi Lire/Euro
  case 10: baeur0A(argc, argv); break; // Copia movimenti contabili da Euro a Lire
  default: baeur00(argc, argv); break; // Creazioe area dati euro
  }  
  return 0;
}