#include <applicat.h>
#include <automask.h>
#include <progind.h>
#include <reputils.h>
#include <utility.h>
#include <relation.h>
#include <textset.h>
#include <reprint.h>

#include "pt0002.h"
#include "pt0002100a.h"

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

#include "clifo.h"
#include "comuni.h"

///////////////////////////////////////////////////////////
// TClient_textset
///////////////////////////////////////////////////////////

class TClifo_recset : public TCSV_recordset
{
	TAssoc_array _index;

protected:
  virtual TRecnotype new_rec(const char* buf = NULL);

public:
  const TString& rag_sociale() const;
  TClifo_recset(const char * query);
};


TRecnotype TClifo_recset::new_rec(const char* buf)
{
  TToken_string str(256,'\t'); //nuovo record tab separator

  if(buf && *buf)
  {
    bool apici=false;

    for (const char* c = buf; *c ; c++)
    {
      if (*c == '"')
      {
        apici = !apici;
      }
      else
      {
        if (*c == ',')
        {
          if (!apici)
            str << str.separator();
          else
            str << *c;
        }
        else
          str << *c;

      }
    }
  }

  const TRecnotype n = TText_recordset::new_rec(str);

  if (n >= 0)
    row(n).separator(str.separator());
  
  return n;
}

//funzione che crea il campo ragione sociale dai primi 2 campi del file csv
const TString& TClifo_recset::rag_sociale() const
{
  const TString& nome = get(1).as_string();
  TString ragsoc = get(0).as_string();
  if (nome.full())  
  {
    ragsoc.cut(30);
    ragsoc.left_just(30);
    ragsoc << nome;
  }
  ragsoc.cut(50);
  return get_tmp_string() = ragsoc;
}

TClifo_recset::TClifo_recset(const char * fileName)
             : TCSV_recordset("CSV(,)\n")
{
  load_file(fileName);
}

///////////////////////////////////////////////////////////
// TAutomask
///////////////////////////////////////////////////////////

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

public:
  TImportaClifo_mask();
};
  
TImportaClifo_mask::TImportaClifo_mask() :TAutomask ("pt0002100a")
{
}  

bool TImportaClifo_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{ 
	switch (f.dlg())
	{
		//giochetto per avere la lista dei files validi nella directory di trasferimento!
		case F_NAME:
			if (e == fe_button)
			{
				TArray_sheet as(-1, -1, 72, 20, TR("Selezione file"), 
                           "File@32");
				TFilename path = get(F_PATH);
				path.add("*.csv");	//files delle testate
				list_files(path, as.rows_array());
				TFilename name;
				FOR_EACH_ARRAY_ROW(as.rows_array(), i, row)
				{
					name = *row;
					*row = name.name();
				}
				if (as.run() == K_ENTER)
				{
					f.set(as.row(as.selected()));
				}
			}
			break;
		default:
			break;
	}
  return true;
}

///////////////////////////////////////
// TSkeleton_application
///////////////////////////////////////
class TClifoCSV : public TSkeleton_application
{
	virtual bool check_autorization() const {return false;}
  virtual const char * extra_modules() const {return "ve";}

	TImportaClifo_mask*				_msk;
	TConfig*							    _configfile;


protected:
  long find_clifo(const char tipo, const TString& cofi, const TString& paiv, const TString& ragsoc) const;
  bool safe_put(TLocalisamfile& clienti, const char* field, const char* val) const;
	long find_last_clifo(const char tipo) const;
  void pulisci_cap(TString& cap) const;


public:           
  virtual bool create();
  virtual bool destroy();
  virtual void main_loop();
  virtual void ini2mask();
  virtual void mask2ini();
	bool transfer(const TFilename& file);
 
  TClifoCSV() {};
};

TClifoCSV& app() { return (TClifoCSV&) main_app(); }

/////////////////////////////////
//		ricerca clifo
/////////////////////////////////

