// gestione tabelle di magazzino
#include <execp.h>
#include <config.h>
#include <printer.h>
#include <tabapp.h>
#include <tabutil.h>
#include <recarray.h>
#include <utility.h>
#include "batbcau.h"
#include "batbfca.h"

#include "../cg/cglib03.h"
#include "mglib01.h"


#define MAXMETACH 20
// maschere delle tabelle di magazzino
class TMask_tabmag : public TMask
{
  TTable *aux_tabf;
  TFile_cache *tab_cache;
	TMetachar * metac[MAXMETACH];

	static bool sumsign_handler(TMask_field &, KEY); // handler 
	static bool format_handler(TMask_field &, KEY); // handler dei metacaratteri
	static bool codliv_handler(TMask_field &, KEY); // handler del numero formato
	static bool numform_handler(TMask_field &, KEY); // handler del numero formato
	static bool codlivgca_handler(TMask_field &, KEY); // handler del numero formato


public:
	TMask_tabmag(const char * ,const TString16 &);
	virtual ~TMask_tabmag();
};

// costruttore della maschera 
TMask_tabmag::TMask_tabmag(const char * _maskname,const TString16 &tabname):
	TMask(_maskname)
{
    aux_tabf=NULL; 
    for (int i=0;i<MAXMETACH;i++) 
			metac[i]=NULL;
  	if (tabname == "CAU") 
    {
      set_handler(F_SGNGIAC, sumsign_handler);
    }
    if (tabname == "FCA")  // FORMATO CODICE ARTICOLI
    {
			metac[0]=new TMetachar;
	    aux_tabf = new TTable("FCA");
			set_handler(F_FORMLIV, format_handler);
      set_handler(F_CODLIV, codliv_handler);
    }
    if (tabname == "GCA") // GRUPPI CODICE ARTICOLI
    {
		  tab_cache = new TDecoder("FCA","S1");
		  tab_cache->fill();
		  // crea i riconoscitori del formato
		  for (int i=1; ((TDecoder *)tab_cache)->decode(i)!="";i++) 
		  {
				metac[i-1]=new TMetachar(((TDecoder *)tab_cache)->decode(i));
			}
      set_handler(F_CODLIV, codlivgca_handler);
      set_handler(F_CODGROUP, numform_handler);
    }
    if (tabname == "FCG")  // FORMATO CODICE GIACENZE
    {
			metac[0]=new TMetachar;
	    aux_tabf = new TTable("FCG");
			set_handler(F_FORMLIV, format_handler);
      set_handler(F_CODLIV, codliv_handler);
    }
    if (tabname == "GCG")      // GRUPPI CODICE GIACENZE
    {
		  tab_cache = new TDecoder("FCG","S1");
		  tab_cache->fill();
		  for (int i=1; ((TDecoder *)tab_cache)->decode(i)!="";i++) 
		  {
				metac[i-1]=new TMetachar(((TDecoder *)tab_cache)->decode(i));
			}
      set_handler(F_CODGROUP, numform_handler);
    }
}

TMask_tabmag::~TMask_tabmag()
{
	if (aux_tabf!=NULL)
		delete aux_tabf;
  for (int i=0;i<MAXMETACH;i++)  {
		if (metac[i]!=NULL)
			delete metac[i];
	}		
}

// tabella causali: handler della somma segni
bool TMask_tabmag::sumsign_handler(TMask_field& f, KEY k)
{        
  if (k == K_ENTER)
  {                  
    if (f.mask().get_int(F_SUMSIGN)!=0)
    {
			f.error_box("La somma dei segni ((GIAC-RIM)-(ACQ+ENTR)+(VEN+USC)+(ACL-INCL)+(PRODF-PRODC)) deve essere uguale a zero");
			return FALSE;  
    }
  }
  return TRUE;  
}

// HANDLER DEL FORMATO DEL LIVELLO
bool TMask_tabmag::format_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    TString s(f.get());
    TMask_tabmag & mymask=((TMask_tabmag &)f.mask());
    TTable * aux_tabf=mymask.aux_tabf;

    s.strip_spaces();
    f.set(s);

    aux_tabf->zero();
    aux_tabf->put("CODTAB",mymask.get_int(F_CODLIV)+1);
    if (aux_tabf->read()==NOERR)
    {
    	// esiste il seguente:solo caratteri obbligatori
    	if (mymask.metac[0]->has_opzchars(s))
    	{
				f.error_box("I caratteri di formato opzionali ('%s') sono consentiti solo per l'ultimo livello",mymask.metac[0]->opz_chars());
				return FALSE;  
    	}
    } else {
    	// ultimo livello: almeno un carattere obbligatorio
    	if (!mymask.metac[0]->has_mandchars(s))
    	{
				f.error_box("Il codice dell'ultimo livello deve includere almeno un carattere obbligatorio (letterali o '%s') ",mymask.metac[0]->mand_chars());
				return FALSE;  
    	}
    }
  	// setta il campo con la lunghezza massima della stringa di formato
  	mymask.field(F_LENFORM).set(mymask.metac[0]->maxstrlen(f.get()));
  }
  return TRUE;  
}

