// Classe che contiene i data members comuni a tutti gli oggetti di creazione
// e la funzione di scansione.

#include <applicat.h>
#include <strings.h>
#include <mask.h>
#include <tabutil.h>
#include <lffiles.h>
#include <rectypes.h>
#include <config.h>
#include <checks.h>

#include "ve6retv.h"            // definizione dei valori di ritorno
#include "ve6.h"
#include "ve6000.h"                     // identificativi dei campi della maschera

class TElaborazioni : public TApplication
{
protected:
  // i data members sono protected in modo che gli oggetti generatori
  // possano accedervi senza la necessità di funzioni specifiche
  TString_array *_chiavi;       // array contenente i valori delle chiavi per ogni record selezionato da scan_doc
  TString _codelab;             // codice elaborazione differita
  TElab_struct _elab;           // struttura per memorizzare i campi significativi dei records di doc
  int _ordinamento;             // indica il tipo di ordinamento
  bool _raggruppa;                      // indica se si deve raggruppare o no

  int scan_doc (void);          // lancia le altre due procedure
  int run_mask (void);          // lancia la maschera e scandisce i records
  int get_info (void);          // imposta la struttura elab leggendo il record per l'elaborazione corrente
  bool errore_fatale(int);      // ritorna true se l'errore passato come argomento è nella lista degli errori fatali
};

bool TElaborazioni::errore_fatale (int err)
{
  switch (err)
  {
  case NO_ORG_DOCS:
  case RECORD_WRITE_ERROR:
  case ELAB_NOT_FOUND:
  case DOC_TYPE_NOT_FOUND:
  case READ_ERROR:
    return TRUE;
  default:
    return 0;
  }
}

int TElaborazioni::get_info(void)
{
  int err;
  
  // informazioni dalla tabella elaborazioni differite
  TTable t("ELD");                                      // tabella elaborazioni differite
  t.zero();
  t.put ("CODTAB", _codelab);           // imposta il codice elaborazione da cercare
  if (!(err = t.read (_isgteq)))                        // si posiziona sul record dell'elab. differita con codice cod_elab
  {
    error_box ("TElaborazioni::get_info() : errore di lettura %d da tab(ELD)", err);
    return READ_ERROR;
  }
  if (t.get("CODTAB") != _codelab)      // controlla se il codice trovato è proprio cod_tab
  {
    error_box ("TElaborazioni::get_info() : non esiste l'elaborazione con codice %s in tab(ELD)", (const char *)_codelab);
    return ELAB_NOT_FOUND;
  }
  
  // Imposta i dati relativi all'elaborazione differita corrente
  _elab.tipo_doc_org = t.get("S6");     // tipo documento originale
  _elab.tipo_doc_des = t.get ("S8");    // tipo documento destinazione
  _elab.stato_doc_ini = t.get ("S7");   // stato iniziale del documento originale
  _elab.stato_doc_fin = t.get ("S9");   // stato finale (dopo l'elaborazione) del documento originale
  _elab.codnum = t.get ("S5");                  // codice numerazione per il documento finale
  
  return 0;
}

