#include <form.h>
#include <msksheet.h>
#include <progind.h>
#include <relapp.h>
#include <utility.h>

#include "at4.h"
#include "atlib.h"

// nomi campi maschera
#include "at4500a.h"
          
// nomi dei campi
#include "soggetti.h"
#include "sezioni.h"
#include "convoc.h"
#include "rconvoc.h"

#define ALIAS_CTD -700
#define ALIAS_TCS -200
#define IDON_SI "SI"
#define IDON_AF "AF"
       
class TGestioneConvocazioni: public TRelation_application
{
	static bool filter_func_convoc(const TRelation* rel);

	TMask*					_msk;
	TRelation*   		_rel;
	TRelation*   		_tmprel;
	TRelation*			_relsog;
	TCursor*				_cur;						// cursore per selezione soggetti
	TIsamtempfile*  _tmpconv;
	TIsamtempfile*  _tmprconv;
	TLocalisamfile* _rconvoc;
	TLocalisamfile* _soggetti;
	TLocalisamfile* _sezioni;
	TRecord_array*	_sconvocati;		// sheet convocati
	long 						_lastcod;				// progressivo convocazione da assegnare
	long						_numero;				// numero convocazione
	TDate						_data; 					// data convocazione
	TString16				_punto;					// punto di prelievo
	TString16				_tipo;					// tipo donazione
	TString16				_codsez;				// codice sezione convocata
	TString16				_codsot;				// codice sottogruppo
	TString16				_modconv;				// modalita di convocazione
	TDate						_dataini;
	bool						_tutti, _ritarda;		
	int							_maxrit;
	bool						_inserimento;	 
	TBit_array			_modified;
              
protected:
	virtual bool user_create();
	virtual bool user_destroy();
	virtual const char* get_next_key();
	virtual int scrivi(const TMask& m, bool ri);
	virtual int write(const TMask& m);
	virtual int rewrite(const TMask& m);
	virtual int read(TMask& m);
	virtual bool remove();
	virtual bool changing_mask(int mode) { return FALSE; }
	virtual TMask* get_mask( int mode = 0) { return _msk; }
	virtual TRelation* get_relation() const { return _rel; }
  virtual void init_query_insert_mode(TMask& m);
  virtual void init_query_mode(TMask& m) { _inserimento = FALSE; init_query_insert_mode(m);};
  virtual void init_modify_mode(TMask& m);
  virtual void init_insert_mode(TMask& m) { _inserimento = TRUE; init_modify_mode(m); }
	
	static bool nome_handler(TMask_field& f, KEY k);
	static bool codice_handler(TMask_field& f, KEY k);
	static bool convocati_notify(TSheet_field& s, int r, KEY k);
	static bool esegui_handler(TMask_field& f, KEY k);
	static bool sistampa_handler(TMask_field& f, KEY k);
	static bool nostampa_handler(TMask_field& f, KEY k);
	static bool data_handler(TMask_field&f, KEY k);
	static bool dataini_handler(TMask_field&f, KEY k);
	static bool sezione_handler(TMask_field&f, KEY k);
	
public:
	virtual void print();       
	TGestioneConvocazioni() {}
	
};

HIDDEN inline TGestioneConvocazioni& app() { return (TGestioneConvocazioni&) main_app(); }

void TGestioneConvocazioni::init_query_insert_mode(TMask& m)
{
  disable_menu_item(M_FILE_NEW);
  m.hide(-1);
  m.show(-2); 
  m.enable(-3); 
}

void TGestioneConvocazioni::init_modify_mode(TMask& m)
{
  m.show(-1);
  m.hide(-2);
  if (app()._inserimento)
  {
  	m.enable(-3);
		m.set(F_TUTTI, TRUE);				
		m.set(F_MODCONV, "PO");				
  }	 
  else
  	m.disable(-3); 
}