//funzione che ricerca un cliente o un fornitore nel file clifo di campo
//restituisce 0 (zero) se non lo trova, se no cerca il pi� simile possibile
long TClifoCSV::find_clifo(const char tipo, const TString& cofi, const TString& paiv, const TString& ragsoc) const
{
  long found=0;

  TRelation clifo(LF_CLIFO);
  TRectype& rec = clifo.curr();
  TString up_ragsoc = ragsoc;
  up_ragsoc.upper();

  for (int key = 4; key<=5 && !found; key++)
  {
    bool good_key = false; // Assumiamo che la chiave sia icompleta
    
    rec.zero();
    rec.put(CLI_TIPOCF,tipo);
    switch (key)
    {    
    case 4: rec.put(CLI_COFI,cofi);     good_key = cofi.full(); break;
    case 5: rec.put(CLI_PAIV,paiv);     good_key = paiv.full(); break;
    default: break;
    }

    if (good_key)  // Se la chiave e' completa ... cerco bene
    {
      TCursor cur(&clifo,"", key, &rec, &rec);
      const TRecnotype items = cur.items();

      if (items > 0)
      {
        double best = -1;

        TString80 cur_ragsoc;
        
        cur.freeze();
        for (cur=0; cur.pos() < items; ++cur)
        {
          cur_ragsoc = rec.get(CLI_RAGSOC);
          cur_ragsoc.upper();
    
          // funzione che mi dice quanto due stringhe si assomiglino
          const double var = xvt_str_fuzzy_compare(up_ragsoc, cur_ragsoc); 
          if (var > best)
          {
            best = var;
            found = rec.get_long(CLI_CODCF);
          }
        }
      }
    }
  }
  return found;
}

/////////////////////////////////
//		aggiornamento clifo
/////////////////////////////////

//funzione che effettua la put solo se non cerco di inserire un campo vuoto
bool TClifoCSV::safe_put(TLocalisamfile& file, const char* field, const char* val) const
{
	const bool ok = val && *val;
	if (ok)
		file.put(field, val);
	return ok;
}

//funzione che trova il primo codice libero di un cliento o di un fornitore
long TClifoCSV::find_last_clifo(const char tipo) const
{
  TLocalisamfile clifo(LF_CLIFO);
  long  codcf = 1L ;  
  if (tipo == 'C')
  {
    clifo.put(CLI_TIPOCF, 'F');
    if (clifo.read(_isgteq) == NOERR)
      clifo.prev();
		else
			clifo.last();

    if (clifo.get_char(CLI_TIPOCF) == 'C')
      codcf += clifo.get_long(CLI_CODCF);
  }
  else
  {
    clifo.last();
    if (clifo.get_char(CLI_TIPOCF) == 'F')
      codcf+=clifo.get_long(CLI_CODCF);
  }
  return codcf;
}

void TClifoCSV::pulisci_cap(TString& cap) const
{
  TString8 str;
  for (int i = 0; cap[i] && str.len() < 5; i++)
    if (isdigit(cap[i]))
      str << cap[i];
  cap = str;
}