// HANDLER DEL CODICE LIVELLO
bool TMask_tabmag::codliv_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    TMask_tabmag & mymask=((TMask_tabmag &)f.mask());
    TTable * aux_tabf=mymask.aux_tabf;
    int codliv=atoi((const char *)f.get());
    
		if (codliv>1)
    // Non è il primo codice
    {
	    aux_tabf->zero();
    	aux_tabf->put("CODTAB",codliv-1);
	    if (aux_tabf->read()==NOERR)
    	// esiste un precedente
	    {
		    TString prevformat(aux_tabf->get("S1"));
		    aux_tabf->zero();
    		aux_tabf->put("CODTAB",codliv+1);
	    	if (aux_tabf->read()!=NOERR && mymask.metac[0]->has_opzchars(prevformat))
	    	{
					f.error_box("Il livello precedente include caratteri opzionali nel formato");
			  	return FALSE;  
	    	}
			} else {
				f.error_box("Non si possono inserire salti nel livello del codice");
			  return FALSE;  
			}
    }
  }
  return TRUE;  
}


// gestisce l'introduzione del codice del livello articoli
bool TMask_tabmag::codlivgca_handler(TMask_field& f, KEY k)
{        
  if ((k == K_TAB && f.focusdirty())||k == K_ENTER )
  {                  
    TMask_tabmag & mymask=((TMask_tabmag &)f.mask());

   	if (((TDecoder *)mymask.tab_cache)->decode(atoi((const char *)f.get())+1)=="")
   	// non esiste un seguente
    {
			f.error_box("Non è possibile definire gruppi per l'ultimo livello di codice");
	  	return FALSE;  
		}
  }
  return TRUE;  
}


// HANDLER DEL CODICE LIVELLO giacenza
// HANDLER DEL CODICE LIVELLO anagrafica
bool TMask_tabmag::numform_handler(TMask_field& f, KEY k)
{        
  if ((k == K_TAB && f.focusdirty())||k == K_ENTER )
  {                  
    TMask_tabmag & mymask=((TMask_tabmag &)f.mask());

   	if (!(mymask.metac[mymask.get_int(F_CODLIV)-1])->recognized(f.get()))
    {
			f.error_box("Codice non corrispondente al formato previsto");
	  	return FALSE;  
		}
  }
  return TRUE;  
}




// applicazione per la gestione delle tabelle di magazzino
class Tab_app_mag : public Tab_application
{
  
protected:  // TRelation_application
  virtual bool user_destroy() ;          
  virtual bool user_create() ;
  virtual bool protected_record(TRectype& rec) ;
  virtual int rewrite(const TMask& m);
	
	virtual TMask * set_mask(TMask * _m=NULL);
	
public:
  Tab_app_mag();
  virtual ~Tab_app_mag() {}
};


HIDDEN inline Tab_app_mag& app() { return (Tab_app_mag&)main_app(); }
// costruttore
Tab_app_mag::Tab_app_mag() {}


bool Tab_app_mag::protected_record(TRectype& rec) 
{ 
  bool prot = rec.get_bool(FPC);

  if (!prot)
  {
  	if (get_tabname()=="FCA" ||get_tabname()=="FCG" )
  	{
 			// non si possono cancellare i livelli intermedi:se non è l'ultimo livello, proteggilo
  		TTable aux_tabf(get_tabname());
	 		aux_tabf.put("CODTAB",rec.get_int("CODTAB")+1);
	  	if (aux_tabf.read()==NOERR)
		  	prot=TRUE;  
		}
	}
  return prot;
}

// alloca/cambia la maschera dell'applicazione
TMask * Tab_app_mag::set_mask(TMask * _m)
{
	if (_m != NULL)
		return Tab_application::set_mask(_m);
	else
		return Tab_application::set_mask(new TMask_tabmag((const char *)mask_name(),get_tabname()));
}

bool Tab_app_mag::user_create()
{
  /*
  	la Tab_application::user_create() apre la maschera TMask in modo automatico
  	basandosi sul parametro passato sulla linea di comando e sulla convenzione
  	nome = "BATB"+parametro;
  	ORA:
  		- questa convenzione cambierà per separare i programmi (e le maschere)
  				dei vari pacchetti
  				In tal caso ridefinire il metodo virtual mask_name()
  		- secondo il nuovo stile, gli handler vanno posti in maschere derivate
  			dalla TMask (TMask_tabmag, TMask_tabcau, ecc), pertanto occorre che 
  			la maschera aperta sia del tipo corretto 
  			per questo motivo la maschera viene creata dalla user_create()
  */

  bool ok = Tab_application::user_create();
	
  if (ok) 
  {
    //TMask& mask = *set_mask();
  }
  
  return ok;
}

bool Tab_app_mag::user_destroy()
{
  return Tab_application::user_destroy();
}

int Tab_app_mag::rewrite(const TMask& m)
{
  return Tab_application::rewrite(m);
}


int mg0100(int argc, char* argv[])
{
 Tab_app_mag a;
  a.run(argc, argv, "Tabella");
  return 0;
}