bool TGestioneConvocazioni::filter_func_convoc(const TRelation* rel)
{   
	bool filtrato = FALSE;
	TRectype& sog = rel->curr();
	const long codice = sog.get_long(SOG_CODICE);
	const TString16 cat = sog.get(SOG_CATDON);
	const char stato = modstato_tcs(sog.get(SOG_STATO));
	const TString16 escluso = sog.get(SOG_ESCLUSO);
	const TString16 modconv = sog.get(SOG_MODCONV);
	const bool dimesso = rel->lfile(ALIAS_CTD).get_bool("B0");	
	filtrato = (cat.not_empty() && (stato == 'I' || stato == 'F') && !dimesso && escluso.empty());
	if (filtrato)
		filtrato = ((modconv.empty()) || (modconv == app()._modconv) || (modconv == "IN"));
	if (filtrato)
	{
		filtrato = FALSE;
		const TString16 punto = sog.get(SOG_PUNTORACC);
		const TString16 codsez = sog.get(SOG_CODSEZ);
		const TString16 codsot = sog.get(SOG_CODSOT);
		if (app()._codsez.not_empty())
		{
			filtrato = (codsez == app()._codsez);
			if ((filtrato) && (app()._codsot.not_empty()))
				filtrato = (codsot == app()._codsot);			
			if (filtrato)
				filtrato = ((punto == app()._punto) || punto.empty());
		}				
		else
				filtrato = (punto == app()._punto);
		if (app()._tutti && !filtrato)
			filtrato = (punto == app()._punto);
						
		// filtro per data prossima donazione
		//const TDate dataprossi = sog.get(SOG_DATAPROSSI);
		//filtrato = (dataprossi.ok()) && (dataprossi <= data) && filtrato;
		// filtro per intervallo tra cartoline/solleciti/ritardatari
		if (filtrato)
		{ 
			filtrato = FALSE;
			const TDate data = app()._data;
			//TDate data = app()._dataini; prima era cosi'
			const int numconv = sog.get_int(SOG_NUMCONV);
			const TDate dataultconv = sog.get(SOG_DATACONV);
			const TDate dataultsol = sog.get(SOG_DATAULTSOL);
			TRectype& sez = rel->curr(LF_SEZIONI);
			const int giocarsol = sez.get_int(SEZ_GIOCARSOL);
			const int giosolsol = sez.get_int(SEZ_GIOSOLSOL);
			const int gioultsol = sez.get_int(SEZ_GIOULTSOL);
			const int giorit = sez.get_int(SEZ_GIOPERRIT);
			const int numsol = sez.get_int(SEZ_NUMMAXSOL);
			if (numconv == 0)
				filtrato = TRUE;
			else			
				if ((numconv == 1) && (data-dataultconv>=giocarsol))
					filtrato = TRUE;
				else
					if ((numconv >= 2 && numconv <= numsol-1) && (data-dataultconv >= giosolsol))
						filtrato = TRUE;
					else
						if ((numconv == numsol && numsol > 0) && (data-dataultconv >= gioultsol))
							filtrato = TRUE;
						else
							if ((numconv > numsol && numsol > 0) && (app()._ritarda) && (data-dataultsol<=app()._maxrit) && (data-dataultconv>=giorit))
				      	filtrato = TRUE;
		}			      	
	}		
  return filtrato;
}

bool TGestioneConvocazioni::sezione_handler(TMask_field& f, KEY k)
{ 
	if (f.to_check(k))
	{
		TMask& m = f.mask();
		if (m.get(F_DATAINI).empty() && (m.mode() == MODE_INS))
		//if (m.mode() == MODE_INS)
		{
			//const TString16 codsez = m.get(F_CODSEZ);
			//const TString16 codsot = m.get(F_CODSOT);		
			TLocalisamfile sez(LF_SEZIONI);
			sez.setkey(1);
			TRectype& recsez = sez.curr();
			recsez.zero();
			recsez.put(SEZ_CODSEZ, m.get(F_CODSEZ));
			recsez.put(SEZ_CODSOT, m.get(F_CODSOT));
			if (sez.read() == NOERR)
			{
				TDate data = sez.get_date(SEZ_DATAULTCON);
				++data;
				if (data <= m.get_date(F_DATA) && data.ok())
				{
					m.set(F_DATAINI, data);				
					m.check_field(F_DATAINI);
				}					
			}			
		}			
	}
	return TRUE;
}

bool TGestioneConvocazioni::data_handler(TMask_field& f, KEY k)
{
	if (f.to_check(k))
	{
		const TDate data = f.get();
		const int giorno = data.wday();
		TString16 datagio = "";
		switch (giorno)
		{
			case 1:
				datagio = "Lunedi";
			break;
			case 2:
				datagio = "Martedi";
			break;
			case 3:
				datagio = "Mercoledi";
			break;
			case 4:
				datagio = "Giovedi";
			break;
			case 5:
				datagio = "Venerdi";
			break;
			case 6:
				datagio = "Sabato";
			break;
			case 7:
				datagio = "Domenica";
			break;
		}
		f.mask().set(F_DATAGIO,datagio);
	}
	return TRUE;
}

bool TGestioneConvocazioni::dataini_handler(TMask_field& f, KEY k)
{
	if (f.to_check(k))
	{
		const TDate data = f.get();
		if (data > f.mask().get_date(F_DATA))
			return f.error_box("ATTENZIONE! La data iniziale non puo' essere superiore alla data finale");
		const int giorno = data.wday();
		TString16 datagio = "";
		switch (giorno)
		{
			case 1:
				datagio = "Lunedi";
			break;
			case 2:
				datagio = "Martedi";
			break;
			case 3:
				datagio = "Mercoledi";
			break;
			case 4:
				datagio = "Giovedi";
			break;
			case 5:
				datagio = "Venerdi";
			break;
			case 6:
				datagio = "Sabato";
			break;
			case 7:
				datagio = "Domenica";
			break;
		}
		f.mask().set(F_DATAINIGIO,datagio);
	}
	return TRUE;
}

