// gestione tabelle di magazzino

#include "mglib.h"
#include "../ve/vetbmag.h"

#include <modaut.h>
#include <tabapp.h>
#include <tabutil.h>

#include "mgtbcau.h"
#include "mgtbfca.h"
#include "mgtbgsa.h"


// applicazione per la gestione delle tabelle di magazzino
class Tab_app_mag : public TTable_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 void init_query_mode(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(); }


#define MAXMETACH 20
// maschere delle tabelle di magazzino
class TMask_tabmag : public TMask
{
  TCodice_livelli * cod_liv;
  TFile_cache *tab_cache;
  TMetachar * metach;

  static bool stdmag_handler(TMask_field &, KEY); // handler 
  static bool singlemag_handler(TMask_field &, KEY); // handler 
  static bool sumsign_handler(TMask_field &, KEY); // handler 
  static bool format_handler(TMask_field &, KEY); // handler dei metacaratteri
  static bool formatgiac_handler(TMask_field &, KEY); // handler dei metacaratteri
  static bool codlivart_handler(TMask_field &, KEY); // handler del numero formato articoli
  static bool codlivgiac_handler(TMask_field &, KEY); // handler del numero formato giacenze
  static bool codgrp_handler(TMask_field &, KEY); // handler del numero formato
  static bool adv_codgrp_handler(TMask_field& f, KEY k); // handler codice gruppo avanzato

public:
  // @cmember Disabilita la verifica del modulo in chiave
  virtual bool check_autorization() const 
  {return FALSE;}
  TMask_tabmag(const char*, const TString&);
  virtual ~TMask_tabmag();
};

// costruttore della maschera 
TMask_tabmag::TMask_tabmag(const char * _maskname, const TString &tabname)
            : TMask(_maskname)
{
  cod_liv = NULL;

  if (tabname == "MAG")  // Magazzini
  {
    TMagazzini magazzini;
    if (!magazzini.gestmultimag())
    {
      set_handler(F_CODICE, singlemag_handler);
      set_handler(F_MAGSTD, stdmag_handler);
      //disable(F_MAGSTD);
    }
    if (!magazzini.gestdep())
    {
      field(F_GESTGIA).reset();
      field(F_GESTGIA).disable();
    }
  } else 
  if (tabname == "%CAU") 
  {
    if (!main_app().has_module(DBAUT))
      hide(F_DIBAEXPLOSION);
    set_handler(F_SGNGIAC, sumsign_handler);
    if (!main_app().has_module(LVAUT))
      hide(-LVAUT);
  } else 
  if (tabname == "FCA")  // FORMATO CODICE ARTICOLI
  {
    cod_liv=new TCodart_livelli;
    metach= new TMetachar("");
    set_handler(F_FORMLIV, format_handler);
    set_handler(F_CODLIV, codlivart_handler);
  } else 
  if (tabname == "GCA") // GRUPPI CODICE ARTICOLI
  {
    cod_liv=new TCodart_livelli;
    set_handler(F_CODGROUP, codgrp_handler);
  } else 
  if (tabname == "FCG")  // FORMATO CODICE GIACENZE
  {
    cod_liv = new TCodgiac_livelli;
    metach = new TMetachar("") ;
    set_handler(F_FORMLIV, formatgiac_handler);
    set_handler(F_CODLIV, codlivgiac_handler);
  } else 
  if (tabname == "GCG")      // GRUPPI CODICE GIACENZE
  {
    cod_liv = new TCodgiac_livelli;
    set_handler(F_CODGROUP, codgrp_handler);
  } else
  if (tabname == "GSA")      // GRUPPI CODICE AVANZATI
  {
    set_handler(F_CODGROUP, adv_codgrp_handler);
  }
}

TMask_tabmag::~TMask_tabmag()
{
  if (cod_liv!=NULL)
    delete cod_liv;
}

// tabella magazzini: controllo codice 
bool TMask_tabmag::singlemag_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.get().not_empty())
  {
    TTable mag("MAG");
    mag.first();
    if (!mag.eof() && mag.get("CODTAB")!=f.get())
    {
      f.error_box(TR("E' abilitata la gestione di un solo magazzino"));
      f.set(mag.get("CODTAB"));
    }
  }
  return TRUE;  
}

// tabella magazzini: controllo mag std 
bool TMask_tabmag::stdmag_handler(TMask_field& f, KEY k)
{        
  if (k == K_ENTER)
    f.set("X");
  return TRUE;  
}

