
#include <relapp.h>
#include <config.h>
#include <tabutil.h>
#include <mailbox.h>
#include <execp.h>
#include <utility.h>

#include "ve2200.h"
#include "ve2300x.h" // include anche il file dei campi della maschera delle righe
#include "veconf.h"

#define RCONDVEN_APP "ve2 -2 " // nome dell'applicazione di gestione delle righe
#define DESTROY(x) { _msk->field(x).reset_key(1); _msk->hide(x); }
#define KILL(x) { _msk->field(x).reset_key(1); _msk->disable(x); }



class TCondizioni_vendita: public TRelation_application {
	  TMask *_msk; // maschera principale
  	TRelation *_rel; // relazione principale

		TString16 _condven; // stringa che indica il tipo di archivio
		TBit_array _tohide; // vettore degli identificatori di campi che devono essere nascosti
    bool _codlis_catven; // booleano di abilitazione della categoria di vendita nella chiave dei listini
		bool _codcon_codcf; // booleano di abilitazioni dei campi TIPOCF e CODCF
    bool _gest_val, _gest_um, _gest_sca, _gest_so; // booleani per l'abilitazione di valute, unitā di misura, scaglioni e sconti/omaggi
    
	  virtual bool user_create();
  	virtual bool user_destroy();                        
	  virtual TMask *get_mask(int) { return _msk; }
  	virtual bool changing_mask(int) { return FALSE; }
	  virtual TRelation *get_relation() const { return _rel; }

		static bool handle_mask(TMask &, KEY); // handler custom della maschera (per il tasto di aggancio alle righe)
		static bool handle_datacam(TMask_field &, KEY); // handler del campo DATACAM (data cambio)
		static bool handle_valfin(TMask_field &, KEY); // handler del campo VALFIN (data fine validitā)
		static bool handle_codsucc(TMask_field &, KEY); // handler del campo CODSUCC (codice successivo)

	  virtual int write(const TMask &); // metodo usato per scrivere il record sul file
  	virtual int rewrite(const TMask &); // metodo usato per aggiornare il record sul file
		virtual bool remove(); // metodo usato per cancellare il record sul file
  
  public:
	  TCondizioni_vendita() {}
  	virtual ~TCondizioni_vendita() {}
};



TCondizioni_vendita &app() { // funzione che ritorna il riferimento alla classe principale dell'applicazione
  return (TCondizioni_vendita &)main_app();
}



