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

#include "contsan.h"
#include "donaz.h"
#include "idoneita.h"
#include "rconvoc.h"
#include "soggetti.h"

#include "atlib.h"
#include "at9800a.h"
////////////////////////////
//  Maschera
////////////////////////////
class TImporta_ct_rn_mask : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
  TImporta_ct_rn_mask();
};

TImporta_ct_rn_mask::TImporta_ct_rn_mask() : TAutomask("at9800a")
{
}

bool TImporta_ct_rn_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{
  switch (f.dlg())
  {
	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("*.txt");
		  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;
}

////////////////////////////
//  Recordset
////////////////////////////
class TImporta_ct_rn_recordset : public TAS400_recordset
{
protected:
  long trova_riga(const TString& key);

public:
  TDate get_date(const char* field_name) const;
  TImporta_ct_rn_recordset(const TFilename& name);
};

//in base al campo decide come ricavare la data; questo perch� quei geni dell'avis producono..
//..un file con le date scritte in formato fritto misto!
TDate TImporta_ct_rn_recordset::get_date(const char* field_name) const
{
  /*l'unica data scritta in modo civile � la datadon: come non detto! hanno porcato anche questa!
  if (xvt_str_compare_ignoring_case(field_name, "DATADON") == 0)
    return get(field_name).as_date();*/

  //le altre sono scritte in modo incivile e vanno girate
  const TString& str_date = get(field_name).as_string();
  TDate output_date(atoi(str_date.left(2)), atoi(str_date.mid(2,2)), atoi(str_date.mid(4,4)));
  return output_date;
}

TImporta_ct_rn_recordset::TImporta_ct_rn_recordset(const TFilename& name)
: TAS400_recordset(TString("AS400(180)\nSELECT * FROM ") << name)
{
  create_field("COGNOME",     -1, 20, _alfafld, true);
  create_field("NOME",        -1, 20, _alfafld, true);
  create_field("DATANASC",    -1,  8, _alfafld, true);
  create_field("SESSO",       -1,  1, _alfafld, true);
  create_field("STATO",       -1,  8, _alfafld, true);
  create_field("DATAULTEC",   -1,  8, _alfafld, false);
  create_field("DATADON",     -1,  8, _alfafld, true);  //unica data scritta a rovescio (cio� corretta!)
  create_field("TIPOPRE",     -1,  8, _alfafld, true);
  create_field("ANNOUNITA",   -1,  4, _intfld, true);
  create_field("NROUNITA",    -1,  6, _intfld, true);
  create_field("MOTIVOSOSP",  -1,  8, _alfafld, false);
  create_field("SOSPESODAL",  -1,  8, _alfafld, false);
  create_field("SOSPESOAL",   -1,  8, _alfafld, false);
  create_field("LUOGO1",      -1,  8, _alfafld, false);
  create_field("LUOGO2",      -1,  8, _alfafld, false);
  create_field("LUOGO3",      -1,  8, _alfafld, true);
  create_field("LUOGO4",      -1,  8, _alfafld, true);
  create_field("IDONEO_SI",   -1,  1, _alfafld, true);
  create_field("IDONEO_PL",   -1,  1, _alfafld, true);
  create_field("IDONEO_PI",   -1,  1, _alfafld, true);
  create_field("TIPO_ESAME",  -1,  8, _alfafld, false);
  create_field("RISULTATO",   -1, 20, _alfafld, false);
}

///////////////////////////////////////
//  Decodificatore
///////////////////////////////////////
//classe per la trascodifica lampo dei codici CT in quelli AT..
//..(secondo la tabella &C2A)
class TDecode_c2a : public TCache
{
protected:
  virtual TObject* key2obj(const char* key);

public:
  const TString& decode(const char* code, const char* prefix);
};

TObject* TDecode_c2a::key2obj(const char* key)
{
  TString* str = new TString;

  TModule_table tabmod("AT548C2A");
  tabmod.put("CODTAB", key);
  if (tabmod.read() == NOERR)
    *str = tabmod.get("S6");

  return str;
}

const TString& TDecode_c2a::decode(const char* code, const char* prefix)
{
  TString16 key;
  key << prefix << code;
  key.trim();
  return *(const TString*)objptr(key);
}


////////////////////////////
//  Applicazione
////////////////////////////
class TImporta_ct_rn : public TSkeleton_application
{
  TImporta_ct_rn_mask*  _mask;
  TLog_report*			    _log;
  TDecode_c2a           _c2a;
  TAssoc_array          _nocontrol_sezioni;

private:
  virtual bool create();
  virtual void main_loop();

protected:
  void msg_no_sog_error(const TImporta_ct_rn_recordset& recset) const;
  void msg_esame_error(const TImporta_ct_rn_recordset& recset, const TString& tipo, const bool manca) const;
  void msg_stato_error(const TImporta_ct_rn_recordset& recset, const int tipo, 
                       const TString& stato_avis = "", const TString& stato_ct = "") const;
  void msg_aggiunge_qualcosa(const TRectype& curr_rec) const;
  const TString& decode(const char* code, const char* prefix);
  long trova_prossimo(TLocalisamfile& file, const long sog_codice) const;

public:
  const TString& decode_stato(const char* code) { return decode(code, "14"); }
  const TString& decode_prelievo(const char* code) { return decode(code, "19"); }
  const TString& decode_esame(const char* code) { return decode(code, "32"); }
  const TString& decode_luogo(const char* code) { return decode(code, "PU"); }
  void aggiunge_contsan(const TImporta_ct_rn_recordset& recset, const long sog_codice);
  void aggiunge_donazione(const TImporta_ct_rn_recordset& recset, const long sog_codice);

  bool importa_dati(const TFilename& name);
  bool controlla_stato_ct_avis(const TImporta_ct_rn_recordset& recset, const long codsog);
  bool aggiorna_soggetto(const long codsog);
};


void TImporta_ct_rn::msg_no_sog_error(const TImporta_ct_rn_recordset& recset) const
{
  TString error_msg;
  _log->log(2, "DONATORE NON PRESENTE NEGLI ARCHIVI !");
  error_msg << "Cognome: " << recset.get("COGNOME").as_string() << "\n";
  error_msg << "Nome: " << recset.get("NOME").as_string() << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << "Data nascita: " << recset.get_date("DATANASC") << "\n";
  error_msg << "Sesso: " << recset.get("SESSO").as_string() << "\n";
  error_msg << "Stato donatore: " << recset.get("STATO").as_string() << "\n";
  error_msg << "Data donazione: " << recset.get_date("DATADON") << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << "Tipo prelievo: " << recset.get("TIPOPRE").as_string() << "\n";
  error_msg << "Data ultimi esami controllo: " << recset.get_date("DATAULTEC") << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << "Sospeso dal: " << recset.get_date("SOSPESODAL") << " al: " << recset.get_date("SOSPESOAL") << "\n";
  error_msg << "Motivo sospensione: " << recset.get("MOTIVOSOSP").as_string() << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << " \n";
  _log->log(0, error_msg);
  error_msg.cut(0);
}


void TImporta_ct_rn::msg_esame_error(const TImporta_ct_rn_recordset& recset, const TString& tipo, bool manca) const
{
  TString error_msg;
  error_msg << tipo << " NON INSERIBILE !";
  _log->log(2, error_msg);
  error_msg.cut(0);

  error_msg << "Data: " << recset.get_date("DATADON") << "\n";
  error_msg << "Tipo: " << recset.get("TIPO_ESAME").as_string() << "\n";
  if (manca)
    error_msg << "Manca il codice " << tipo << " corrispondente" << "\n";
  else
    error_msg << tipo << " gi� presente !" << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << "Cognome: " << recset.get("COGNOME").as_string() << "\n";
  error_msg << "Nome: " << recset.get("NOME").as_string() << "\n";
  error_msg << "Data nascita: " << recset.get_date("DATANASC") << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << " \n";
  _log->log(0, error_msg);
}

void TImporta_ct_rn::msg_stato_error(const TImporta_ct_rn_recordset& recset, const int tipo, 
                                     const TString& stato_avis, const TString& stato_ct) const
{
  TString error_msg;
  switch (tipo)
  {
  case 0:
    error_msg << "STATO DONATORE NON PRESENTE IN TABELLA" << "\n";
    error_msg << "Stato: " << recset.get("STATO").as_string() << "\n";
    break;
  case 1:
    error_msg << "STATO DONATORE AVIS DIVERSO DA CT - VERIFICARE" << "\n";
    error_msg << "- AVIS: " << stato_avis << "\n";
    error_msg << "- CT:   " << stato_ct << "\n";
    break;
  case 2:
    error_msg << "SOGGETTO DICHIARATO IDONEO DAL CT SENZA TIPI DI DONAZIONE" << "\n";
    break;
  case 3:
    error_msg << "SOGGETTO DICHIARATO DECEDUTO DA CT - VERIFICARE" << "\n";
    break;
  default:
    break;
  }

  _log->log(2, error_msg);
  error_msg.cut(0);

  error_msg << "Cognome: " << recset.get("COGNOME").as_string() << "\n";
  error_msg << "Nome: " << recset.get("NOME").as_string() << "\n";
  error_msg << "Data nascita: " << recset.get_date("DATANASC") << "\n";
  _log->log(0, error_msg);
  error_msg.cut(0);

  error_msg << " \n";
  _log->log(0, error_msg);
}

//metodo per scrivere sul log le avvenute registrazioni di donazioni e controlli
void TImporta_ct_rn::msg_aggiunge_qualcosa(const TRectype& curr_rec) const
{
  const bool is_donaz = curr_rec.num() == LF_DONAZ;
  const char* tipo = is_donaz ? "DONAZIONE" : "ESAME";
  TString msg;
  msg << "INSERIMENTO " << tipo << "\n";
  _log->log(2, msg);
  msg.cut(0);
  //data
  const TDate data = is_donaz ? curr_rec.get_date(DON_DATADON) : curr_rec.get_date(CON_DATACON);
  msg << "Data: " << data.string() << "\n";
  //tipo
  const TString& tipodon = is_donaz ? curr_rec.get(DON_TIPODON) : curr_rec.get(CON_TIPOCON);
  msg << "Tipo: " << tipodon << "\n";
  //luogo
  if (is_donaz)
  {
    const TString& cod_luogo = curr_rec.get(DON_LUOGODON);
    const TString& descr_luogo = cache().get("LDN", cod_luogo, "S0");
    msg << "Luogo: " << cod_luogo << " - " << descr_luogo << "\n";
  }
  _log->log(0, msg);
  msg.cut(0);
  //progressivo
  const int progressivo = is_donaz ? curr_rec.get_int(DON_PROGDON) : curr_rec.get_int(CON_PROGCON);
  msg << "Prog. don.: " << progressivo << "\n";
  //soggetto
  const long codsog = is_donaz ? curr_rec.get_long(DON_CODICE) : curr_rec.get_long(CON_CODICE);
  const TRectype& recsog = cache().get(LF_SOGGETTI, codsog);
  msg << "Cognome: " << recsog.get(SOG_COGNOME) << "\n";
  msg << "Nome: " << recsog.get(SOG_NOME) << "\n";
  msg << "Data nascita: " << recsog.get_date(SOG_DATANASC) << "\n";
  _log->log(0, msg);
  msg.cut(0);
  msg << " \n";
  _log->log(0, msg);
}

//decodifica sulla tabella C2A (utilizza la classe apposita creata in precedenza)
const TString& TImporta_ct_rn::decode(const char* code, const char* prefix)
{
  return _c2a.decode(code, prefix);
}


static int compare_date(const TObject** o1, const TObject** o2)
{
  const TRectype& s1 = *((TRectype*)*o1);
  const TRectype& s2 = *((TRectype*)*o2);
  
  const TDate d1(s1.get(IDO_DATAIDO));
  const TDate d2(s2.get(IDO_DATAIDO));
  
  int d = d1 - d2;
	return d;
}

//metodo per cercare l'ultimo record di un soggetto in un file tipo donaz e contsan
long TImporta_ct_rn::trova_prossimo(TLocalisamfile& file, const long sog_codice) const
{
  long next = 1;

  file.put("CODICE", sog_codice + 1); //Guy mi perdoni se non uso la macro!
  int err = file.read(_isgteq);
  if (err == NOERR)
    err = file.read(_isprev);
  else
  {
    if (err == _iseof)
      err = file.read(_islast);
  }
  if (err == NOERR && file.get_long("CODICE") == sog_codice)  //Mi riperdoni!
  {
    const int filenum = file.num(); //Qui si rischia il linciaggio...
    if (filenum == LF_CONTSAN)
      next += file.get_long(CON_PROGCON);
    if (filenum == LF_DONAZ)
      next += file.get_long(DON_PROGDON);
  }

  return next;
}

//confronto stato donatore avis con quello ct
bool TImporta_ct_rn::controlla_stato_ct_avis(const TImporta_ct_rn_recordset& recset, const long codsog)
{
  //stato_ct = stato preso da file da importare
  //stato_at = stato_ct decodificato per avis in base alla tabella di trascodifica
  //stato_attuale = stato sul record del soggetto nel file dei soggetti
  const TString& stato_ct = recset.get("STATO").as_string();
  if (stato_ct.full())
  {
    const TString& stato_at = decode_stato(stato_ct);
    //se non riesce a decodificare lo stato avverte ed esce
    if (stato_at.blank())
      msg_stato_error(recset, 0);
    else
    {
      TLocalisamfile soggetti(LF_SOGGETTI);
      soggetti.put(SOG_CODICE, codsog);
      int err = soggetti.read();
      if (err == NOERR) //e non possiamo aspettarci altro che NOERR, visto che il controllo lo ha gi� fatto prima
      {
        const TString& stato_attuale = soggetti.get(SOG_STATO);
        //se lo stato sul record del soggetto risulta != dallo stato sul file adesso decodificato..
        //..procede al casino infernale dell'allineamento stati
        //Questo casino pu� per� farlo solo nel caso la sezione ammetta controlli;in caso contrario..
        //..deve semplicemente abbandonare la questione dando segnalazione dell'incongruenza tra gli..
        //..stati avis e ct (incongruenza che non pu� essere corretta causa la propriet� della sezione).
        if (stato_at != stato_attuale)
        {
          const TString& sog_sez = soggetti.get(SOG_CODSEZ);
          const bool sez_no_controlli = _nocontrol_sezioni.is_key(sog_sez);
          //controlla se la sezione ammette i controlli
          if (!sez_no_controlli)
          {
            //verifica se deve veramente elaborare il tutto o no
            //Per prima cosa verifica se lo stato comporta una idoneit�/sospensione/donazionabilit�
            //Deve controllare sulla tabella di trascodifica il campo S7
            TModule_table tabmod("AT548C2A");
            TString key;
            key << "14" << stato_ct;
            key.trim();
            tabmod.put("CODTAB", key);
            TString4 i_s_d;   //non � una droga, ma idoneit�_sospensione_donatoreabile
            if (tabmod.read() == NOERR)
              i_s_d = tabmod.get("S7");

            //controlla se sono state passate via file da importare una o pi� idoneit�
            const TString& ido_si = recset.get("IDONEO_SI").as_string();
            const TString& ido_pl = recset.get("IDONEO_PL").as_string();
            const TString& ido_pi = recset.get("IDONEO_PI").as_string();

            //nessuno stato con idoneit� -> salta
            if (i_s_d[0] == 'I' &&  ido_si[0] != 'S' && ido_pl[0] != 'S' && ido_pi[0] != 'S')
                msg_stato_error(recset, 2);
            else
            {
              //giro sui contsan del soggetto
              //per prima cosa cerca se gi� esiste un contsan in data letta dal recset
              TDate datacon = recset.get_date("DATADON");
              TLocalisamfile contsan(LF_CONTSAN);
              contsan.setkey(2);
              contsan.put(CON_DATACON, datacon);
              contsan.put(CON_CODICE, codsog);
              int err = contsan.read();
              //se esiste deve spostare di un giorno in avanti la data del controllo da inserire
              if (err == NOERR)
                ++datacon;
              const long next_contsan = trova_prossimo(contsan, codsog);

              //dopo essersi posizionato correttamente, agiunge il contsan
              contsan.zero();
              contsan.put(CON_CODICE, codsog);
              contsan.put(CON_PROGCON, next_contsan);
              contsan.put(CON_DATACON, datacon);
              contsan.put(CON_TIPOCON, stato_at);
              contsan.put(CON_RESPONSAB, "AGGIORNAMENTO DA CENTRO TRASF.");

              //campi speciali in base a parametri allucinanti
              //se il soggetto � dichiarato idoneo...
              if (i_s_d[0] == 'I')
              {
                int ido_num = 0;  //questa � da seguire perch� esempio di mentalit� contorta!
                TString8 nome_campo_ido;

                //idoneit� SI
                if (ido_si[0] == 'S')
                {
                  ido_num++;
                  nome_campo_ido.format("IDON%d", ido_num);
                  contsan.put(nome_campo_ido, "SI");
                  if (soggetti.get_int(SOG_INTSI) == 0)
                  {
                    if (soggetti.get_int(SOG_SESSO) == 1)
                      contsan.put(CON_INTSI, 94);
                    else
                      contsan.put(CON_INTSI, 180);
                  }
                }
                //idoneit� PL-AF
                if (ido_pl[0] == 'S')
                {
                  ido_num++;
                  nome_campo_ido.format("IDON%d", ido_num);
                  contsan.put(nome_campo_ido, "PL");
                  const int intaf = soggetti.get_int(SOG_INTAF);
                  if (intaf == 0)
                    contsan.put(CON_INTAF, 30);
                  else
                    contsan.put(CON_INTAF, intaf);
                }
                
                //idoneit� PI
                if (ido_pi[0] == 'S')
                {
                  ido_num++;
                  nome_campo_ido.format("IDON%d", ido_num);
                  contsan.put(nome_campo_ido, "PI");
                  if (contsan.get_int(CON_INTAF) == 0)
                  {
                    const int intaf = soggetti.get_int(SOG_INTAF);
                    if (intaf == 0)
                      contsan.put(CON_INTAF, 30);
                    else
                      contsan.put(CON_INTAF, intaf);
                  }
                }
              } //if (i_s_d[0] == 'I' &&...
              //e alla fine della storia scrive il record!
              err = contsan.write();

              //comunque sia, effettua il controllo della morte del soggetto
              //Ebbene si, anche se lo ha aggiornato, non si sa mai che risorga...
              const bool sog_kaputt = tabmod.get_bool("B1");
              if (sog_kaputt)
                msg_stato_error(recset, 3);
            }
          }
          else  //if (!sez_no_controlli)...
          {
            msg_stato_error(recset, 1, stato_at, stato_attuale);
          } ////if (!sez_no_controlli)...
        } //if (stato_at != stato_attuale)...
      } //if (err == NOERR)...
    } //if (stato_at.blank())..
  } //if (stato_ct.full())...
  return true;
}

//aggiorna i files di atwin (donazioni,idoneit�,controlli,soggetti) del..
//..soggetto di cui ha importato donazione o contsan
bool TImporta_ct_rn::aggiorna_soggetto(const long codsog)
{
  TLocalisamfile soggetti(LF_SOGGETTI);
  TRectype& recsog = soggetti.curr();
  recsog.put(SOG_CODICE, codsog);
  int err = soggetti.read();
  //se non trova il soggetto c'� qualcosa che non quadra ed esce (impossibile)
	if (err != NOERR)
    return false;

  //codice del soggetto in formato alfanumerico per i TRecord_array
  const TString8 sog_codice = recsog.get(SOG_CODICE);

  //riordino delle donazioni
  TRecord_array sdonazioni(sog_codice, LF_DONAZ);
	calcola_donazioni_lib(recsog, &sdonazioni);
	sdonazioni.rewrite();

  //riordino delle idoneit�
  TRecord_array sidoneita(sog_codice, LF_IDONEITA);
	sidoneita.sort(compare_date);				
	sidoneita.rewrite();

  //riordino dei controlli
  TRecord_array scontrolli(sog_codice, LF_CONTSAN);
	if (scontrolli.rows() > 0 || sidoneita.rows() > 0)
		con_reord(recsog, &scontrolli, &sidoneita);

  //riordino del soggetto
  TConfig config(CONFIG_STUDIO);
  const bool dataisc = config.get_bool("DataIsc");

  TDate dataiscsog = recsog.get_date(SOG_DATAISC);
  if (!dataiscsog.ok() && dataisc)
  {                 
		if (!recsog.get_date(SOG_DATAPRISI) == NULLDATE)
			recsog.put(SOG_DATAISC, recsog.get(SOG_DATAPRISI));
		else
		{
			const TRectype& riga = sdonazioni.row(1);
			recsog.put(SOG_DATAISC, riga.get(DON_DATADON));
		}				  	
	} //if (!dataiscsog.ok()...

  //riordino convocazioni
	const TDate dataprossi = recsog.get_date(SOG_DATAPROSSI);
	const TDate dataconv = recsog.get_date(SOG_DATACONV);
	const char stato = modstato_tcs(recsog.get(SOG_STATO));
	const TString& statosi = recsog.get(SOG_STATOSI);
	if ((stato == 'S') || (statosi == SOSPENSIONE) || (dataprossi > dataconv) || !dataprossi.ok())
	{
    TLocalisamfile rconvoc(LF_RCONVOC);
		rconvoc.setkey(3);
		rconvoc.zero();
		rconvoc.put(RCV_CODICE, recsog.get(SOG_CODICE));
		rconvoc.put(RCV_DATACONV, recsog.get(SOG_DATACONV));
		if (rconvoc.read() == NOERR)
		{
			rconvoc.put(RCV_ANNULLATO, TRUE);
			rconvoc.write();
		}

		recsog.zero(SOG_DATACONV);
		recsog.zero(SOG_DATAULTSOL);
		recsog.zero(SOG_NUMCONV);

	}	  //if(stato=='S'...
	recsog.put(SOG_DATAULTAGG, TDate(TODAY));
  recsog.put(SOG_UTENULTAGG, "CONVE");

  //e alla fine riscrive il file dei soggetti
	soggetti.rewrite();

  return true;
}


void TImporta_ct_rn::aggiunge_contsan(const TImporta_ct_rn_recordset& recset, const long sog_codice)
{
  //cerca, per il soggetto in questione, quale � l'ultimo controllo sanitario e aggiunge quello nuovo
  TLocalisamfile contsan(LF_CONTSAN);
  const long next_contsan = trova_prossimo(contsan, sog_codice);

  //dopo essersi posizionato correttamente, agiunge il contsan
  contsan.zero();
  contsan.put(CON_CODICE, sog_codice);
  contsan.put(CON_PROGCON, next_contsan);
  const TDate& dataesame = recset.get_date("DATADON");
  contsan.put(CON_DATACON, dataesame);
  const TString& tipopre = decode_prelievo(recset.get("TIPOPRE").as_string());
  contsan.put(CON_TIPOCON, tipopre);
  contsan.put(CON_RESPONSAB, "AGGIORNAMENTO DA CENTRO TRASF.");

  int err = contsan.write();
  //se riesce a scrivere il nuovo contsan, aggiorna il log ed il soggetto
  if (err == NOERR)
    msg_aggiunge_qualcosa(contsan.curr());
}


void TImporta_ct_rn::aggiunge_donazione(const TImporta_ct_rn_recordset& recset, const long sog_codice)
{
  //cerca, per il soggetto in questione, quale � l'ultima donazione e aggiunge quella nuova
  TLocalisamfile donaz(LF_DONAZ);
  const long next_donaz = trova_prossimo(donaz, sog_codice);

  //dopo essersi posizionato correttamente, agiunge la donazione
  donaz.zero();
  donaz.put(DON_CODICE, sog_codice);
  donaz.put(DON_PROGDON, next_donaz);
  const TDate& dataesame = recset.get_date("DATADON");
  donaz.put(DON_DATADON, dataesame);
  const TString& tipopre = decode_prelievo(recset.get("TIPOPRE").as_string());
  donaz.put(DON_TIPODON, tipopre);
  const int unita = recset.get("NROUNITA").as_int();
  donaz.put(DON_ETICHETTA, unita);
  //controllo soggetto-sezione-sottosezione
  TLocalisamfile soggetti(LF_SOGGETTI);
  soggetti.put(SOG_CODICE, sog_codice);
  int err = soggetti.read();
  if (err == NOERR) //dovrebbe esserlo sempre, perch� il controllo � stato fatto all'inizio di elabora
  {
    const TString& codsez = soggetti.get(SOG_CODSEZ);
    donaz.put(DON_CODSEZ, codsez);
    const TString& codsot = soggetti.get(SOG_CODSOT);
    donaz.put(DON_CODSOT, codsot);
  }
  //caso della prima donazione (donatore vergine e martire)
  if (next_donaz == 1 && soggetti.get_int(SOG_DONPRECSI) == 0 && soggetti.get_int(SOG_DONPRECAF) == 0)
    donaz.put(DON_PRIMADON, 'X');

  //controllo del luogo donazione
  const TString& luogodon2 = decode_luogo(recset.get("LUOGO2").as_string());
  if (luogodon2.full())
    donaz.put(DON_LUOGODON, luogodon2);
  else
  {
    const TString& luogodon4 = decode_luogo(recset.get("LUOGO4").as_string());
    if (luogodon4.full())
      donaz.put(DON_LUOGODON, luogodon4);
    else
      donaz.put(DON_LUOGODON, "1A");
  }
  
  err = donaz.write();
  //se riesce a scrivere la nuova donazione, aggiorna il log ed il soggetto
  if (err == NOERR)
    msg_aggiunge_qualcosa(donaz.curr());
}


bool TImporta_ct_rn::importa_dati(const TFilename& name)
{
  //lista sezioni senza controlli (viene riempita una volta per tutte all'inizio)
  //� qui e non nella create perch� dopo una esecuzione del programma si potrebbe modificare..
  //..la lista delle sezioni (non capita da 15 anni, per� non si sa mai...)
  TSheet_field& sf_nocontrol_sez = _mask->sfield(F_SEZIONI);
  const int righe_sheet = sf_nocontrol_sez.items();

  FOR_EACH_SHEET_ROW(sf_nocontrol_sez, i, row)
  {
    TString4 sh_sezione = row->get(0);
    _nocontrol_sezioni.add(sh_sezione, sh_sezione);
  }

  //recordset di importazione
  TImporta_ct_rn_recordset recset(name);
  TLocalisamfile soggetti(LF_SOGGETTI);
  soggetti.setkey(2);

  TProgind pi(recset.items(), TR("Importazione dati da file..."), true, true);

  for (bool ok = recset.move_first(); ok; ok = recset.move_next())
  {
    if (!pi.addstatus(1))
      break;

    //ciclo di importazione e controllo dati
    //va ricavato dalla procedura foxprow dacentro.prg

    //CONTROLLO ESISTENZA DEL SOGGETTO
    //--------------------------------
    TString80 sog_cognome = recset.get("COGNOME").as_string();
    sog_cognome.trim();
    TString80 sog_nome = recset.get("NOME").as_string();
    sog_nome.trim();
    TDate sog_datanasc = recset.get_date("DATANASC");
    
    //cerca il soggetto nel file dei soggetti
    soggetti.put(SOG_COGNOME, sog_cognome);
    soggetti.put(SOG_NOME, sog_nome);
    soggetti.put(SOG_DATANASC, sog_datanasc);

    int err = soggetti.read();
    //se trova il soggetto in anagrafica parte con l'elaborazione...
    if (err == NOERR)
    {
      const long sog_codice = soggetti.get_long(SOG_CODICE);

      //controllo il tipo di prelievo nella tabella di modulo avis C2A
      //il tipoprelievo � nella subtabella 19
      const TString& at_tipopre = decode_prelievo(recset.get("TIPOPRE").as_string());

      //ESAMI E CONTROLLI SANITARI
      //--------------------------
      //se il tipoprelievo � in realt� un esame..
      if (at_tipopre == "****")
      {
        //controlla se la sez del soggetto rifiuta i controlli (lista sezioni sullo sheet)
        const TString& sog_sez = soggetti.get(SOG_CODSEZ);
        const bool sez_no_controlli = _nocontrol_sezioni.is_key(sog_sez);
        //se la sezione ammette i controlli
        if (!sez_no_controlli)
        {
          const TString& at_tipoesame = decode_esame(recset.get("TIPO_ESAME").as_string());
          //se non c'� una decodifica dell'esame avverte sul log
          if (at_tipoesame.blank())
            msg_esame_error(recset, "CONTROLLO", true);
          else
          //controlla se l'esame (detto controllo sanitario in gergo vampiresco) � gi� stato..
          //..inserito oppure lo aggiunge al file dei controlli sanitari
          {
            const TDate& datadon = recset.get_date("DATADON");

            TLocalisamfile contsan(LF_CONTSAN);
            contsan.setkey(2);
            contsan.put(CON_DATACON, datadon);
            contsan.put(CON_CODICE, sog_codice);
            err = contsan.read();
            //se trova il controllo nella lista segnala che esiste gi�..
            if (err == NOERR)
              msg_esame_error(recset, "CONTROLLO", false);
            else  //senn� aggiunge il controllo sanitario..ol�!
            {
              aggiunge_contsan(recset, sog_codice);
            }
          }
        } //if(!sez_no_controlli...
      } //if(at_tipopre=="**..

      //DONAZIONI
      //---------
      else
      {
        //se non c'� una decodifica della donazione avverte sul log
        if (at_tipopre.blank())
          msg_esame_error(recset, "DONAZIONE", true);
        else
        {
          const TDate& datadon = recset.get_date("DATADON");
          const long sog_codice = soggetti.get_long(SOG_CODICE);

          TLocalisamfile donaz(LF_DONAZ);
          donaz.setkey(2);
          donaz.put(DON_DATADON, datadon);
          donaz.put(DON_CODICE, sog_codice);
          err = donaz.read();

          //se trova la donazione nella lista segnala che esiste gi�..
          if (err == NOERR)
            msg_esame_error(recset, "DONAZIONE", false);
          else  //senn� aggiunge la donazione..ol�!
          {
            aggiunge_donazione(recset, sog_codice);
          }
        } //else di if (at_tipopre.blank())
      } //else di if(at_tipopre=="**

      //indipendentemente da ogni cosa controlla contsan avis/ct per lo stato donatore
      controlla_stato_ct_avis(recset, sog_codice);
      //aggiorna tutti i files legati al soggetto
      aggiorna_soggetto(sog_codice);

    }
    else  //if(err==NOERR)...se non trova il soggetto lo deve aggiungere? Per adesso si incazza e avverte l'operatore
      msg_no_sog_error(recset);

  } //for (bool ok = recset.move_first...

  return true;
}



void TImporta_ct_rn::main_loop()
{
  _mask = new  TImporta_ct_rn_mask;

  if (_mask->run() == K_ENTER)
  {
    //ricava il nome del file da importare
    TFilename name = _mask->get(F_PATH);
    name.add(_mask->get(F_NAME));
    //crea il log di importazione
    _log = new TLog_report("SEGNALAZIONI   IMPORTAZIONE");

    //importazione dati ed elaborazione soggetti
    if (importa_dati(name))
    {
      const int items = _log->recordset()->items();
      if (items > 0)
        _log->preview();
      message_box(TR("Importazione file completata"));
    }

    delete _log;
    _log = NULL;
  }

  delete _mask;
  _mask = NULL;
}

bool TImporta_ct_rn::create()
{
  return TSkeleton_application::create();
}


int at9800(int argc, char* argv[])
{
	TImporta_ct_rn app;
	app.run(argc, argv, "Importazione da CT Rimini");
	return 0;
}