// tabella causali: handler della somma segni
bool TMask_tabmag::sumsign_handler(TMask_field& f, KEY k)
{        
  bool ok = true;
  if (k == K_ENTER)
  {                  
    int ss=f.mask().get_int(F_SGNGIAC)-f.mask().get_int(F_SGNRIM);
    ss-=f.mask().get_int(F_SGNACQ)+f.mask().get_int(F_SGNENTR);
    ss+=f.mask().get_int(F_SGNVEN)+f.mask().get_int(F_SGNUSC);
    ss+=f.mask().get_int(F_SGNACL)-f.mask().get_int(F_SGNINCL);
    ss+=f.mask().get_int(F_SGNPRODF)-f.mask().get_int(F_SGNPRODC);
    ss+=f.mask().get_int(F_SGNSCAR);
    f.mask().set(F_SUMSIGN,long(ss));
    if (ss!=0)
    {
      f.error_box(TR("La somma dei segni \n((GIAC-RIM)-(ACQ+ENTR)+(VEN+USC)+(ACL-INCL)+(PRODF-PRODC) + SCARTI) \ndeve essere uguale a zero"));
      return FALSE;  
    }
#define ABSSALDO(fld) abs(f.mask().get_int(fld))
    if (f.mask().edit_mode() || f.mask().insert_mode())
    {
      int ps=ABSSALDO(F_SGNGIAC)+ABSSALDO(F_SGNRIM);
      ps+=ABSSALDO(F_SGNACQ)+ABSSALDO(F_SGNENTR);
      ps+=ABSSALDO(F_SGNVEN)+ABSSALDO(F_SGNUSC);
      ps+=ABSSALDO(F_SGNACL)+ABSSALDO(F_SGNINCL);
      ps+=ABSSALDO(F_SGNPRODF)+ABSSALDO(F_SGNPRODC);
      ps+=ABSSALDO(F_SGNORDC)+ABSSALDO(F_SGNORDF);
      ps+=ABSSALDO(F_SGNLABEL)+ABSSALDO(F_SGNSCAR);
      if (ps==0)
        ok = f.yesno_box(TR("Attenzione: la causale non movimenta nessun saldo. Confermare?"));
      const char tipomov=*f.mask().get(F_TIPOMOV);
      if ((f.mask().get_int(F_SGNGIAC) >=0 && tipomov=='S') )
        ok = f.yesno_box(TR("Attenzione: la causale e' impostata come scarico ma la giacenza non e' movimentata in negativo. Confermare?"));
      if ((f.mask().get_int(F_SGNGIAC) <=0 && tipomov=='C'))
        ok = f.yesno_box(TR("Attenzione: la causale e' impostata come carico ma la giacenza non e' movimentata in positivo. Confermare?"));
    }
  }
  return ok;  
}

// 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 & mask=((TMask_tabmag &)f.mask());
    TTable aux_tabf(app().get_tabname());

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

    aux_tabf.put("CODTAB",mask.get_int(F_CODLIV)+1);
    if (aux_tabf.read()==NOERR)
    {
      // non � l'ultimo livello: solo caratteri obbligatori
      if (mask.metach->has_opzchars(s))
      {
        f.error_box(FR("I caratteri di formato opzionali ('%s') sono consentiti solo per l'ultimo livello"),
          mask.metach->opz_chars());
        return FALSE;  
      }
    } 
  }
  return TRUE;  
}

// HANDLER DEL FORMATO DEL LIVELLO
bool TMask_tabmag::formatgiac_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    const int maxlen=15;
    int total_len=0;
    TString s(f.get());
    TMask_tabmag & mask=((TMask_tabmag &)f.mask());
    TTable aux_tabf(app().get_tabname());

    s.strip_spaces();
    f.set(s);
    mask.set(F_LENFORM,mask.metach->maxstrlen(s));

    aux_tabf.put("CODTAB",1);
    if (aux_tabf.read()==NOERR)
    {
      do {
        if (aux_tabf.get_int("CODTAB") != mask.get_int(F_CODLIV))
          total_len+=aux_tabf.get_int("I0");
      } while (aux_tabf.next()==NOERR);
    }
    total_len+=mask.get_int(F_LENFORM);
    if (total_len > maxlen)
    {
      f.error_box(FR("La somma delle lunghezze dei codici \n dei livelli di giacenza eccede \nil massimo consentito di %d caratteri"),maxlen);
      return false;
    }
  }
  return true;
}


// HANDLER DEL CODICE LIVELLO
bool TMask_tabmag::codlivart_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    const int codliv=atoi(f.get());
     if (codliv>1)
    // Non � il primo codice
    {
      TMask_tabmag & mask=((TMask_tabmag &)f.mask());
      TTable aux_tabf(app().get_tabname());
      aux_tabf.put("CODTAB",codliv-1);
      if (aux_tabf.read()==NOERR)
      // esiste un precedente
      {
        TString prevformat(aux_tabf.get("S1"));
        aux_tabf.put("CODTAB",codliv+1);
        if (aux_tabf.read()!=NOERR && mask.metach->has_opzchars(prevformat))
          return f.error_box(TR("Il livello precedente include caratteri opzionali nel formato\ne non puo' divenire un livello intermedio"));
      } 
      else 
        return f.error_box(TR("Non si possono inserire salti nel livello del codice"));
    }
  }
  return TRUE;  
}