bool TCondizioni_vendita::user_create() {
	bool gotcha= FALSE; // booleano di avvenuta inizializzazione
	
	_condven= "*"; // inizializzazione dell'indicatore del tipo di archivio
	if (argc()>2) _condven= argv(2); // se c'č, prende il tipo di archivio dalla linea di comando
	else {
		TMask choose("VE2200"); // istanzia la maschera di scelta del tipo di archivio
		if (choose.run() == K_ENTER) _condven= choose.get(F_TIPOCV); // prende il tipo di archivio dalla maschera
	}
	_condven.upper(); // rende la stringa upper-case
	_msk= new TMask("VE2200X");
	TConfig prassid(CONFIG_DITTA, "ve"); // apre il file di configurazione della ditta corrente
	switch (_condven[0]) {
		case 'L': { // listini
			if (!(prassid.get_bool("GES", NULL, A_LISTINI))) error_box("L'archivio Listini non č abilititato"); // controlla che l'archivio listini sia abilitato
			else {
				// eliminazione campi di altri archivi
				DESTROY(F_C_COD);
				DESTROY(F_O_COD);
				DESTROY(F_C_TIPOCF);
				DESTROY(F_C_CODCF);
				DESTROY(F_C_OBBLIG);
				DESTROY(F_C_DESCF);
				set_search_field(F_L_COD); // impostazione del campo di ricerca
				_msk->set_handler(F_L_CODSUCC, handle_codsucc); // setta l'handler per il campo di codice successivo
				_codlis_catven= prassid.get_bool("GESLISCV"); // setta il booleano di abilitazione delle categoria di vendita
				if (!_codlis_catven) KILL(F_L_CATVEN); // disabilita condizionalmente le categorie di vendita
				_gest_um= prassid.get_bool("GESUM", NULL, A_LISTINI); // setta il booleano di abilitazione delle unitā di misura
				_gest_sca= prassid.get_bool("GESSCA", NULL, A_LISTINI); // setta il booleano di abilitazione degli scaglioni
				_gest_so= prassid.get_bool("GESSO", NULL, A_LISTINI); // setta il booleano di abilitazione degli sconti/omaggi
 				gotcha= TRUE;
 			}
			break;
		}
		case 'C': // contratti
			if (!(prassid.get_bool("GES", NULL, A_CONTRATTI))) error_box("L'archivio Contratti non č abilititato"); // controlla che l'archivio listini sia abilitato
			else {
				// settaggio dei campi da eliminare
				DESTROY(F_L_COD);
				DESTROY(F_O_COD);
				DESTROY(F_L_CATVEN);
				DESTROY(F_L_DESVEN);
				DESTROY(F_L_CODSUCC);
				DESTROY(F_L_DESSUCC);
		    _codcon_codcf= prassid.get_bool("GESCONCC"); // setta il booleano di abilitazione di TIPOCF e CODCF
		    if (!_codcon_codcf) { // disabilita i campi di gestione clienti/fornitori in base al flag. di config.
		    	KILL(F_C_TIPOCF);
		    	KILL(F_C_CODCF);
		    }
  	    set_search_field(F_C_COD); // impostazione del campo di ricerca
				_gest_um= prassid.get_bool("GESUM", NULL, A_CONTRATTI); // setta il booleano di abilitazione delle unitā di misura
				_gest_sca= prassid.get_bool("GESSCA", NULL, A_CONTRATTI); // setta il booleano di abilitazione degli scaglioni
				_gest_so= prassid.get_bool("GESSO", NULL, A_CONTRATTI); // setta il booleano di abilitazione degli sconti/omaggi
 				gotcha= TRUE;
 			}
			break;
		case 'O': // offerte
			if (!(prassid.get_bool("GES", NULL, A_OFFERTE))) error_box("L'archivio Offerte non č abilititato"); // controlla che l'archivio listini sia abilitato
			else {
				// settaggio dei campi da eliminare
				DESTROY(F_L_COD);
				DESTROY(F_C_COD);
				DESTROY(F_L_CATVEN);
				DESTROY(F_C_TIPOCF);
				DESTROY(F_C_CODCF);
				DESTROY(F_C_DESCF);
				DESTROY(F_L_DESVEN);
				DESTROY(F_C_OBBLIG);
				DESTROY(F_L_CODSUCC);
				DESTROY(F_L_DESSUCC);
				set_search_field(F_O_COD); // impostazione del campo di ricerca
				_gest_um= prassid.get_bool("GESUM", NULL, A_OFFERTE); // setta il booleano di abilitazione delle unitā di misura
				_gest_sca= prassid.get_bool("GESSCA", NULL, A_OFFERTE); // setta il booleano di abilitazione degli scaglioni
				_gest_so= prassid.get_bool("GESSO", NULL, A_OFFERTE); // setta il booleano di abilitazione degli sconti/omaggi
 				gotcha= TRUE;
 			}
			break;		
		default: // messaggio di errore se si indica un archivio non valido
			error_box("Indicare l'archivio sulla linea di comando (L, C o O) oppure selezionarla dalla maschera di partenza");
			break;
	}
	if (gotcha) { // se č stato selezionato correttamente un archivio completa l'inizializzazione
		_rel= new TRelation(LF_CONDV); // apre la relazione (un unico file)
		_msk->set(F_TIPO, _condven); // settaggio del campo di tipo archivio
		_msk->set_handler(handle_mask); // imposta l'handler generale della maschera
		_msk->set_handler(F_DATACAM, handle_datacam); // imposta l'handler per il campo della data del cambio
		_msk->set_handler(F_VALFIN, handle_valfin); // imposta l'handler per il campo di fine validitā
		if (!_gest_um) _msk->disable(F_GESTUM); // disabilita condizionalmente il booleano di gestione delle unitā di misura
		if (!_gest_sca) _msk->disable(F_GESTSCAGL); // disabilita condizionalmente il booleano di gestione degli scaglioni
		if (!_gest_so) _msk->disable(F_GESTSCO); // disabilita condizionalmente il booleano di gestione degli sconti/omaggi
		_gest_val= prassid.get_bool("GESVAL"); // legge il booleano di abilitazione delle gastione delle valute
		if (!_gest_val) { // se la gestione delle valute č disabilitata i campi di gestione vengono disabilitati
			_msk->disable(F_CODVAL);
			_msk->disable(F_CAMBIO);
			_msk->disable(F_DATACAM);
		}
	}
	return (gotcha);
}