bool TClifoCSV::transfer(const TFilename& file)
{
  const char tipo = _msk->get(F_TIPO)[0];
  const char* head = tipo == 'C' ? TR("Trasferimento clienti") : TR("Trasferimento fornitori");

  TLog_report log(head);
  
  TClifo_recset s(file);
  
  TLocalisamfile clifo(LF_CLIFO);
  
  TProgind pi(s.items(),head,true,true);

  for (bool ok=s.move_first();ok;ok=s.move_next())
  {
    if (!pi.addstatus(1)) 
      break;
    
    const TString ragsoc = s.rag_sociale();
    if (ragsoc.full())
    {
      const TString16 cofi = s.get(2).as_string(); //get da file del cod. fisc.
      const TString16 paiv = s.get(3).as_string(); //get da file della p. iva
    
      const long var = find_clifo(tipo,cofi,paiv,ragsoc); //controllo se il clifo esiste gi�

      clifo.zero();
      clifo.put(CLI_TIPOCF, tipo);
    
      if (var)
      {
        //se esiste leggo il record corrispondente
        clifo.put(CLI_CODCF,var);
        clifo.read();
      }
      else
      {
        //se no ne creo uno nuovo
        long codcf = find_last_clifo(tipo);
		    clifo.put(CLI_CODCF, codcf);
      }
    
	    safe_put(clifo, CLI_RAGSOC, ragsoc);	//ragsoc
      if (!var)
        safe_put(clifo, CLI_TIPOAPER, s.get(1).is_empty() ? "G" : "F");


	    safe_put(clifo, CLI_PAIV, paiv);	//p.iva
	    safe_put(clifo, CLI_COFI, cofi);	//cod. fisc.

	    
	    safe_put(clifo, CLI_INDCF, s.get(4).as_string());	//indirizzo
      safe_put(clifo, CLI_CIVCF, s.get(5).as_string());	//num. civico

	    if (s.get(6).as_string().empty())                 //italiano
      {
        TString cap = s.get(9).as_string();

        pulisci_cap(cap);
	      
        TString80 comune = s.get(11).as_string();	//comune o localita'
	      comune.trim();
	      safe_put(clifo, CLI_CAPCF, cap);		//cap
	      const TString& codcom = cap2comune(cap, comune);
	      if (codcom.blank())
        {
		      if (s.get(10).as_string().full())
            comune << " (" << s.get(10).as_string() << ')'; //inserisce la localit� se non trova un comune
          safe_put(clifo, CLI_LOCCF, comune);
        }
	      else
		      safe_put(clifo, CLI_COMCF, codcom);
      }
      else
      {
        TString comune = s.get(7).as_string();
        comune << ", " << s.get(8).as_string() << '(' << s.get(6).as_string() <<')';  //inserisce la localit� estera
        safe_put(clifo, CLI_LOCCF, comune);
        if (!var)
          safe_put(clifo, CLI_ALLEG, "5");  // Cliente/Fornitore Estero
      }

      const char* tp = tipo == 'C' ? TR("Cliente") : TR("Fornitore");
      TString str;
      str << "Il "<< tp << " codice (" << clifo.get(CLI_CODCF) <<") " << ragsoc << " ";

      if (var)
      {
        const int err = clifo.rewrite();
        if (err == NOERR)
        {
          str << "� stato aggiornato";
          log.log(0, str); 
        }
        else
        {
          str << "NON � stato aggiornato. Errore " << err;
          log.log(2, str); 
        }
      }
      else
      {
        const int err = clifo.write();
        if (err == NOERR)
        {
          str << "� stato inserito";
          log.log(0, str); 
        }
        else
        {
          str << "NON � stato inserito. Errore " << err;
          log.log(2, str); 
        }
      }

      if (cofi.empty() && paiv.empty())
      {
        TString str;
        str << "Il " << tp << ' ' << ragsoc << " non ha n� CODICE FISCALE n� PARTITA IVA";
        log.log(1, str);
      }
    }

  }

  TReport_book buc;
	buc.add(log);
	buc.preview();

  return true;
}

void TClifoCSV::mask2ini()
{
	//carica i parametri del file di configurazione
	_configfile->set_paragraph("MAIN");
  for (int i = 0; i < _msk->fields() ; i++)
	{
		TMask_field& f = _msk->fld(i);
		const TFieldref* fr = f.field();
		if (fr != NULL)
			_configfile->set(fr->name(), f.get());
	}
}

void TClifoCSV::ini2mask()
{
	//carica i parametri del file di configurazione
	_configfile->set_paragraph("MAIN");
  for (int i = 0; i < _msk->fields() ; i++)
	{
		TMask_field& f = _msk->fld(i);
		const TFieldref* fr = f.field();
		if (fr != NULL)
			f.set(_configfile->get(fr->name()));
	}
}

bool TClifoCSV::create()
{
  _configfile = new TConfig("pt0002conf.ini");
  _msk = new TImportaClifo_mask();

         
  return TSkeleton_application::create();
}

bool TClifoCSV::destroy()
{
	delete _msk;
	delete _configfile;
  return TApplication::destroy();
}

void TClifoCSV::main_loop()
{
  KEY	tasto;
	ini2mask();
  tasto = _msk->run();
  if (tasto == K_ENTER)
  {
		mask2ini();

    //genero il nome del file da caricare
    TFilename name = _msk->get(F_PATH);
    name.add(_msk->get(F_NAME));
		if (transfer(name))
		{
			message_box(TR("Importazione documenti completata"));
		}
  }   
}

int pt0002100 (int argc, char* argv[])
{
  TClifoCSV main_app;
  main_app.run(argc, argv, TR("Importazione Clienti/Fornitori"));
  return true;
}