bool TGestioneConvocazioni::esegui_handler(TMask_field& f, KEY k)
{
	if (k == K_SPACE)
	{
		f.disable();
		TMask& m = f.mask();
		TCursor* cur = app()._cur;
		app()._numero	 = m.get_long(F_NUMERO);		                     
	 	app()._data		 = m.get(F_DATA);
		app()._punto	 = m.get(F_PUNTO);
		app()._tutti	 = m.get_bool(F_TUTTI);
		app()._tipo		 = m.get(F_TIPO);
		app()._codsez	 = m.get(F_CODSEZ);
		app()._codsot	 = m.get(F_CODSOT);
	 	app()._dataini = m.get(F_DATAINI);
	 	if (app()._dataini.empty())
	 		app()._dataini = app()._data;
	 	app()._ritarda = m.get_bool(F_RITARDA);
	 	app()._maxrit  = m.get_int(F_MAXRIT);
	 	app()._modconv  = m.get(F_MODCONV);
		if (app()._numero == 0 || !app()._data.ok() || app()._punto.empty() || app()._tipo.empty())
			return f.error_box("Mancano i dati fondamentali per la convocazione");
    const TDate data = app()._data;
    const TDate dataini = app()._dataini;
    TDate datalimite = dataini;
    datalimite.set_year(datalimite.year()-2);
		// filtro per data prossima donazione
  	TRectype da(LF_SOGGETTI);
  	TRectype a(LF_SOGGETTI);
		da.put(SOG_DATAPROSSI,datalimite);
		a.put(SOG_DATAPROSSI,data);
		cur->setregion(da, a);
		cur->set_filterfunction(filter_func_convoc, TRUE);
		app()._modified.reset();
		TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI);
		s.destroy();
    TRectype& rec = cur->curr();
		TRectype& sez = cur->curr(LF_SEZIONI);
    int nconv=0;
    int nsoll=0;
    int nrit=0;
    TDate datasog = data;
   	const int giorni = (int)(data-dataini);	// giorni su cui suddividere la chiamata -1
   	const int dim = giorni+1;
 		int* numperdata = new int[dim];
 		int quanti = ((int)(cur->items())/(giorni+1))+1; // quanti donatori per giorno
 		if (quanti < 1)
 			quanti = 1;
 		for (int i=0; i<giorni+1; i++)
 			numperdata[i] = 0;
    long last = cur->items();   
    int r=0;
    TProgind prg (last, "Elaborazione in corso... Prego attendere", FALSE, TRUE, 30);
    for ( *cur=0; cur->pos() < last; ++(*cur) )
    { 
      prg.addstatus(1);
      TDate datarif(NULLDATE);
			const int numconv = rec.get_int(SOG_NUMCONV);
			const TDate dataultconv = rec.get(SOG_DATACONV);
			const TDate dataultsol = rec.get(SOG_DATAULTSOL);
			const TDate dataprossi = rec.get(SOG_DATAPROSSI);
			const int giocarsol = sez.get_int(SEZ_GIOCARSOL);
			const int giosolsol = sez.get_int(SEZ_GIOSOLSOL);
			const int gioultsol = sez.get_int(SEZ_GIOULTSOL);
			const int giorit = sez.get_int(SEZ_GIOPERRIT);
			const int numsol = sez.get_int(SEZ_NUMMAXSOL);
			char chiamata = ' ';
			if (numconv == 0)
			{
				chiamata = 'C';
				datarif = dataprossi;
			}				
			else			             
			{
				if ((numconv == 1) && (data-dataultconv>=giocarsol))
				{
					chiamata = 'S';
					datarif = dataultconv+(long)giocarsol;
				}					
				else                              
				{
					if ((numconv >= 2 && numconv <= numsol-1) && (data-dataultconv >= giosolsol))
					{
						chiamata = 'S';
						datarif = dataultconv+(long)giosolsol;
					}						
					else
					{
						if ((numconv == numsol && numsol > 0) && (data-dataultconv >= gioultsol))
						{
							chiamata = 'S';
							datarif = dataultconv+(long)gioultsol;
						}							
						else
						{
							if ((numconv > numsol && numsol > 0) && (app()._ritarda) && (data-dataultsol<=app()._maxrit) && (data-dataultconv>=giorit))
							{
				      	chiamata = 'R';
				      	datarif = dataultconv+(long)giorit;
							}				      	
						}				      	
					}				      	
				}				      	
			}				      	
			if (dataprossi<=data)
			{
				switch (chiamata)
				{
					case 'C':
						nconv++;
					break;
					case 'S':
						nsoll++;
					break;
					case 'R':
						nrit++;
					break;
				}				
				if (giorni > 0)
				{
					datasog = NULLDATE;
					int partenza;
					if (datarif <= dataini)
						partenza = 0;					
					else  
						partenza = (int)(datarif-dataini);
											
					for (int r=partenza;r<=giorni;r++)
					{
						if ((numperdata[r]<quanti) && (!datasog.ok()))
						{
							datasog = dataini+(long)(r);
							numperdata[r]++;
						}						
					}					
					if (!datasog.ok())
					{
						//if (dataprossi < dataini)
						//	datasog = dataini;
						//else
						//	datasog = dataprossi;						
						datasog = datarif;   //aggiunto da Marco in data 24/09/99 per sostituire le azioni commentate in quanto non rispettava gli intervalli fra cartoline
					}					
				}
				TToken_string& row = s.row(r);
				row.add(rec.get(SOG_CODICE));
				row.add(rec.get(SOG_COGNOME));
				row.add(rec.get(SOG_NOME));
				row.add(datasog);
				row.add(chiamata);
				row.add(' '); // stampato
				row.add(' '); // annullato
				row.add(rec.get(SOG_DATANASC));
				row.add(rec.get(SOG_CATDON));
				row.add(rec.get(SOG_TESSAVIS));
				row.add(rec.get(SOG_CODSEZ));
				row.add(rec.get(SOG_CODSOT));
				row.add(rec.get(SOG_DATAULTDON));
				row.add(rec.get(SOG_DATAPROSSI));
	      r++;
			}	      
		}
		m.set(F_NUMCONV,nconv);
		m.set(F_NUMSOLL,nsoll);
		m.set(F_NUMRIT,nrit);
		s.force_update();
		delete numperdata;
	}
	return TRUE;
}