// HANDLER DEL CODICE GRUPPO AVANZATO
bool TMask_tabmag::adv_codgrp_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    TMask& m = f.mask();
    if (m.query_mode())
    {
      const int desc_pos = m.id2pos(f.dlg()) + 1;
      TMask_field& desc = m.fld(desc_pos);
      if (desc.empty())   // Copia il codice nella descrizione se necessario
        desc.set(f.get());
    }
  }
	else
		if (k == K_F8)
		{
	    TMask& m = f.mask();
		
			if (m.query_mode())
			{
				TString newcod(m.get(F_CODLIV));
				const int prlen = newcod.len();
				const bool autonumalfa = cache().get("FSA", newcod).get_bool("B1");
				
				newcod << ((TEditable_field&)f).get_window_data();

				TString cod(newcod);
				const int len = cod.len();
				TTable gsa("GSA");

				cod << (autonumalfa ? "ZZZZZZ" : "999999");
				gsa.put("CODTAB", cod);
				if (gsa.read(_isgteq) != _isemptyfile)
				{
					TString code = gsa.get("CODTAB");
		    
					if (cod < code.left(len) || (newcod == code.left(len) && !isdigit(code[len])))
					{
						gsa.prev();
						code = gsa.get("CODTAB");
					}  
					if (newcod == code.left(len))
					{
						if (autonumalfa)
						{

							newcod = code;
							newcod.ltrim(prlen);

							int add = 1;
							int lastpos = newcod.len() - 1;

							while (lastpos >= 0)
							{
								newcod[lastpos] += add;
								if (newcod[lastpos] > '9' && newcod[lastpos] < 'A')
								{
									newcod[lastpos] = 'A';
									break;
								}
								else
									if (newcod[lastpos] > 'Z')
										newcod[lastpos--] = '0';
									else
										break;
							}
						}
						else
						{
							const int progr = atol(code.mid(len)) + 1;
							TString fmt;

							fmt.format("%%s%%0%dld", code.len() - len);
							newcod.ltrim(prlen);
							newcod.format(fmt, (const char *)newcod, progr);
						}
						f.set(newcod);
						m.stop_run(K_INS);
					}
				}
			}
		}
	return true;
}

// HANDLER DEL CODICE LIVELLO
bool TMask_tabmag::codlivgiac_handler(TMask_field& f, KEY k)
{        
  if (k == K_TAB && f.focusdirty())
  {                  
    const int codliv = atoi(f.get());
    if (codliv>1) // Non � il primo codice
    {
      TTable aux_tabf(app().get_tabname());
      aux_tabf.put("CODTAB",codliv-1);
      if (aux_tabf.read()!=NOERR) // non esiste un precedente
        return f.error_box(TR("Non si possono inserire salti nel livello del codice"));
    }
  }
  return TRUE;  
}

// HANDLER DEL CODICE LIVELLO giacenza
// HANDLER DEL CODICE LIVELLO anagrafica
bool TMask_tabmag::codgrp_handler(TMask_field& f, KEY k)
{        
  if ((k == K_TAB && f.focusdirty() )||k == K_ENTER )
  {                  
    TMask_tabmag & mask=((TMask_tabmag &)f.mask());
    if (!mask.cod_liv->enabled())
      return f.error_box(TR("Livelli del codice non abilitati"));

    if (!f.empty() && !(mask.cod_liv->fit_to_format(f.get(),mask.get_int(F_CODLIV))))
      return f.error_box(TR("Codice non corrispondente al formato previsto"));
  }
  return TRUE;  
}

// costruttore
Tab_app_mag::Tab_app_mag() {}


bool Tab_app_mag::protected_record(TRectype& rec) 
{ 
  bool prot = rec.get_bool(FPC);
  if (!prot)
  {
    const TString4 tn = get_tabname();
    if (tn=="FCA" || tn=="FCG" )
    {
      // non si possono cancellare i livelli intermedi:se non � l'ultimo livello, proteggilo
      TTable aux_tabf(tn);
      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 
  {
    const TString& tabname = get_tabname();
    TString maskname; get_mask_name(maskname);
    return Tab_application::set_mask(new TMask_tabmag(maskname, 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);
}

void Tab_app_mag::init_query_mode(TMask& m) 
{
	TTable_application::init_query_mode(m);

	if (get_tabname() == "GSA" && argc() > 3)
		m.set(F_CODLIV, argv(3));
}

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