#include <applicat.h>
#include <automask.h>
#include <defmask.h>
#include <recset.h>
#include <tabmod.h>

#include "../pr/agenti.h"

#include "ha3.h"
#include "ha3100a.h"

const char* const APPNAME = TR("Gestione giri");

                                          /////////////////////////
                                          ////    TGIRI_KEY    ////
                                          /////////////////////////
class TGiri_key : public TObject
{
  TString8 _agente;
  int      _giorno;
  long     _cliente;

public:
  TGiri_key& operator =(const TGiri_key& gkey) {return *this;}
  
  const TString8  agente()  const;
  const int       giorno()  const;
  const long      cliente() const;
  
  void set_agente  (const char* codag);
  void set_giorno  (const int   giorno);
  void set_cliente (const long  codcli);
  
  const char* key() const;

  TGiri_key(const char* codag, const int giorno, const long codcli);
  TGiri_key(const TString& key);
};

const TString8 TGiri_key::agente() const
{
  return _agente;
}

const int TGiri_key::giorno() const
{
  return _giorno;
}

const long TGiri_key::cliente() const
{
  return _cliente;
}

void TGiri_key::set_agente(const char* codag)
{  
  _agente = codag;
}

void TGiri_key::set_giorno(const int giorno)
{
  _giorno = giorno;
}

void TGiri_key::set_cliente(const long codcli)
{
  _cliente = codcli;
}


const char* TGiri_key::key() const
{
  TString& str = get_tmp_string();
  str = _agente;
  
  TString8 tmp;
  tmp.format("%01d", _giorno);
  str << tmp;

  tmp.cut(0);
  tmp.format("%06d", _cliente);
  str << tmp;
  
  return str;
}

TGiri_key::TGiri_key(const char* codag, const int giorno, const long codcli/*, const int coditi*/)
{
  set_agente(codag);
  set_giorno(giorno);
  set_cliente(codcli);
}

TGiri_key::TGiri_key(const TString& key)
{
  set_agente(key.left(5));
  set_giorno(atoi(key.mid(5,1)));
  set_cliente(atol(key.mid(6,6)));
}

                                          ///////////////////////////////////////
                                          ////    FUNZIONE DI ORDINAMENTO    ////
                                          ///////////////////////////////////////

static int sort_by_stop(TSheet_field& sheet, int r1, int r2)
{
  TToken_string& row1 = sheet.row(r1);
  TToken_string& row2 = sheet.row(r2);

  const int i1 = row1.get_int(sheet.cid2index(S_AGENTE));
  const int i2 = row2.get_int(sheet.cid2index(S_AGENTE));

  int dif = i1 - i2;
  if (dif == 0)
  {
    dif = row1.get_int(sheet.cid2index(S_GIORNO)) - row2.get_int(sheet.cid2index(S_GIORNO));

    if (dif == 0)
      dif = row1.get_int(sheet.cid2index(S_ORDPASS)) - row2.get_int(sheet.cid2index(S_ORDPASS));    
  }

  return dif;
}

                                          //////////////////////////////////
                                          ////    TGESTIONE_GIRI_MSK    ////
                                          //////////////////////////////////

class TGestione_giri_msk : public TAutomask
{
protected:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);

  void riempi_sheet();
  void aggiungi_riga();
  void registra();

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

//RIEMPI_SHEET: riempie lo sheet tenendo conto dei filtri impostati
void TGestione_giri_msk::riempi_sheet()
{
  TSheet_field& sheet = sfield(F_SHEET);
  sheet.destroy();
  
  //leggi dalla maschera i filtri
  TString8 agente; agente.format("%05d", get_long(F_AGENTE));
  const long giorno   = get_int(F_GIORNO);
  const long cliente = get_long(F_CLIENTE);

  //prepara la query;
  //ATTENZIONE: le query su tabmod non funzionano con il semplice USE &TAB, ma vogliono SEMPRE FROM e TO
  TString query;
  query << "USE &HGI\n"
        << "SELECT (BETWEEN(CODTAB[6,6];" << giorno << ';' << giorno << "))&&(BETWEEN(CODTAB[7,12];" << cliente << ';' << cliente << "))";

  if(!field(F_AGENTE).empty())
  {
    query << "\nFROM CODTAB=\"" << agente << "\""
          << "\nTO CODTAB=\""   << agente  << "\"";    
  }
  else
  {
    TISAM_recordset agenti(TR("USE AGENTI"));

    agenti.move_first();
    query << "\nFROM CODTAB=\"" << agenti.get(AGE_CODAGE).as_string() << "\"";

    agenti.move_last();
    query << "\nTO CODTAB=\""   << agenti.get(AGE_CODAGE).as_string()  << "\"";
  }

  TISAM_recordset giri(query);
  
  //se non ho trovato niente con i filtri impostati, lo segnalo
  if(giri.items() == 0)
  {
    warning_box(TR("Non � stato possibile trovare giri con i filtri selezionati."));
    return;
  }

  //riempio lo sheet con i dati trovati sulla tabella di modulo
  for(bool ok = giri.move_first(); ok; ok = giri.move_next())
  {   
    TToken_string& riga = sheet.row(-1);

    TGiri_key gkey(giri.get("CODTAB").as_string());

    riga.add(gkey.agente(),              sheet.cid2index(S_AGENTE));
    riga.add(gkey.giorno(),              sheet.cid2index(S_GIORNO));
    riga.add(gkey.cliente(),             sheet.cid2index(S_CLIENTE));
    riga.add(giri.get("I0").as_int(),    sheet.cid2index(S_ORDPASS));
    riga.add(giri.get("S0").as_string(), sheet.cid2index(S_ORAPASS));
  }

  //faccio fare gli output ai campi della riga e disabilito le celle dei campi chiave
  FOR_EACH_SHEET_ROW(sheet, r, row)
  {
    sheet.check_row(r);  
    sheet.disable_cell(r, sheet.cid2index(S_AGENTE));
    sheet.disable_cell(r, sheet.cid2index(S_RAGSOC));
    sheet.disable_cell(r, sheet.cid2index(S_GIORNO));
    sheet.disable_cell(r, sheet.cid2index(S_CLIENTE));
    sheet.disable_cell(r, sheet.cid2index(S_CLIRAGSOC));
  }
  sheet.sort(sort_by_stop);
  sheet.force_update();
}

