#include <relapp.h>
#include <utility.h>
#include <tabutil.h>
#include <msksheet.h>
#include <recarray.h>
#include <assoc.h>
#include <checks.h>
#include <defmask.h>
#include <varrec.h>
#include "..\mg\mglib01.h"
#include "mg1100.h"

//**************************************
// classe per il controllo dei record composti da una testata e N righe
// è implementato come un TRectype che contiene anche un TRecord_array
//
class THead_body_record : public TAuto_variable_rectype {

  TRecord_array _rows;  // Array di TRectype per le righe 
  bool _nuovo;
  int _file;		// file principale  (
  int _rowsfilenum;		// file delle righe

protected:
  long get_next_key(char provv, int anno, const char* codnum) const;
  virtual TRectype & row(int index);  // riga del corpo
  virtual void put_str(const char* fieldname, const char* val); 
  long renum(long numdoc = 0);  
	// @ cmember funzione per estrarre dal record della testata la chiave delle righe
  virtual void copy_linekey(const TRectype headrecord, TRectype linesrecord)=0; 

public:
	//***********************
	// struttura
  const TAuto_variable_rectype& head() const { return *this; } // Ritorna la testata del documento
  TAuto_variable_rectype& head() { return *this; } // Ritorna la testata del documento

  int rows() const { return _rows.rows(); } 
  
  const TRectype& operator[](int index) const 
  	{ return (const TRectype&)((THead_body_record *)this)->row(index); }
  TRectype& operator[](int index) 
  	{ return (TRectype&)row(index); } 
  
  TRectype & insert_row(int row, const char *tipo = NULL);
  TRectype & new_row(const char *tipo = NULL);
  bool destroy_row(int n, bool pack = FALSE) { return _rows.destroy_row(n, pack); }
  void destroy_rows() { _rows.destroy_rows(); }
  
	//***********************
  // record e I/O
  void dirty_fields();

  virtual TRectype & operator =(const TRectype & r); 
  virtual TRectype & operator =(const char * r); 
  virtual void zero(const char * fieldname);
  virtual void zero(char c = '\0');

  void reset_fields(TAuto_variable_rectype & rec) { rec.remove_field(); }
  void set_fields(TAuto_variable_rectype & rec);
    
  int read(const TRectype& rec);
  
  int write(bool re = FALSE) const;
  int rewrite() const { return write(TRUE); }
  int remove() const;

  //**************************
	THead_body_record(int hfn, int rfn,const char *numfield);
	THead_body_record(const TBaseisamfile* i,int rfn,const char *numfield);
	THead_body_record(const TRectype & r,int rfn,const char *numfield);
	THead_body_record(const TVariable_rectype & r,int rfn,const char *numfield);
	virtual ~THead_body_record();
};

THead_body_record::THead_body_record(int hfn, int rfn,const char *numfield):
	_rows(rfn,numfield), // inizializza il record array delle righe
	TAuto_variable_rectype(hfn)
{
  _file=hfn;		// file principale  
  _rowsfilenum=rfn;		// file delle righe
}

THead_body_record::THead_body_record(const TBaseisamfile* i,int rfn,const char *numfield):
	TAuto_variable_rectype(i)
{
}
THead_body_record::THead_body_record(const TRectype & r,int rfn,const char *numfield):
	TAuto_variable_rectype(r)
{
}
THead_body_record::THead_body_record(const THead_body_record& r):
	TAuto_variable_rectype(r)
{
	// copia..
}

int THead_body_record::read(const TRectype& rec)
{
  head() = rec;  
  TRectype line_key(_rows.key());

  copy_linekey(head(),line_key);
  
  TLocalisamfile afile(_file);        
  int err = TRectype::read(afile);
  if (err == NOERR)
  {
    _nuovo = FALSE;
    _rows.read(line_key); //ok
  }  
  else
  {
		// nuovo oggetto: resetta tutto
    _nuovo = TRUE;
    head() = rec;
    destroy_rows();
    _rows.set_key(&line_key);  // ok
  }
  return err;
}

