#include "../ve/velib.h"
#include "../ve/sconti.h"
#include "../mg/mglib.h"

#include "../ve/vepriv.h"
#include "../ve/veuml.h"

#include <automask.h>
#include <defmask.h>
#include <execp.h>
#include <agasys.h>
#include <tabutil.h>
#include <utility.h>

#include "../mg/anamag.h"
#include "../ve/ve0100.h"
#include "../ve/veini.h"
#include "../ve/veuml.h"
#include "../ve/veuml1.h"
#include "../ve/verig.h"

#include <clifo.h>
#include "pc0001.h"

class TCommesse_mask : public TDocumento_mask
{
	TBit_array	_modified_rows;
	TBit_array	_deleted_rows;
	int _last_row;

protected:
	static bool cc_notify(TSheet_field& ss, int r, KEY key);


public:
	TBit_array & modified_rows() { return  _modified_rows;}
	TBit_array & deleted_rows() {return _deleted_rows;}
	void reset_last_row() { _last_row = -1;}
	void set_last_row(int r) { _last_row = r;}
	int last_row() const { return _last_row;}
	bool modified(long idriga) const{ return _modified_rows[(int)idriga];}
	bool deleted(long idriga) const {return _deleted_rows[(int)idriga];}
  TCommesse_mask(const char* tipodoc);
  virtual ~TCommesse_mask() {}
};

bool TCommesse_mask::cc_notify( TSheet_field& ss, int r, KEY key )
{
  TCommesse_mask& m = (TCommesse_mask&)ss.mask();
  TDocumento& doc = m.doc();

  if ( key == K_ENTER )
  {
    TRiga_documento& riga = doc[r + 1];
		const long idriga = riga.get_long(RDOC_IDRIGA);

		m.modified_rows().set(idriga);
  }
	else
		if ( key == K_TAB && m.is_running() && m.last_row() != r)
		{
			m.set_last_row(r);
			TRiga_documento& riga = doc[r + 1];
			const long idriga = riga.get_long(RDOC_IDRIGA);

			if (!m.modified(idriga))
			{
				TToken_string key;
				key.add(riga.get(RDOC_CODNUM));
				key.add(riga.get(RDOC_ANNO));
				key.add(riga.get(RDOC_PROVV));
				key.add(riga.get(RDOC_NDOC));
				for (int i = 1; ; i++)
				{
					key.add(i, 4);

					const TRectype& rec = cache().get(LF_RIGHEDOC, key);

					if (rec.empty()) break;
					if (rec.get_long(RDOC_IDRIGA) == idriga)
					{
						TDocumento::copy_data(riga, rec);
						riga.autoload(ss);
						ss.check_row(r, 0x2);
						ss.force_update(r);
						break;
					}
				}
			}
		}
		else
			if ( key == K_DEL ) // Cancellazione
			{
				TRiga_documento& riga = doc[r + 1];
				const long idriga = riga.get_long(RDOC_IDRIGA);

				m.deleted_rows().set(idriga);
				m.modified_rows().set(idriga, false);
			}
			else
				if (key == K_CTRL + K_INS)
				{
					doc.set_row_ids();
					TRiga_documento & riga = doc[r + 1];
					const long idriga = riga.get_long(RDOC_IDRIGA);

					m.modified_rows().set(idriga);
				}
	return TDocumento_mask::ss_notify(ss, r,key);
}

TCommesse_mask::TCommesse_mask(const char* tipodoc):
										TDocumento_mask(tipodoc), _last_row(-1)
{
  sfield(F_SHEET).set_notify( cc_notify );
}

// Definizione della classe dell'applicazione motore
class TCommesse_application : public TMotore_application
{
	TAssoc_array _masks; // assoc_array delle maschere da utilizzare
	TString4 _tipodoc; 
	TBit_array	_modified;

protected:
  virtual TMask* get_mask( int mode );
  virtual int read( TMask& m );
  virtual int rewrite( const TMask& m );

public:
  virtual TMask & query_mask();
  virtual TDocumento_mask & edit_mask() const;

	TCommesse_application() {}
};

inline TCommesse_application& pcapp() { return (TCommesse_application &) main_app(); };

TMask& TCommesse_application::query_mask()
{
	TMask* m = (TMask*) _masks.objptr("pc0001100a");
	if (m == NULL)
	{
		m = new TMask("pc0001100a");
		_masks.add("pc0001100a", m);
	}
	return *m;
}

TDocumento_mask& TCommesse_application::edit_mask() const
{
	TDocumento_mask* m = (TDocumento_mask*) _masks.objptr(_tipodoc);
	if (m == NULL)
	{
		m = new TCommesse_mask(_tipodoc);
		((TAssoc_array&)_masks).add(_tipodoc, m);
	}
	return *m;
}

TMask* TCommesse_application::get_mask( int mode )
{
	TMask* m = NULL;
	if (mode == MODE_MOD || mode == MODE_INS)
	{
		_tipodoc = query_mask().get(F_TIPODOC);
		m = &edit_mask();
	}
	else
		m = &query_mask();
	return m;
}

// maschera di ricerca
// maschera di edit
int TCommesse_application::read(TMask& m )  
{          
	TCommesse_mask & mask = (TCommesse_mask &) m;
	mask.modified_rows().reset();
	mask.deleted_rows().reset();
	mask.reset_last_row();

	const int err = TMotore_application::read(m);
	if (err == NOERR)
		((TDocumento_mask &) m).doc().read(_isequal, _unlock);
	return err;
}

int TCommesse_application::rewrite( const TMask& m )  
{          
	int err = NOERR;
	const TCommesse_mask & mask = (const TCommesse_mask &) m;
	const TDocumento & maskdoc = mask.doc();
	TDocumento outdoc = maskdoc;
	while ((err = outdoc.read(_isequal, _testandlock)) == _islocked)
		xvt_sys_sleep (500);
	if (err == NOERR)
	{
	  for (int p = mask.fields()-1; p >= 0; p--)
		{
			TMask_field& f = mask.fld(p);
			const TFieldref* fr = f.field();
			if (fr != NULL)
				fr->write(f.get(), outdoc);
	  }

		int outrows = outdoc.physical_rows();
		
		for (int j = outrows; j > 1; j--)
		{
			TRiga_documento & outrow = outdoc[j];
			const long idriga = outrow.get_long(RDOC_IDRIGA);

			if (mask.deleted(idriga))
				outdoc.destroy_row(j, true);
		}
		outrows = outdoc.physical_rows();
		const int rows = maskdoc.physical_rows();
		for (int i = 1; i <= rows; i++)
		{
			const TRiga_documento & row = maskdoc[i];
			const long idriga = row.get_long(RDOC_IDRIGA);

			if (mask.modified(idriga))
			{
				bool newrow = true;

				for (int j = 1; newrow && j <= outrows; j++)
				{
					TRiga_documento & outrow = outdoc[j];
					
					if (idriga == outrow.get_int(RDOC_IDRIGA))
					{
						TDocumento::copy_data(outrow, row);
						newrow = false;
					}
				}
				if (newrow)
				{
					outdoc.insert_row(i);
					
					TRiga_documento & outrow = outdoc[i];
					
					TDocumento::copy_data(outrow, row);
				}
			}
		}
		err = outdoc.rewrite();
	}
	return err;
}
										
int pc0001100( int argc, char* argv[])
{
  TCommesse_application a;

  a.run( argc, argv, TR("Commesse GAM"));
  return 0;
}