bool TCondizioni_vendita::user_destroy() {
  delete _rel;
  delete _msk;
  return TRUE;
}

bool TCondizioni_vendita::handle_mask(TMask &m, KEY k) {
	if (k==K_F5) { // se viene premuto F5 o selezionato il tasto "Righe" viene lanciata l'applicazione di editing
		TString &_condven= app()._condven; // prende l'indicatore del tipo di archivio
		bool &_codlis_catven= app()._codlis_catven; // prende il booleano di attivazione del campo CATVEN
		TString appname(RCONDVEN_APP); // istanzia e inizializza la stringa con il nome dell'applicazione da lanciare
		TString body; // istanzia la stringa contenente il corpo del messaggio (lista di inizializzazione dei campi della maschera)
		switch (_condven[0]) {
			case 'L': // listini
				body << F_R_L_RICERCA << "|"; // appende l'id del campo di ricerca
				body << F_R_TIPO << "=" << _condven << "|"; // appende il filtro sul tipo
				body << F_R_L_CATVEN << "=" << ((_codlis_catven)?(m.get(F_L_CATVEN)):("")) << "|"; // appende il filtro sulla categoria di vendita
				body << F_R_L_COD << "=" << m.get(F_L_COD); // appende il filtro sul campo codice
				break;
			case 'C': // contratti
				body << F_R_C_RICERCA << "|"; // appende l'id del campo di ricerca
				body << F_R_TIPO << "=" << _condven << "|"; // appende il filtro sul tipo
				body << F_R_C_TIPOCF << "=" << m.get(F_C_TIPOCF) << "|"; // appende il filtro sul campo tipo cliente/fornitore
				body << F_R_C_CODCF << "=" << m.get(F_C_CODCF) << "|"; // appende il filtro sul campo codice cliente/fornitore
				body << F_R_C_COD << "=" << m.get(F_C_COD); // appende il filtro sul campo codice
				break;
			case 'O': // offerte
				body << F_R_O_RICERCA << "|"; // appende l'id del campo di ricerca
				body << F_R_TIPO << "=" << _condven << "|"; // appende il filtro sul tipo
				body << F_R_O_COD << "=" << m.get(F_O_COD); // appende il filtro sul campo codice
				break;
		}
		appname << _condven; // aggiunge al lancio dell'applicazione la selezione del tipo di archivio
		TMessage msg(cmd2name(appname), MSG_FS, (const char *)body); // istanzia il messaggio per l'applicazione
		msg.send(); // invia il messaggio all'applicazione
		TExternal_app ve2_2(appname); // istanzia l'applicazione esterna...
		ve2_2.run(); // ...la lancia e rimane in attesa del suo termine
	}
	return TRUE;
}

bool TCondizioni_vendita::handle_datacam(TMask_field &fld, KEY k) {
	if (k==K_TAB) { // ad ogni perdita di fuoco viene tentato un accoppiamento tra valuta e data per ottenere il cambio preciso
		TString datacam(fld.get()); // legge la data di cambio nel campo corrente
		if (datacam.not_empty()) {
			TMask &m= fld.mask(); // prende la maschera principale
			TString codval(m.get(F_CODVAL)); // prende il codice della valuta
			if (codval.not_empty()) {
				TTable cam("CAM"); // apre la tabella cambi
				cam.put("CODTAB", codval << datacam); // riempie la chiave
				if (cam.read() == NOERR) m.set(F_CAMBIO, cam.get("R10")); // se la lettura riesce il valore del cambio viene posto nel campo CAMBIO della maschera
			}
		}
	}
	return TRUE;
}

bool TCondizioni_vendita::handle_valfin(TMask_field &fld, KEY k) {
	if (k==K_TAB) {
		if (fld.get().not_empty()) {
			TMask &m= fld.mask(); // prende la maschera principale
			if (m.get(F_VALIN).not_empty()) {
				TDate valfin(fld.get()); // prende la data di fine validitā
				TDate valin(m.get(F_VALIN)); // prende la data di inizio validitā
				if (valfin<valin) {
					error_box("La data di inizio validitā deve essere minore della data di fine");
					return FALSE;
				}
			}
		}
	}
	return TRUE;
}