int THead_body_record::write(bool re) const
{              
  const bool nuovo = _nuovo;  // E' nuovo di zecca!
  if (nuovo && re)                             // quindi ...
    re = FALSE;                                // ... non fare la rewrite

  TLocalisamfile afile(_file);
  int err = NOERR;
  if (re)
  {
    err = _rows.write(re); 
    if (err == NOERR)
    {
      err = TRectype::rewrite(afile);
      if (err != NOERR)
        err = TRectype::write(afile);
    }    
  }
  else
  {             
    if (nuovo)
    {         
      THead_body_record& myself = *(THead_body_record*)this;
      //if (numero() <= 0)
      //  myself.renum();
      do
      {
        err = TRectype::write(afile);
        if (err == _isreinsert)
          myself.renum();
      } while (err == _isreinsert);
      myself._nuovo = FALSE;
    }
    else 
    {
      err = TRectype::write(afile);
      if (err != NOERR)
        err = TRectype::rewrite(afile);
    }    
    if (err == NOERR)
      err = _rows.write(re); 
  }
  return err;  
}


int THead_body_record::remove() const
{
  TLocalisamfile afile(_file);
  int err = _rows.remove();
  if (err == NOERR)
    err = TRectype::remove(afile);
  return err;  
}








class TMov_mag : public THead_body_record {
	TString16 _nextcod;    
	
public:
	// IO ad alto livello
	const char *get_next_key()  ;
	int read(int numreg);
	int remove();
	// gestione saldi
	int save_line_minus();
	int save_line_plus();
	int update_balances();
	// costruttori e distruttori
	TMov_mag();
	virtual ~TMov_mag() {};
};

TMov_mag::TMov_mag() : 
	TRelation(LF_MOVMAG)
{ 	
}

TMov_mag::remove()
{
  /*
  // controlla le righe da togliere
  if ((res=((TSheet_field &)_msk->field(F_RIGHE)).record()->remove())==NOERR ) {
  	// effettua la variazione dei saldi
	*/
	return 0;
}

const char *TMov_mag::get_next_key()  
{
 	TLocalisamfile f(LF_MOVMAG);
	f.last();
	int a=atoi(f.get("NUMREG"))+1;
  return _nextcod.format("%d|%d",F_NUMREG,a);
}

//*******
// gestione delle variazione dei saldi
//
//
int TMov_mag::save_line_plus() 
{
	return 0;
}

int TMov_mag::save_line_minus() 
{
	return 0;
}

int TMov_mag::update_balances() 
{
	return 0;
}








//*****
//*****
// maschera dei movimenti di magazzino
class TMask_movmag: public TMask {
	TMov_mag * mov_mag;
	TMag_livelli * livelli_giac; // oggetto gestione livelli di giacenza
	static bool handle_sheetrighe(TMask_field &fld, KEY k); // handler delle righe
	static bool handle_codcaus(TMask_field &fld, KEY k); // handler delle righe
	static bool handle_numreg(TMask_field &, KEY); // handler del campo anno delle giacenze
public:
	TMask_movmag(TMag_livelli *l_m,TMov_mag * m_m);
	virtual ~TMask_movmag();
static void sheetrighe_put(TSheet_field &fld_righe, int item);
static void sheetrighe_get(TSheet_field &fld_righe, int item);
};