//AGGIUNGI_RIGA: aggiunge una riga allo sheet tetendo conto dei filtri impostati in testata
//(compila i campi gi� compilati e li disabilita)
void TGestione_giri_msk::aggiungi_riga()
{
  const long agente  = get_long(F_AGENTE);
  const long giorno  = get_int(F_GIORNO);
  const long cliente = get_long(F_CLIENTE);
  TString8 codage; codage.format("%05d", agente);

  TSheet_field& sheet = sfield(F_SHEET);

  const short pos_codage = sheet.cid2index(S_AGENTE);
  const short pos_giorno = sheet.cid2index(S_GIORNO);
  const short pos_codcli = sheet.cid2index(S_CLIENTE);
  
  TToken_string& riga = sheet.row(-1);
  const int r = sheet.items() - 1;

  if(agente > 0L)
    riga.add(codage, pos_codage);

  if(giorno > 0L)
    riga.add(giorno, pos_giorno);
  else
    riga.add(1L, pos_giorno);

  if(agente > 0L)
    riga.add(cliente, pos_codcli);
  
  riga.add("00:00", sheet.cid2index(S_ORAPASS));

  sheet.force_update();
  sheet.check_row(sheet.items() - 1);

  if(agente > 0L)
  {
    sheet.disable_cell(r, pos_codage);
    sheet.disable_cell(r, sheet.cid2index(S_RAGSOC));
  }

  if(giorno > 0L)
    sheet.disable_cell(r, pos_giorno);

  if(cliente > 0L)
  {
    sheet.disable_cell(r, pos_codcli);
    sheet.disable_cell(r, sheet.cid2index(S_CLIRAGSOC));
  }
  sheet.sort(sort_by_stop);
  sheet.force_update();
}

//REGISTRA: registra le variazioni ai record esistenti, aggiunge quelli nuovi e cancella quelli contrasegnati
void TGestione_giri_msk::registra()
{
  TModule_table giri("&HGI");
  TSheet_field& sheet = sfield(F_SHEET);

  TAssoc_array chiavi;

  FOR_EACH_SHEET_ROW(sheet, r, riga)
  {
    giri.zero();
    TToken_string& row = *(TToken_string*)riga;

    const bool      cancella = row.get_char(sheet.cid2index(S_CANC)) == 'X' ? true : false;
    const TString8  agente   = row.get(sheet.cid2index(S_AGENTE));
    const int       giorno   = row.get_int(sheet.cid2index(S_GIORNO));
    const long      cliente  = row.get_long(sheet.cid2index(S_CLIENTE));
		const long      ordpass  = row.get_long(sheet.cid2index(S_ORDPASS));
		const TString8  orapass  = row.get(sheet.cid2index(S_ORAPASS));

    const TGiri_key gkey(agente, giorno, cliente);
    const TString80 codtab = gkey.key();

    //se esiste un'altra riga sullo sheet con la stessa chiave, lo segnala e chiede se sovrascrivere quella gi� registrata
    if(chiavi.is_key(codtab))
    {
      TString msg;
      msg << "Attenzione: il passaggio dell'agente " << agente << " presso il cliente " << cliente << " previsto per il giorno " << itow(giorno)
          << " risulta duplicato. Si desidera sovrascrivere?";
      if(!yesno_box(msg))
        continue;
    }

    chiavi.add(codtab, codtab);

    //cancella le righe contrassegnate e aggiorna le altre
    giri.put("CODTAB", codtab);
		if (!cancella)
		{
			giri.put("I0", ordpass);
			giri.put("S0", orapass);      
			giri.rewrite_write();
		}
		else
			giri.remove();
  }
  riempi_sheet();
}

//ON_FIELD_EVENT: gestisce i comportamenti modificati dei bottoni e dello sheet
bool TGestione_giri_msk::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
	switch (o.dlg())
	{
  case DLG_FINDREC:
    if(e == fe_button)
    {
      riempi_sheet();
      return false;
    }
    break;
  case DLG_SAVEREC:
    if(e == fe_button)
    {
      registra();
      return false;
    }
    break;
  case F_SHEET:
    if(e == se_notify_add)
      aggiungi_riga();
    break;
  default: break;
  }
  return true;
}

TGestione_giri_msk::TGestione_giri_msk() 
                   : TAutomask ("ha3100a")
{}

///////////////////////////////////////
// TSkeleton_application
///////////////////////////////////////
class TGestione_giri_app : public TSkeleton_application
{
protected:
  virtual const char * extra_modules() const {return "ba";}
  void elabora(const TMask& msk);

public:
  virtual void main_loop();
  virtual bool create();
};



void TGestione_giri_app::elabora(const TMask& msk)
{}

void TGestione_giri_app::main_loop()
{
  TGestione_giri_msk msk;
  while (msk.run() == K_ENTER)
    elabora(msk);
}

bool TGestione_giri_app::create()
{
	return TSkeleton_application::create();
}

int ha3100 (int argc, char* argv[])
{
  TGestione_giri_app elabapp;
	elabapp.run(argc, argv, APPNAME);
  return 0;
}