int TElaborazioni::run_mask(void)
{
  int err;
  TMask *_msk = new TMask ("ve6000");           // carica la maschera
  
  // Imposta il flag di autorizzazione agente   
  TTable t("TIP");                                      // tabella tipi documento
  t.zero();                                                     // azzera i campi
  t.put ("CODTAB", _elab.tipo_doc_org); // tipo del documento originale
  if (!(err = t.read (_isgteq)))                                        // si posiziona sul record relativo al documento del tipo specificato
  {
    error_box ("TElaborazioni::run_mask() : errore di lettura %d da tab(TIP)", err);
    return READ_ERROR;
  }
  if (t.get ("CODTAB") != _elab.tipo_doc_org)   // verifica che il tipo di documento trovato sia quello richiesto
  {
    error_box ("TElaborazioni::run_mask() : non esiste il tipo documento %s in tab(TIP)", (const char *)_elab.tipo_doc_org);
    return DOC_TYPE_NOT_FOUND;
  }
  TFilename profilo(t.get ("S4"));              // nome del profilo documento (nome del .ini associato al tipo documento originale)
  profilo.ext("ini");                                   // necessario per aggiungere l'estensione
  TConfig profilo_doc(profilo);         // oggetto configurazione (file ini del documento)
  TConfig p(CONFIG_DITTA);                              // crea l'oggetto per rilevare l'autorizzazione dall'ini della ditta
  // gestione agente abilitata <==> abilitata in profilo documento e nell'ini della ditta
  int agente = (profilo_doc.get_int ("CODAG", "PROFILO") && p.get_int("AGENTE", "VE"));
  
  /* se il flag per la gestione agenti è != 0, allora visualizza i campi agente ed
     adotta la stessa convenzione usata per codice cliente e zona per gestire l'eventualita' che
     l'utente non specifichi nulla.
     Se è disabilitata, allora lascia vuoti i campi codice agente da e codice agente a, in modo
     da eliminare una condizione durante il test per il filtraggio dei records.
     */
  
  // nasconde i campi se la gestione agenti è disabilitata
  if (!agente)          
  {
    _msk->show (F_CODICE_AGENTE_DA, FALSE);
    _msk->show (F_CODICE_AGENTE_A, FALSE);
  }

  if (_msk->run() == K_ESC)             // se premuto esc, esci
    return ESC_PRESSED;
  
  _ordinamento = _msk->get_int (F_ORDINAMENTO_EMISSIONE);
  _raggruppa = _msk->get_int (F_RAGGRUPPA);

  TString temps;                        // stringa temporanea

  // Imposta i campi dei records campione per il filtraggio
  TLocalisamfile f(LF_DOC);             // file doc
  f.zero();                                             // azzera i campi
  TRectype first(f.curr()), last(f.curr());     // dichiara due records con la stessa struttura dei records di $doc
  
  first.put("TIPOCF", 'C');             // trattare solo clienti
  last.put ("TIPOCF", 'C');
  first.put ("TIPODOC", _elab.tipo_doc_org);    // tipo documento (da tab. ELD)
  last.put ("TIPODOC", _elab.tipo_doc_org);
  first.put ("STATO", _elab.stato_doc_ini);     // stato documento originale
  last.put ("STATO", _elab.stato_doc_ini);
  
  // codice cliente
  temps = _msk->get(F_CODICE_CLIENTE_DA);
  if (temps.not_empty())
    first.put ("CODCF", temps);
  temps = _msk->get(F_CODICE_CLIENTE_A);
  if (temps.not_empty())
    last.put ("CODCF", temps);
  
  // data
  first.put ("DATADOC", _msk->get(F_DATA_DOCUMENTO_DA));        // nessun controllo perché data doc. da e data doc. a sono checktype required
  last.put  ("DATADOC", _msk->get(F_DATA_DOCUMENTO_A));

  // codice zona
  temps = _msk->get (F_CODICE_ZONA_DA);                 // mette in temps il valore del campo codice zona da
  if (temps.not_empty())                                        // se è stato inserito un valore...
    // ******************** N.B.: il campo ZONA va aggiunto a $doc. verificare se il campo è proprio ZONA *****************
    first.put("ZONA", temps);                           // mettilo nel campo zona
  temps = _msk->get (F_CODICE_ZONA_A);
  if (temps.not_empty())
    last.put ("ZONA", temps); 

  // codice agente: imposta i campi solo se ne è abilitata la gestione
  // se agente è disabilitato, i campi agente rimangono vuoti
  if (agente)
  {
    temps = _msk->get (F_CODICE_AGENTE_DA);
    if (temps.not_empty())
      first.put("CODCF", temps);
    temps = _msk->get (F_CODICE_AGENTE_A);
    if (temps.not_empty())
      last.put ("CODCF", temps);
  }
  
  f.put ("STATO", _elab.stato_doc_ini);
  if (! (err = f.read (_isgteq)))
    error_box ("TElaborazioni::run_mask() : errore di lettura &d da doc", err);
  if (f.get ("STATO") != _elab.stato_doc_ini)
  {
    error_box ("TElaborazioni::run_mask() : non esistrono documenti allo stato %s", (const char *)_elab.stato_doc_ini);
    return NO_ORG_DOCS;
  }
  
  do            // scandisce tutti i records a partire dal primo che ha lo stato richiesto
  {
    TToken_string tempt;                // ttoken string per aggiungere chiavi all'array
    if (f.curr() >= first && f.curr() <= last)
    {
      tempt = f.get("CODNUM");          // utilizza la chiave 1 di $doc
      tempt.add( (const char *)f.get("ANNO") );
      tempt.add( (const char *)f.get("PROVV") );
      tempt.add( (const char *)f.get ("NDOC") );
      _chiavi->add(tempt);                              // aggiunge la chiave del record alla lista
    }
  }
  while (err = f.read(_isnext));
  if (err !=NOERR)
  {
    error_box ("TElaborazioni::run_mask() : errore di lettura %d da doc", err);
    return READ_ERROR;
  }
  
  if (!_chiavi->items())                                // se l'array è vuoto, indica al chiamante che non ci sono documenti da raggruppare
  {
    error_box ("TElaborazioni::run_mask() : nessun documento originale soddisfa le condizioni richieste");
    return NO_ORG_DOCS;
  }
  
  for (int i = 0; i<_chiavi->items()-1; i++)
    message_box ("Record %d: %s", i, (const char *)_chiavi->row(i));
  
  return 0;
}

int TElaborazioni::scan_doc(void)
{
  int err;              // codice ritornato dalle procedure
  
  if (err = get_info())
    return err;         // ritorna al chiamante l'errore di get_info, senza eseguire run_mask
  return run_mask();    // ritorna il codice di errore di run_mask
}