// costruttore della maschera anagrafica di magazzino
//TMask_movmag::TMask_movmag() : 
TMask_movmag::TMask_movmag(TMag_livelli *l_m,TMov_mag * m_m) : TMask("mg1100")
{
  
	// oggetti dell'applciazione
	livelli_giac= l_m;
	mov_mag = m_m;

  set_handler(F_NUMREG, handle_numreg);
  set_handler(F_CODCAUS, handle_codcaus);
  set_handler(F_RIGHE, handle_sheetrighe);
  ((TSheet_field &)field(F_RIGHE)).set_userget(sheetrighe_get);
  ((TSheet_field &)field(F_RIGHE)).set_userput(sheetrighe_put);
  
		// setta i campi della maschera
		// per la pagina giacenze
		TSheet_field &fld_righe= (TSheet_field &)field(F_RIGHE); 
  	// disabilita le colonne quando non sono utilizzati i livelli di giacenza
		if (livelli_giac->enabled(1)) {
			fld_righe.sheet_mask().field(F_LIV1).show();
			fld_righe.set_column_header(fld_righe.cid2index(F_LIV1),livelli_giac->name(1));
			fld_righe.sheet_mask().field(F_LIV1).set_prompt(livelli_giac->name(1));
		} else {
			fld_righe.sheet_mask().field(F_LIV1).hide();
			fld_righe.delete_column(fld_righe.cid2index(F_LIV1));
		}
		if (livelli_giac->enabled(2)) {
			fld_righe.sheet_mask().field(F_LIV2).show();
			fld_righe.set_column_header(fld_righe.cid2index(F_LIV2),livelli_giac->name(2));
			fld_righe.sheet_mask().field(F_LIV2).set_prompt(livelli_giac->name(2));
		} else {
			fld_righe.sheet_mask().field(F_LIV2).hide();
			fld_righe.delete_column(fld_righe.cid2index(F_LIV2));
		}
		if (livelli_giac->enabled(3)) {
			fld_righe.sheet_mask().field(F_LIV3).show();
			fld_righe.set_column_header(fld_righe.cid2index(F_LIV3),livelli_giac->name(3));
			fld_righe.sheet_mask().field(F_LIV3).set_prompt(livelli_giac->name(3));
		} else {
			fld_righe.sheet_mask().field(F_LIV3).hide();
			fld_righe.delete_column(fld_righe.cid2index(F_LIV3));
		}
		if (livelli_giac->enabled(4)) {
			fld_righe.sheet_mask().field(F_LIV4).show();
			fld_righe.set_column_header(fld_righe.cid2index(F_LIV4),livelli_giac->name(4));
			fld_righe.sheet_mask().field(F_LIV4).set_prompt(livelli_giac->name(4));
		} else {
			fld_righe.sheet_mask().field(F_LIV4).hide();
			fld_righe.delete_column(fld_righe.cid2index(F_LIV4));
		}
}


TMask_movmag::~TMask_movmag()
{
  delete livelli_giac;
}



// item varies from 1 to items()
void TMask_movmag::sheetrighe_get(TSheet_field &fld_righe, int item)
{
  TMask_movmag &m=(TMask_movmag &)fld_righe.mask();
  // prende il record della riga corrente dal record array
	TRectype &rec= fld_righe.record()->row(item, TRUE);
  TToken_string &row= fld_righe.row(item-1);
  // codici di livello
  row.add( m.livelli_giac->unpack_grpcode(rec.get("LIVGIAC") ,1),fld_righe.cid2index(F_LIV1) );
	row.add( m.livelli_giac->unpack_grpcode(rec.get("LIVGIAC") ,2),fld_righe.cid2index(F_LIV2) );
  row.add( m.livelli_giac->unpack_grpcode(rec.get("LIVGIAC") ,3),fld_righe.cid2index(F_LIV3) );
	row.add( m.livelli_giac->unpack_grpcode(rec.get("LIVGIAC") ,4),fld_righe.cid2index(F_LIV4) );
}