bool TCondizioni_vendita::handle_codsucc(TMask_field &fld, KEY k) {
	if (k==K_TAB) {
		TString &_condven= app()._condven; // prende il tipo di archivio dall'applicazione principale
		TString codsucc(fld.get()); // prende il codice successivo dal campo corrente
		if (codsucc.not_empty()) {
			TMask &m= fld.mask(); // prende la maschera principale
			TString cod; // istanzia la stringa per il codice corrente
			switch (_condven[0]) {
				case 'L': cod= m.get(F_L_COD); break; // prende il codice listino corrente dal campo della maschera
				case 'C': cod= m.get(F_C_COD); break; // prende il codice contratto dal campo della maschera
			}
			if (codsucc == cod) {
				error_box("Il codice successivo deve essere diverso dal codice corrente");
				return FALSE;
			}
   	}
	}
	return TRUE;
}

int TCondizioni_vendita::write(const TMask &m) {
  m.autosave(_rel); // scrive il contenuto della maschera nel record della relazione
	TLocalisamfile &f= _rel->lfile(); // prende il file principale della relazione
	if (_condven != "C") f.zero("TIPOCF"); // se non si sta lavorando sui contratti il campo TIPOCF deve essere svuotato sul file
  _rel->write(); // invoca la scrittura della relazione
  return (_rel->status()); // ritorna lo stato della relazione
}

int TCondizioni_vendita::rewrite(const TMask &m) {
  m.autosave(_rel); // scrive il contenuto della maschera nel record della relazione
	TLocalisamfile &f= _rel->lfile(); // prende il file principale della relazione
	if (_condven != "C") f.zero("TIPOCF"); // se non si sta lavorando sui contratti il campo TIPOCF deve essere svuotato sul file
  _rel->rewrite(); // invoca la riscrittura della relazione
  return (_rel->status()); // ritorna lo stato della relazione
}

bool TCondizioni_vendita::remove() {
	TLocalisamfile &condv= _rel->lfile(); // prende il file della testata dalla relazione principale
  TLocalisamfile rcondv(LF_RCONDV); // apre il file delle righe per ottenenre il record corrente
  TRectype delrec(rcondv.curr()); // istanzia il record basato sul file delle righe, da usare come campione
  delrec.zero(); // svuota il record campione
  delrec.put("TIPO", _condven); // setta il tipo di archivio
  delrec.put("COD", condv.get("COD")); // setta il codice della testata
  if ((_condven=="L") && _codlis_catven) delrec.put("CATVEN", condv.get("CATVEN")); // setta la categoria di vendita se č abilitata e siamo nei listini
  if (_condven=="C") {
  	delrec.put("TIPOCF", condv.get("TIPOCF")); // setta i dati del cliente/fornitore se siamo nei contratti
  	delrec.put("CODCF", condv.get("CODCF"));
	}
  TRelation delrel(LF_RCONDV); // istanzia una relazione sulle righe
  TCursor delcur(&delrel, "", 1, &delrec, &delrec); // istanzia il cursore di cancellazione sulla relazione delle righe
  long n= delcur.items(); // legge il numero di elementi del cursore
  delcur.freeze(); // congela il cursore al suo stato attuale
  bool proceed= FALSE; // istanzia il booleano di conferma alla cancellazione
  if (n==1) proceed= yesno_box("Esiste una riga collegata a questa testata: verrā anch'essa cancellata. Procedo?"); // viene richiesta conferma alla cancellazione della riga...
  if (n>1) proceed= yesno_box("Esistono %ld righe collegate a questa testata: verranno anch'esse cancellate. Procedo?", n); // ...o delle righe
  if (proceed) { // se si conferma le righe vengono cancellate
  	TLocalisamfile &delfile= delcur.file(); // prende riferimento al file delle righe dal cursore
  	for (delcur=0; delcur.pos()<n; ++delcur) delfile.remove(); // ciclo sugli elementi del cursore, cancella i record del file delle righe
  } else return FALSE;
	return (TRelation_application::remove()); // viene invocata la funzione standard di cancellazione del record corrente
}



int ve2200(int argc, char* argv[]) {
  TCondizioni_vendita a;
  
  a.run(argc, argv, "Condizioni di vendita ");
  return 0;
}