bool TGestioneConvocazioni::sistampa_handler(TMask_field& f, KEY k)
{
	if (k == K_SPACE)
	{
		TSheet_field& s = f.mask().sfield(F_CONVOCATI);
		const int pos = s.cid2index(F_S_STAMPATO);
		const int posann = s.cid2index(F_S_ANNULLATO);
		FOR_EACH_SHEET_ROW(s,r,row)
			if (row->get(posann)[0] != 'X')			
				row->add('X',pos);
		s.force_update();
	}
	return TRUE;
}

bool TGestioneConvocazioni::nostampa_handler(TMask_field& f, KEY k)
{
	if (k == K_SPACE)
	{
		TSheet_field& s = f.mask().sfield(F_CONVOCATI);
		const int pos = s.cid2index(F_S_STAMPATO);
		const int posann = s.cid2index(F_S_ANNULLATO);
		FOR_EACH_SHEET_ROW(s,r,row)
			if (row->get(posann)[0] != 'X')			
				row->add(' ',pos);
		s.force_update();
	}
	return TRUE;
}
  
bool TGestioneConvocazioni::nome_handler(TMask_field& f, KEY k)
{
	bool ok = TRUE;
  if (f.to_check(k))
  {
  	TMask& m = f.mask();
  	long codsog = m.get_long(F_S_CODICE);
  	if (codsog == 0)
      f.on_key(K_F9);
  }	
  return ok;
}

bool TGestioneConvocazioni::codice_handler(TMask_field& f, KEY k)
{
	bool ok = TRUE;
  if (f.to_check(k))
  {
  	TMask& m = f.mask();
  	long codsog = m.get_long(F_S_CODICE);
  	if (codsog != 0)
  	{
			TLocalisamfile sog(LF_SOGGETTI); ;
  		sog.setkey(1);	
			sog.zero();
			sog.put(SOG_CODICE, codsog);
			int err = sog.read();
			if (err == NOERR)
			{
  			m.set(F_S_COGNOME, sog.get(SOG_COGNOME));
  			m.set(F_S_NOME, sog.get(SOG_NOME));
  			m.set(F_S_DATANASC, sog.get(SOG_DATANASC));
  			m.set(F_S_TESSAVIS, sog.get(SOG_TESSAVIS));
  			m.set(F_S_CODSEZ, sog.get(SOG_CODSEZ));
  			m.set(F_S_CODSOT, sog.get(SOG_CODSOT));
  			m.set(F_S_CATDON, sog.get(SOG_CATDON));
  			m.set(F_S_DATAULTDON, sog.get(SOG_DATAULTDON));
  			m.set(F_S_DATAPROSSI, sog.get(SOG_DATAPROSSI));
			}  			
			else
				ok = FALSE; // codice non esistente  			
  	}
  }	
  return ok;
}
  
bool TGestioneConvocazioni::user_create()
{
  _tmpconv = new TIsamtempfile(LF_CONVOC,NULL,TRUE,TRUE);
  _tmprconv = new TIsamtempfile(LF_RCONVOC,NULL,TRUE,TRUE);

	_tmprel = new TRelation(LF_CONVOC);
  _tmprel->add(LF_RCONVOC, "CODICE==CODICE");

	_msk = new TMask("at4500a");
	_rel = new TRelation(LF_CONVOC);
	_relsog = new TRelation(LF_SOGGETTI);
  _relsog->add("CTD", "CODTAB==CATDON",1,0,-ALIAS_CTD);
  _relsog->add("TCS", "CODTAB==STATO",1,0,-ALIAS_TCS);
  _relsog->add(LF_SEZIONI, "CODSEZ==CODSEZ|CODSOT==CODSOT");
	// ordinamento per data prossima donazione  
  _cur = new TCursor(_relsog, "", 5);
	_rconvoc = new TLocalisamfile(LF_RCONVOC);
	_soggetti = new TLocalisamfile(LF_SOGGETTI);
	_sconvocati = new TRecord_array(LF_RCONVOC,RCV_PROGCONV);
	_msk->set_handler(F_SISTAMPA,sistampa_handler);
	_msk->set_handler(F_NOSTAMPA,nostampa_handler);
	_msk->set_handler(F_ESEGUI,esegui_handler);
	_msk->set_handler(F_DATA,data_handler);	
	_msk->set_handler(F_DATAINI,dataini_handler);	
	_msk->set_handler(F_CODSEZ,sezione_handler);
	_msk->set_handler(F_CODSOT,sezione_handler);
	TSheet_field& sc = (TSheet_field&)_msk->field(F_CONVOCATI);
	sc.set_notify(convocati_notify);
	sc.sheet_mask().set_handler(F_S_NOME,nome_handler);
	sc.sheet_mask().set_handler(F_S_CODICE,codice_handler);
	
	_rel->lfile().last();
	_lastcod = _rel->lfile().get_long(COV_NUMERO);
  enable_menu_item(M_FILE_PRINT);
	return TRUE;
}	
	