// item varies from 1 to items()
void TMask_movmag::sheetrighe_put(TSheet_field &fld_righe, int item)
{
  TMask_movmag &m=(TMask_movmag &)fld_righe.mask();
  TToken_string &row= fld_righe.row(item-1);
          
		TRectype &recrighe= fld_righe.record()->row(item, TRUE);
		// codici livello
		if (m.livelli_giac->enabled()) {
     	TString16 packedcode;
     	m.livelli_giac->pack_grpcode(packedcode,row.get(fld_righe.cid2index(F_LIV1)),1);
     	m.livelli_giac->pack_grpcode(packedcode,row.get(fld_righe.cid2index(F_LIV2)),2);
     	m.livelli_giac->pack_grpcode(packedcode,row.get(fld_righe.cid2index(F_LIV3)),3);
     	m.livelli_giac->pack_grpcode(packedcode,row.get(fld_righe.cid2index(F_LIV4)),4);
     	recrighe.put("LIVGIAC", packedcode);
		}			
}  
  


bool TMask_movmag::handle_sheetrighe(TMask_field &fld, KEY k)
{
  TSheet_field &f= (TSheet_field &)fld; // typecast del campo al suo sheet corrispondente
  TMask_movmag &m= (TMask_movmag &)fld.mask();
  int line;
  if (k==K_SPACE)
  {	
  	// entrata nella modifica
		m.mov_mag->save_line_minus(line);    
  }
  if (k==K_TAB && fld.focusdirty())
  {	
  	// uscita dalla modifica
		m.mov_mag->save_line_plus(line);    
  }
  if (k==K_ENTER)
  {
		m.mov_mag->update_balances();    
  }
  return TRUE;
}

bool TMask_movmag::handle_codcaus(TMask_field &fld, KEY k)
{
  if (k==K_TAB)
  {
	  TMask_movmag &m= (TMask_movmag &)fld.mask();
		m.mov_mag->save_line_minus();    
  }
  return TRUE;
}

bool TMask_movmag::handle_numreg(TMask_field &fld, KEY k)
{
  if (k==K_ENTER)
  {
  }
  return TRUE;
}

/*
// handle
bool TMask_movmag::handle_rmov_um(TMask_field &fld, KEY k)
{
  if (k==K_ENTER)
  {
  	TTable cau("CAU");
  }
  return TRUE;
} 
*/



class TApp_movmag: public TRelation_application {
	TMask_movmag *_msk; // maschera principale
  TMov_mag * _mov_mag; // relazione principale di un solo file (movimenti di magazzino)
  TMag_livelli * _livelli_giac;// oggetto handler  per i livelli di le giacenze
	int _lastnumreg;
  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 _mov_mag; }
  virtual void init_insert_mode(TMask &);
	virtual const char *get_next_key()  ;
  virtual int read(TMask& m);
  virtual bool remove();
  virtual int write(const TMask& m);             
  virtual int rewrite(const TMask& m);           

public:
  TApp_movmag() {};
  virtual ~TApp_movmag() {};
};


inline TApp_movmag& app() { return (TApp_movmag&) main_app(); }

bool TApp_movmag::user_create()
{
  // apre la maschera e dispone gli sheet
	_livelli_giac= new TMag_livelli("FCG");
  _mov_mag= new TMov_mag;
  _msk= new TMask_movmag(_livelli_giac,_mov_mag);
		  
  return TRUE;
}

bool TApp_movmag::user_destroy()
{
  delete _msk;
  delete _mov_mag;
  delete _livelli_giac;
  
  return TRUE;
}

// autonumerazione
const char *TApp_movmag::get_next_key()
{
  return _mov_mag->get_next_key();
}

// rimozione
bool TApp_movmag::remove()
{
  int res;
	_mov_mag->remove();
  return (res && TRelation_application::remove()); 
}

int TApp_movmag::read(TMask& m)
{
  int err=TRelation_application::read(m);
  return err;
}

int TApp_movmag::write(const TMask& m)
{
  int err= TRelation_application::write(m);
  
	return err;
}

int TApp_movmag::rewrite(const TMask& m)
{
  
  int err= TRelation_application::rewrite(m);
  
	return err;
}
  
void TApp_movmag::init_insert_mode(TMask &m)
{
}

int mg1100(int argc, char* argv[])
{
  TApp_movmag a;
  
  a.run(argc, argv, "Movimenti di magazzino");
  return 0;
}