bool TGestioneConvocazioni::user_destroy()	
{             
	delete _sconvocati;
	delete _soggetti;
	delete _rconvoc;
	delete _cur;
	delete _relsog;
	delete _rel;
	delete _msk;
	delete _tmprel;
	delete _tmprconv;
	delete _tmpconv;
	return TRUE;
}

const char* TGestioneConvocazioni::get_next_key()
{
	// autonumerazione progressiva delle convocazioni
	_rel->lfile().last();
	_lastcod = _rel->lfile().get_long(COV_NUMERO);	
	return format("%d|%ld", F_NUMERO, _lastcod+1 );
}	

bool TGestioneConvocazioni::remove()
{
  TWait_cursor hourglass;

 	// cancella convocati
 	// cancella testata convocazione
 	bool ok = TRUE;
 	// cancella convocati
 	// prima cancella dall'archivio soggetti la data ultima convocazione
	TLocalisamfile soggetti(LF_SOGGETTI);
	soggetti.setkey(1);
	TLocalisamfile rconvoc(LF_RCONVOC);
	rconvoc.setkey(3);
	for (int r=1; r<=_sconvocati->rows(); r++)
	{
		const TRectype& riga = _sconvocati->row(r);
		const long codice = riga.get_long(RCV_CODICE);
		const TDate dataconv = riga.get_date(RCV_DATACONV);
		soggetti.put(SOG_CODICE,codice);
		if (soggetti.read() == NOERR) 
		{ 
			const TDate dataprossi = soggetti.get_date(SOG_DATAPROSSI);
			int numconv = soggetti.get_int(SOG_NUMCONV);
			if (numconv > 0)
			{
				numconv--;
				soggetti.put(SOG_NUMCONV,numconv);
				rconvoc.put(RCV_CODICE,codice);
				rconvoc.put(RCV_DATACONV,dataconv);			
				if (rconvoc.read() == NOERR)
				{           
					bool ok = TRUE;
					while (ok)
					{
						--rconvoc;
						const long codprec = rconvoc.get_long(RCV_CODICE);
						if (codprec == codice)
						{
							if (rconvoc.get(RCV_ANNULLATO)[0] != 'X')
							{
								ok = FALSE;
								soggetti.put(SOG_DATACONV, rconvoc.get(RCV_DATACONV));
							}	
						}	
						else
						{
							ok = FALSE;
							soggetti.put(SOG_NUMCONV, 0);
							soggetti.put(SOG_DATACONV, NULLDATE);
							soggetti.put(SOG_DATAULTSOL, NULLDATE);
						}											
					}	
					if (numconv == 1)
						soggetti.put(SOG_DATAULTSOL, NULLDATE);									
				}				
				else
				{
					soggetti.put(SOG_NUMCONV, 0);
					soggetti.put(SOG_DATACONV, NULLDATE);
					soggetti.put(SOG_DATAULTSOL, NULLDATE);
				}				
			}
			else
			{
				soggetti.put(SOG_NUMCONV, 0);
				soggetti.put(SOG_DATACONV, NULLDATE);
				soggetti.put(SOG_DATAULTSOL, NULLDATE);
			}				
			const TDate dataconvsog = soggetti.get_date(SOG_DATACONV);
			if (dataconvsog < dataprossi)
			{
				soggetti.put(SOG_NUMCONV, 0);
				soggetti.put(SOG_DATACONV, NULLDATE);
				soggetti.put(SOG_DATAULTSOL, NULLDATE);
			}				
			soggetti.rewrite();
		}			
	}
	int err = _sconvocati->remove();	
  if (err == _iseof || err == _isemptyfile)
		err = NOERR;
	if (err == NOERR)
	{
		TLocalisamfile sez(LF_SEZIONI);
		sez.setkey(1);
		sez.zero();         
		
		TMask& m = curr_mask();
		sez.put(SEZ_CODSEZ, m.get(F_CODSEZ));
		sez.put(SEZ_CODSOT, m.get(F_CODSOT));
		if (sez.read() == NOERR)
		{ 
			TLocalisamfile convoc(LF_CONVOC);
			convoc.setkey(3);
			convoc.put(COV_CODSEZ, m.get(F_CODSEZ));
			convoc.put(COV_CODSOT, m.get(F_CODSOT));
			convoc.put(COV_DATA, m.get(F_DATA));
			convoc.read();			
			--convoc;
			TDate dataini = convoc.get_date(COV_DATAINI);
			TDate datanulla(NULLDATE);
			while (!convoc.eof() && (dataini == datanulla))
			{
				--convoc;
				dataini = convoc.get_date(COV_DATAINI);
			}				
			if ((convoc.get(COV_CODSEZ) == m.get(F_CODSEZ)) && (convoc.get(COV_CODSOT) == m.get(F_CODSOT)))
				sez.put(SEZ_DATAULTCON, convoc.get_date(COV_DATA));
			else				
				sez.put(SEZ_DATAULTCON,NULLDATE);
			sez.rewrite();
		}		
	}	
	// cancella la testata
	if (err == NOERR) ok = TRelation_application::remove();
	return (ok && err == NOERR);
}

int TGestioneConvocazioni::read(TMask& m)
{
	int err = TRelation_application::read(m);
	if (err == NOERR)
	{ 
	  TRectype* key = new TRectype(LF_RCONVOC);
		key->put(RCV_NUMERO, m.get(F_NUMERO));
		err = _sconvocati->read(key);
		if (err == NOERR)
		{
			TLocalisamfile soggetti(LF_SOGGETTI);
			TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI);
			app()._modified.reset();
			s.destroy();
			for (int r=1; r<=_sconvocati->rows(); r++)
			{
				TToken_string& row = s.row(r-1);
				const TRectype& riga = _sconvocati->row(r);
				const TString& codice = riga.get(RCV_CODICE);
				row.add(codice);
				soggetti.put(SOG_CODICE,codice);
				if (soggetti.read() != NOERR) 
					soggetti.zero();
				row.add(soggetti.get(SOG_COGNOME));
				row.add(soggetti.get(SOG_NOME));
				row.add(riga.get(RCV_DATACONV));
				row.add(riga.get(RCV_CHIAMATA));
				row.add(riga.get(RCV_STAMPATO));
				row.add(riga.get(RCV_ANNULLATO));
				row.add(soggetti.get(SOG_DATANASC));
 				row.add(soggetti.get(SOG_CATDON));
				row.add(soggetti.get(SOG_TESSAVIS));
				row.add(soggetti.get(SOG_CODSEZ));
				row.add(soggetti.get(SOG_CODSOT));
				row.add(soggetti.get(SOG_DATAULTDON));
				row.add(soggetti.get(SOG_DATAPROSSI));
			}
		}
		else
		  if (err == _iseof || err == _isemptyfile)
		    err = NOERR;
	}
	return err;
}

int TGestioneConvocazioni::write(const TMask& m)
{  
	long curcod = m.get_long(F_NUMERO);
	if (curcod > _lastcod) _lastcod = curcod;
	_inserimento = FALSE;
	return TGestioneConvocazioni::scrivi(m, FALSE);	
}

int TGestioneConvocazioni::rewrite(const TMask& m)
{
	return TGestioneConvocazioni::scrivi(m, TRUE);	
}

int TGestioneConvocazioni::scrivi(const TMask& m, bool ri)
{                             
	int err = ri ? TRelation_application::rewrite(m) : TRelation_application::write(m);
	if (err == NOERR)
	{
		TLocalisamfile sez(LF_SEZIONI);
		sez.setkey(1);
		sez.zero();
		sez.put(SEZ_CODSEZ, app()._codsez);
		sez.put(SEZ_CODSOT, app()._codsot);
		if (sez.read() == NOERR)
		{
			sez.put(SEZ_DATAULTCON, app()._data);
			sez.rewrite();
		}		
		TLocalisamfile soggetti(LF_SOGGETTI);
		_sconvocati->destroy_rows();
		TRectype* key = new TRectype(LF_RCONVOC);
		key->put(RCV_NUMERO, m.get(F_NUMERO));
		_sconvocati->set_key(key);
		TSheet_field& s = (TSheet_field&)m.field(F_CONVOCATI);
		TProgind prg (s.items(), "Registrazione in corso... Prego attendere", FALSE, TRUE, 30);
		for (int r=s.items(); r>0; r--)
		{
  	  prg.addstatus(1);
			TToken_string& row = s.row(r-1);
			TRectype& rec = _sconvocati->row(r,TRUE);
			const long codice = row.get_long(0);			
			const TDate dataconv = row.get(3);
			const char chiamata = row.get_char(4);
			const bool annullato = (row.get(6)[0] == 'X');
			rec.put(RCV_CODICE,codice);
			rec.put(RCV_DATACONV,dataconv);
			rec.put(RCV_CHIAMATA,chiamata);
			rec.put(RCV_STAMPATO,row.get(5));
			rec.put(RCV_ANNULLATO,row.get(6));
	  }
		err = ri ? _sconvocati->rewrite() : _sconvocati->write();
		if (err == NOERR)
		{
			for (int r=s.items(); r>0; r--)
			{
	  	  prg.addstatus(1);
				TToken_string& row = s.row(r-1);
				//TRectype& rec = _sconvocati->row(r,TRUE);
				const long codice = row.get_long(0);			
				const TDate dataconv = row.get(3);
				const char chiamata = row.get_char(4);
				const bool annullato = (row.get(6)[0] == 'X');
				//rec.put(RCV_CODICE,codice);
				//rec.put(RCV_DATACONV,dataconv);
				//rec.put(RCV_CHIAMATA,chiamata);
				//rec.put(RCV_STAMPATO,row.get(5));
				//rec.put(RCV_ANNULLATO,row.get(6));
				// aggiornamento archivio soggetti
				soggetti.put(SOG_CODICE,codice);
				/* Messo il < invece del != nel primo if, spostato il controllo se sollecito
					o meno all'interno del controllo sulla data da Marco in data 23/08/99
				*/
				if (soggetti.read() == NOERR) 
				{
					if (soggetti.get_date(SOG_DATACONV) < dataconv)  //Aggiungo 30/08/99 da qui
					{
						if (!_modified[r-1] && (!annullato))
						{                                                //Fino a qui
							if (chiamata == 'S')
								soggetti.put(SOG_DATAULTSOL,dataconv);
							soggetti.put(SOG_DATACONV,dataconv);
							int numconv = soggetti.get_int(SOG_NUMCONV);
							soggetti.put(SOG_NUMCONV,numconv+1);
						}                                                  //Aggiungo 30/08/99 da qui
						else
						{
							if (_modified[r-1] && (!annullato))
							{
								if (chiamata == 'S')
									soggetti.put(SOG_DATAULTSOL,dataconv);
								soggetti.put(SOG_DATACONV,dataconv);
							}                                                       
							else
							{
								if (_modified[r-1] && (annullato))
								{
									const TDate dataprossi = soggetti.get_date(SOG_DATAPROSSI);
									int numconv = soggetti.get_int(SOG_NUMCONV);
									numconv--;
									if (numconv > 0)
										soggetti.put(SOG_NUMCONV,numconv);
									TRectype da(LF_RCONVOC);
									da.put(RCV_CODICE,codice);
									TRectype a(LF_RCONVOC);
									a.put(RCV_CODICE,codice);
									TRelation rel(LF_RCONVOC);
									TCursor cur(&rel,"",3,&da,&a);
									const TRecnotype convocazioni = cur.items();
									TRectype& rec = cur.curr();
									for (TRecnotype pos = convocazioni-2; pos>=0; pos--)
									{
										cur = pos;
										//TRectype& rec = cur.curr();
										if (rec.get(RCV_ANNULLATO)[0] != 'X')	
										{
											soggetti.put(SOG_DATACONV, rec.get(RCV_DATACONV));									
											break;
										}
									}
									if (pos < 0)
									{
										soggetti.put(SOG_NUMCONV, 0);
										soggetti.put(SOG_DATACONV, NULLDATE);
										soggetti.put(SOG_DATAULTSOL, NULLDATE);
									}
									else
									{
									 	if (numconv > 1)
											soggetti.put(SOG_DATAULTSOL, rec.get(RCV_DATACONV));
										else
											soggetti.put(SOG_DATAULTSOL, NULLDATE);									
									}
									const TDate dataconvsog = soggetti.get_date(SOG_DATACONV);
									if (dataconvsog < dataprossi)
									{
										soggetti.put(SOG_NUMCONV, 0);
										soggetti.put(SOG_DATACONV, NULLDATE);
										soggetti.put(SOG_DATAULTSOL, NULLDATE);
									}
								}		
							}
						}																								
					}
					else
					{
						if ((annullato) && (dataconv == soggetti.get_date(SOG_DATACONV)))
						{
							const TDate dataprossi = soggetti.get_date(SOG_DATAPROSSI);
							int numconv = soggetti.get_int(SOG_NUMCONV);
							numconv--;
							if (numconv > 0)
								soggetti.put(SOG_NUMCONV,numconv);
							TLocalisamfile rconvoc(LF_RCONVOC);
							rconvoc.setkey(3);
							rconvoc.put(RCV_CODICE,codice);
							rconvoc.put(RCV_DATACONV,dataconv);			
							if (rconvoc.read() == NOERR)
							{           
								bool ok = TRUE;
								while (ok)
								{
									--rconvoc;
									const long codprec = rconvoc.get_long(RCV_CODICE);
									if (codprec == codice)
									{
										if (rconvoc.get(RCV_ANNULLATO)[0] != 'X')
										{
											ok = FALSE;
											soggetti.put(SOG_DATACONV, rconvoc.get(RCV_DATACONV));
										}	
									}	
									else
									{
										ok = FALSE;
										soggetti.put(SOG_NUMCONV, 0);
										soggetti.put(SOG_DATACONV, NULLDATE);
										soggetti.put(SOG_DATAULTSOL, NULLDATE);
									}											
								}	
								if (numconv > 1) 
									soggetti.put(SOG_DATAULTSOL, rconvoc.get(RCV_DATACONV));
								else
									soggetti.put(SOG_DATAULTSOL, NULLDATE);
							}				
							const TDate dataconvsog = soggetti.get_date(SOG_DATACONV);
							if (dataconvsog < dataprossi)
							{
								soggetti.put(SOG_NUMCONV, 0);
								soggetti.put(SOG_DATACONV, NULLDATE);
								soggetti.put(SOG_DATAULTSOL, NULLDATE);
							}
						}
					}                                               //Fino a qui
					soggetti.rewrite();
				}			
			}
			//err = ri ? _sconvocati->rewrite() : _sconvocati->write();
			message_box("Convocazione registrata");
		}
		else
  		error_box("Errore %d durante la scrittura. Convocazione non registrata correttamente", err);
	}	
	else
		error_box("Errore %d durante la scrittura. Convocazione non registrata correttamente", err);
	return err;
}

bool TGestioneConvocazioni::convocati_notify(TSheet_field& s, int r, KEY k)
{              
	static TToken_string oldrow;
	bool result = TRUE;
	switch (k)
	{ 
	  /* Tolto da Marco in data 26/08/99 in quanto si vuole impedire l'eliminazione di una singola riga
	  		dello sheet dei convocati
	  case K_CTRL+K_DEL: // avvenuta cancellazione riga
		{               
			int numconv = s.mask().get_int(F_NUMCONV);
			s.mask().set(F_NUMCONV,numconv-1);
		}
		break;                       
		
			Aggiunto da Marco in data 26/08/99 per impedire l'eliminazione di una singola riga dallo sheet 
			dei convocati
		*/
		case K_DEL: //richiesta cancellazione riga
		{
			message_box("Impossibile eliminare la convocazione di un singolo soggetto!/n Eventualmente annullarla.");
			result = FALSE;
		}
		  break;                    
		// Aggiunto da Marco in data 26/08/99 per gestire la modifica di una singola convocazione
		case K_SPACE:
		{
		  oldrow = s.row(r);
		  TDate olddata = oldrow.get(s.cid2index(F_S_DATACONV));   // Le righe seguenti impostano un blocco per impedire di modificare una convocazione che non sia l'ultima per il soggetto
		  const long codice = oldrow.get_long(0); 
		  TLocalisamfile soggetti(LF_SOGGETTI);
		  soggetti.put(SOG_CODICE,codice);
		  if (soggetti.read() == NOERR)
		  	  if (olddata != soggetti.get_date(SOG_DATACONV))
		  	  	{
		  	  	message_box("Impossibile modificare una convocazione che non sia l'ultima per il soggetto in questione.");
		  	  	result = FALSE;
		  	  	s.row(r) = oldrow;
		  	  	s.force_update();
		  	  	}
		}
		  break;		
		case K_ENTER:
		{
		  TToken_string& newrow = s.row(r);
		  TDate olddata = oldrow.get(s.cid2index(F_S_DATACONV));
		  TDate newdata = newrow.get(s.cid2index(F_S_DATACONV));
		  if (newdata != olddata)
		  {
		  	app()._modified.set(r);
		  }
		}
      break;
		case K_CTRL+K_TAB:
		// uscita riga
		{ 
			TToken_string& row = s.row(r);
			const long codsog = row.get_long(0);
			if (codsog != 0)
				for (int i=s.items()-1; i>=0; i--)
				{
					if (i != r)
					{
						TToken_string& row = s.row(i); 
						if (codsog == row.get_long(0))
							return s.sheet_mask().field(F_S_CODICE).error_box("Soggetto gia' inserito");
					}					
				}				
			else
			{
				const char* cognome = row.get(1);
				if ((cognome != NULL) && (cognome != "\0"))
					s.sheet_mask().field(F_S_NOME).set_focusdirty();
					//s.set_focus_cell(r,2);
			}
		}
	  break;  	
		case K_CTRL+K_INS:
		{
			int numconv = s.mask().get_int(F_NUMCONV);
			s.mask().set(F_NUMCONV,numconv+1);
		}
		break;
		case K_INS:
			result = FALSE;
		break;
	}
  return result;  
}

void TGestioneConvocazioni::print()
{
	TForm	elenco("ATCONVOC");
	TCursor& cur = *elenco.cursor();
	if (_inserimento)
	{
		message_box("Convocazione non registrata; non � possibile la stampa");
	}
	else
	{
		TLocalisamfile& convoc = cur.file();
		const long numero = app()._msk->get_long(F_NUMERO);
		convoc.put(COV_NUMERO, numero);
		cur.read();
		elenco.print(-1);
	}		
}

int at4500(int argc, char* argv[])
{
	TGestioneConvocazioni a;
	a.run(argc, argv, "Gestione convocazione su punto prelievo");
	return 0;
}