// Stampa ordini
#include <applicat.h>
#include <printer.h>
#include <tabutil.h>

#include "orlib.h"
#include "or1100a.h"

#include "../ve/velib.h"

// Tipi di stampa per selezionare il form
enum tipo_stampa {
  numero,   // or1100a.frm
  clifo,    // or1100b.frm
  agente,   // or1100c.frm
  articolo  // or1100d.frm
};

// Tipi di ordinamento
enum tipo_ord {
  num_doc,   // ordinamento per numero documento
  data_doc   // ordinamento per data documento
};

// Applicazione di stampa

class TStampa_ordini : public TSkeleton_application
{
  TMask          * _m;
  TOrdine_form   * _frm;
  tipo_stampa _tipo;
  TCodgiac_livelli *_codgiac;
  TAssoc_array     _tipi_riga; // Cache dei tipi riga attivati: tipo M, S, P, C, O D
  TString     _codnum;
  int         _anno;
  char        _provv, _tipocf,
              _TEA_ord, _TEA_rord; // Tipi ordini/righe 'T'utti/'E'vasi/'A'perti
  tipo_ord    _order;
  bool        _detail_rows, _detail_doc, _detail_cli, _detail_mag, _detail_dep,
              _pr_spese, _pr_prest, _pr_sconti, _pr_omaggi, _pr_descr,
              _opz_valore, _opz_prezzo, _opz_residuo, _opz_giacenza,
              _force_evase;
  int         _detail_level; //0..4    0 = Articoli 4 = FCG #4 Maximum detail level
  TString     _from_age, _to_age,
              _from_art, _to_art,
              _from_mag, _to_mag,
              _from_dep, _to_dep;
  TString_array
              _from_giac, _to_giac;
  long        _from_ndoc, _to_ndoc,
              _from_cf,   _to_cf;
  TDate       _from_date, _to_date,
              _from_cons, _to_cons;
  TArray _file;

protected:
  static bool stato_handler(TMask_field& f, KEY k);
  static bool detail_handler(TMask_field& f, KEY k);

  bool document_row_filter(const TRectype& row) const;
  static bool document_filter(const TRelation* rel);
  void add_tiporiga(TString& cond, const char tipo);
  
  virtual bool create(); 
  virtual bool destroy(); 
  virtual void main_loop();
  void set_totvaluta_items();
  void filter_for_number();
  void filter_for_clifo_agent();
  void filter_for_articolo();

  void show_giac_levels();
  void show_body_field_for_number(short id, bool on, int from = 0, int to = 0);
  void show_body_field_for_clifo_agent(short id, bool on, int from = 0, int to = 0);
  void show_body_field_for_articolo(short id, bool on, int from = 0, int to = 0);

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

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

bool TStampa_ordini::stato_handler(TMask_field& f, KEY k)
{
  if (f.to_check(k))
  {
    TMask& m = f.mask();
    const char v = f.get()[0];
    const bool b = m.get_bool(F_DETTAGLIO);
    if (v == 'E' && b) // Se si seleziona la stampa degli ordini totalmente evasi ha senso stampare solo le righe evase, cioe' tutte
    {
      m.set(F_STATORORD, "T");
      m.disable(F_STATORORD);
    }
    else
      if (b) // Qualsiasi altro tipo di stampa dettaglio righe puo' essere selezionata
        m.enable(F_STATORORD);
  }
  return true;
}

bool TStampa_ordini::detail_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TMask& m = f.mask();
    const bool b = m.get_bool(F_DETTAGLIO);
    const tipo_stampa tipo = (tipo_stampa) m.get_int(F_TIPO);
    
    if (tipo != numero)
    {
      m.enable(-GR_DETAIL,b);
      m.enable(F_STATOORD,!b);
      m.reset(-GR_PRINT);
      m.disable(-GR_PRINT);
    }
    else
    {
      m.enable(-GR_ART,b);
      m.enable(-GR_MAG,b);
      m.enable(-GR_PRINT, b);
      m.enable(F_STATORORD,b);
    }
    m.enable(F_STATOORD,!b);

    const bool enable_field = !b && (tipo != articolo);
    
    m.enable(F_DETAIL_BY_DOC, enable_field);
    m.set(F_DETAIL_BY_DOC, enable_field ? "" : "X");
    if (!b)
    {
      m.reset(F_FORCE_EVASE);
      m.disable(F_FORCE_EVASE);
    }
  }
  return true;
}

bool TStampa_ordini::create()
{
  open_files(LF_OCCAS, LF_CLIFO, LF_INDSP, LF_CFVEN, LF_UMART, LF_MAG, LF_STOMAG, LF_MOVMAG, LF_RMOVMAG,  LF_RIGHEDOC, 0);
  _m = new TMask ("or1100a");
  _m->set_handler(F_DETTAGLIO, detail_handler);
  _codgiac = new  TCodgiac_livelli;
  if (!_codgiac->enabled())
  {
    _m->disable(F_DETAIL_LEV);
    _m->hide(-GR_GIAC);
  }
  
  int err = NOERR;
  
  short id = F_GIAC1;
  TTable fcg("FCG");
  for (err = fcg.first(); err == NOERR; err = fcg.next(), id+=4)
    _m->set(id, fcg.get("CODTAB"));

  // Carica i tipi riga dalla tabella TRI
  TTable tri ("%TRI");
  for (err = tri.first(); err == NOERR; err = tri.next())
  {
    const TString& tiporiga = tri.get("S7");
    TToken_string* tok = (TToken_string*)_tipi_riga.objptr(tiporiga);
    if (tok == NULL)
    {
      tok = new TToken_string;
      _tipi_riga.add(tiporiga, tok);
    }
    const TString& ss = tri.get("CODTAB");
    tok->add(ss);
  }
  
  return TSkeleton_application::create();
}

bool TStampa_ordini::destroy()
{
  delete _m;
  delete _codgiac;
  return TSkeleton_application::destroy();
}

// Abilita disabilita i campi per i totali in valuta presenti alla fine del body
// per quel che riguarda le stampe per cli/fo/agenti/articoli
void TStampa_ordini::set_totvaluta_items()
{
  TString16 sec_name;
  
  for (int i = 1; i<=4; i++)
  {
    sec_name = "TOTVAL";
    sec_name << i;
    TForm_subsection& asec = (TForm_subsection&)_frm->find_field('B', odd_page, sec_name);
    short id = BODY_TOTVALORD + ((i-1) * 10);
    asec.printsection().find_field(id).show(_opz_valore);
    asec.printsection().find_field(id + 1).show(_opz_valore);
  }
}

bool TStampa_ordini::document_row_filter(const TRectype& row) const
{
  if (_from_cons.ok() || _to_cons.ok())
  {
    const TDate datacons = row.get(RDOC_DATACONS);
    if (_from_cons.ok() && datacons < _from_cons)
      return false;
    if (_to_cons.ok() && datacons > _from_cons)
      return false;
  }

  if (_TEA_rord > ' ')
  {
    const bool evasa = row.get_bool(RDOC_RIGAEVASA);
    if (_TEA_rord == 'E')
    {
      if (!evasa)
        return false;
      if (_force_evase)  // Controlla se evasa con residuo
      {
        const real qta = row.get(RDOC_QTA);
        const real qta_evasa = row.get(RDOC_QTAEVASA);
        if (qta_evasa >= qta)
          return false; // Non c'e' residuo
      }
    }
    if (_TEA_rord == 'A' && evasa)
      return false;
  }

  if (_from_art.full() || _to_art.full())
  {
    const TString& codart = row.get(RDOC_CODART);
    if (_from_art.full() && codart < _from_art)
      return false;
    if (_to_art.full() && codart > _to_art)
      return false;
  }

  return true;
}

bool TStampa_ordini::document_filter(const TRelation* rel)
{
  const TRectype& doc = rel->curr(LF_DOC);
  TRectype rdoc(LF_RIGHEDOC);
  rdoc.put(RDOC_PROVV, doc.get(DOC_PROVV));
  rdoc.put(RDOC_ANNO, doc.get(DOC_ANNO));
  rdoc.put(RDOC_CODNUM, doc.get(DOC_CODNUM));
  rdoc.put(RDOC_NDOC, doc.get(DOC_NDOC));
  TRecord_array righe(LF_RIGHEDOC, RDOC_NRIGA);
  righe.read(rdoc);
  for (int r = righe.rows(); r > 0; r--)
  {
    if (app().document_row_filter(righe.row(r)))
      return true;
  }
  return false;
}


//********************SEZIONI DEDICATE ALLE 4 TIPOLOGIE DI STAMPA PRINCIPALI*******************
//Per Numero Documento
//********************
void TStampa_ordini::show_body_field_for_number(short id, bool on, int from, int to)
{
  TForm_item* i = _frm->exist_field('B', odd_page, id);
  if (i != NULL)
  {
    i->enable(on);
    if (on && (to > from))
      i->width() = to - from;
//aggiunto in prova da qui...
    {
      const short offset1 = 300;
      TForm_subsection& ssec1 = (TForm_subsection&)_frm->find_field('B', odd_page, "RIGHEART"); // Sottosezione padre
      TForm_string& fld1 = (TForm_string&)ssec1.printsection().find_field(id + offset1);
      fld1.show(on);
      fld1.width() = to - from;
    }
//...a qui
    const short offset = !_detail_doc && _detail_rows ? 400 : 100;
    TForm_subsection& ssec = (TForm_subsection&)_frm->find_field('B', odd_page, "RIGHE"); // Sottosezione padre
    TForm_string& fld = (TForm_string&)ssec.printsection().find_field(id + offset);
    fld.show(on);
    if (on && (to > from))
    {
      fld.width() = to - from;
      fld.field(0).set_from(from);
      fld.field(0).set_to(to);
    }
  }
}

void TStampa_ordini::add_tiporiga(TString& cond, const char tipo)
{
  TString s;
  const char strtipo[2] = {tipo, '\0'};
  TToken_string* codici = (TToken_string*)_tipi_riga.objptr(strtipo);
  if (codici != NULL)
  {
    FOR_EACH_TOKEN((*codici), tok)
    {
      s.format("(%d->TIPORIGA==\"%s\")", LF_RIGHEDOC, tok);
      if (cond.not_empty())
        cond << "||";
      cond << s;
    }
  }
}

void TStampa_ordini::filter_for_number()
{
  CHECK(_frm, "Form non valido");
  
  TCursor* cur = _frm->cursor();
  
  cur->setkey(_order == num_doc ?  1 : 3); // Selezione per numero doc o data emissione
          
  TRectype f(LF_DOC), t(LF_DOC);
  TString filter_expr,s, lev_str, mag_str;
  
  if (_order == num_doc)
  {
    f.put(DOC_PROVV, _provv);
    f.put(DOC_ANNO, _anno);
    f.put(DOC_CODNUM, _codnum);
    t = f;
    f.put(DOC_NDOC, _from_ndoc);
    t.put(DOC_NDOC, _to_ndoc);
  }
  else
  {
    f.put(DOC_DATADOC, _from_date);
    t.put(DOC_DATADOC, _to_date);
    filter_expr << "&&(PROVV==\"" << _provv << "\")";
    if (_anno != 0)
      filter_expr << "&&(ANNO==\"" << _anno << "\")";
    filter_expr << "&&(CODNUM==\"" << _codnum << "\")";
  }
  cur->setregion(f,t);
  
  // Imposta l'ordine CODNUM+ANNO+PROVV+NDOC+CODART+LIVELLO+CODMAG+DATACONS
  // nel caso si voglia il dettaglio all'interno del singolo documento, per liv.giac e cod.mag.
  // In tal caso viene sostituito LF_RIGHEDOC nella relazione con un TSortedfile siffatto
  if (_detail_rows && !_detail_doc)
  {
    s << "CODNUM|ANNO|PROVV|NDOC|CODART|";
    
    if (_detail_level > 0)
      lev_str.format("LIVELLO[1,%d]",_codgiac->packed_length(_detail_level));
    if (_detail_mag)
      mag_str.format("CODMAG[1,3]");
    if (_detail_dep)
      mag_str.format("CODMAG");
    
    if (lev_str.not_empty())
      s << lev_str << "|";
    if (mag_str.not_empty())
      s <<  mag_str << "|";
    s << RDOC_DATACONS;
    
    TSortedfile *rdoc = new TSortedfile(LF_RIGHEDOC,NULL,s,"",1);
    cur->relation()->replace(rdoc,1,"CODNUM==CODNUM|ANNO==ANNO|PROVV==PROVV|NDOC==NDOC");

    TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "RIGHEART");
    ssec.enable(); 
    TString cond(ssec.condition());
    if (lev_str.not_empty())
      cond << "+" << lev_str;
    if (mag_str.not_empty())
      cond << "+" << mag_str;
    ssec.setcondition(cond, _strexpr);
  }
  
  if (_TEA_ord == 'E')
    filter_expr << "&&(DOCEVASO==\"X\")";
  else
    if (_TEA_ord == 'A')
      filter_expr << "&&(DOCEVASO!=\"X\")";

  if (!_detail_rows)
  {
    // In caso di dettaglio per righe non va settato il filtro per dataconsegnain quanto
    // gi� impostato sulla sottosezione (vedi sotto)
    if (_from_cons.ok())
    {
      filter_expr << "&&";
      s.format("(ANSI(DATACONS)>=\"%s\")", 
                   (const char*)_from_cons.string(ANSI));
      filter_expr << s;
    }
    if (_to_cons.ok())  
    {
      filter_expr << "&&";
      s.format("(ANSI(DATACONS)<=\"%s\")", 
                   (const char*)_to_cons.string(ANSI));
      filter_expr << s;
    }
  }

  if (filter_expr.starts_with("&&"))
    filter_expr.ltrim(2);
  cur->setfilter(filter_expr);

  // Filtro aggiuntivo per eliminare testate di documenti in cui tutte
  // le righe hanno data di consegna fuori range.
  if (_detail_doc) // Era if (_detail_rows && _detail_doc)
    cur->set_filterfunction(document_filter);
  
  if (_detail_rows)
  {
    for (short i = BODY_COL_UM; i<=BODY_COL_LAST; i++)
      _frm->find_field('B', odd_page, i).show();
    _frm->find_field('B', odd_page, "DET").show(); // Visualizza la sottosezione
    TForm_subsection& ssec = (TForm_subsection&)_frm->find_field('B', odd_page, "RIGHE"); // Sottosezione padre
    
    // Applica filtri alla sezione
    TString cond;
    
    // Aggiunge filtro sui tipi di riga
    // E' abbastanza utile avere tutti i tipi riga merce
      // Carica i tipi riga dalla tabella TRI
    add_tiporiga(cond, 'M');

    if (_pr_spese)
      add_tiporiga(cond, 'S');

    if (_pr_prest)
      add_tiporiga(cond, 'P');

    if (_pr_sconti)
      add_tiporiga(cond, 'C');

    if (_pr_omaggi)
      add_tiporiga(cond, 'O');

    if (_pr_descr)
      add_tiporiga(cond, 'D');

    cond.insert("("); cond << ")";
    
    // TBI: stampa righe di sconto testata od esenzione. Siccome non sono righe fisiche
    // credo sara' necessario implementarle con un messaggio nella validate...
        
    // Applica il filtro per righe evase/aperte
    s = "";
    if (_TEA_rord == 'E')
      s.format("&&(%d->RIGAEVASA==\"X\")",LF_RIGHEDOC);
    else
      if (_TEA_rord == 'A')
        s.format("&&(%d->RIGAEVASA!=\"X\")",LF_RIGHEDOC);
    
    cond << s;
    
    s = "";
    if (_force_evase)
      s.format("&&(STR(%d->QTAEVASA<%d->QTA))", LF_RIGHEDOC, LF_RIGHEDOC);
    cond << s;
    
    // Setta i range per la data di consegna
    if (_from_cons.ok())
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(ANSI(%d->DATACONS)>=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_from_cons.string(ANSI));
      cond << s;
    }
    if (_to_cons.ok())  
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(ANSI(%d->DATACONS)<=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_to_cons.string(ANSI));
      cond << s;
    }

    // Setta i range per il codice magazzino
    if (_from_mag.not_empty())
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(%d->CODMAG>=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_from_mag);
      cond << s;
    }
    if (_to_mag.not_empty())
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(%d->CODMAG<=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_to_mag);
      cond << s;
    }

    // Setta i range per il codice articolo
    if (_from_art.not_empty())
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(%d->CODART>=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_from_art);
      cond << s;
    }
    if (_to_art.not_empty())
    {
      if (cond.not_empty())
        cond << "&&";
      s.format("(%d->CODART<=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_to_art);
      cond << s;
    }
    
    s.format("&&(%d->CODART!=\"\")", LF_RIGHEDOC);
    cond << s;
    
    if (cond.not_empty())
      ssec.setcondition(cond, _strexpr);
    
    if (!_detail_doc)
    {
      TForm_subsection& ss = (TForm_subsection&)_frm->find_field('B', odd_page, "RIGHE");
      TPrint_section&   ps = ss.printsection();
      for (short j = BODY_COL_FIRST; j <= BODY_COL_LAST; j++)
      {
        ps.find_field(j + 100).disable();
        ps.find_field(j + 400).enable();
      }
    }
  }

// Abilitazione intestazioni di colonna
  show_body_field_for_number(BODY_COL_VALORE, _opz_valore);
  show_body_field_for_number(BODY_COL_VALRES, _opz_valore);
  show_body_field_for_number(BODY_COL_PRZSCON, _opz_prezzo);
  show_body_field_for_number(BODY_COL_INTEST, _opz_residuo);
  show_body_field_for_number(BODY_COL_GIACATT, _opz_giacenza);

  _frm->find_field('F', last_page, BODY_COL_VALORE+200).show(_opz_valore);
  _frm->find_field('F', last_page, BODY_COL_VALRES+200).show(_opz_valore);

  show_giac_levels();
}

//Per Cliente/Fornitore o per Agente
//**********************************
void TStampa_ordini::show_body_field_for_clifo_agent(short id, bool on, int from, int to)
{
  TForm_item* i = _frm->exist_field('B', odd_page, id);
  if (i != NULL)
  {
    i->show(on);
    if (on && (to > from))
      i->width() = to - from;

    {
      const short offset1 = 100;
      TForm_subsection& ssec1 = (TForm_subsection&)_frm->find_field('B', odd_page, "DOCUMENTI"); // Sottosezione padre
      TForm_string * fld1 = (TForm_string *) ssec1.printsection().exist_field(id + offset1);
      if (fld1 != NULL)
      {
        fld1->show(on);
        if (on && to > from)
          fld1->width() = to - from;
      }
    } 

    {
      const short offset1 = 400;
      TString16 subsection;
      if (_tipo == clifo)
        subsection << "DOCUMENTI";
      else
        subsection << "ARTCLI";
      TForm_subsection& ssec1 = (TForm_subsection&)_frm->find_field('B', odd_page, subsection); // Sottosezione padre
      TForm_string& fld1 = (TForm_string&)ssec1.printsection().find_field(id + offset1);
      fld1.show(on);
      if (to > from)
      {
        fld1.width() = to - from;
        fld1.field(0).set_from(from);
        fld1.field(0).set_to(to);
      }
    }

    const short offset2 = 200;
    TForm_subsection& ssec2 = (TForm_subsection&)_frm->find_field('B', odd_page, "RIGHEDOC"); // Sottosezione padre
    TForm_string& fld2 = (TForm_string&)ssec2.printsection().find_field(id + offset2);
    fld2.show(on);
    if (on && to > from)
    {
      fld2.width() = to - from;
      fld2.field(0).set_from(from);
      fld2.field(0).set_to(to);
    }
  }
}

void TStampa_ordini::filter_for_clifo_agent()
{
  CHECK(_frm, "Form non valido");
  
  const bool is_for_cli = _tipo == clifo;
  
  TString s, ws,lev_str, mag_str;
  TSorted_cursor* cur = (TSorted_cursor*)_frm->cursor();
  
  if (_detail_rows && !_detail_doc) // Cambia l'ordinamento se si vuol dettagliare per articolo e non per documento
  {
    if (_detail_level > 0)
      lev_str.format("LIVELLO[1,%d]",_codgiac->packed_length(_detail_level));
    if (_detail_mag)
      mag_str.format("CODMAG[1,3]");
    if (_detail_dep)
      mag_str.format("CODMAG");
    
    if (!is_for_cli)
      s.format("%d->CODAG|",LF_DOC);
    if (is_for_cli || _detail_cli)
    {
      ws.format("%d->TIPOCF|%d->CODCF|%d->OCFPI|",LF_DOC, LF_DOC, LF_DOC);
      s << ws;
    }
    s << "CODART|";
    if (lev_str.not_empty())
      s << lev_str << "|";
    if (mag_str.not_empty())
      s <<  mag_str << "|";
    s << "DATACONS";
    cur->change_order(s);
  }
  //Mo setto li filtri, altrimenti stampa tutto er file de' righe documento
  TRectype f(LF_RIGHEDOC), t(LF_RIGHEDOC);
  TString filter_expr;
  
  f.put(DOC_CODNUM, _codnum);
  if (_anno != 0)
  {
    f.put(DOC_PROVV, _provv);
    f.put(DOC_ANNO, _anno);
  }
  else
  {
    s.format("(PROVV==\"%c\")&&", _provv);
    filter_expr << s;
  }
  
  t = f;
  cur->setregion(f,t); // This is the region...

  s.format("(%d->TIPOCF==\"",LF_DOC);
  filter_expr << s << _tipocf << "\")"; // Nel caso di stampa per agenti e' sempre "C"
  
  s.format("&&(%d->CODART!=\"\")", LF_RIGHEDOC);
  filter_expr << s;
  
  // Filtro su Cli/Fo   od agente
  if (is_for_cli)
  {
    if (_from_cf > 0L)
    {
      s.format("&&(STR(NUM(%d->CODCF)>=%ld))", LF_DOC, _from_cf);
      filter_expr << s;
    }
    
    if (_to_cf > 0L)
    {
      s.format("&&(STR(NUM(%d->CODCF)<=%ld))", LF_DOC, _to_cf);
      filter_expr << s;
    }
  }
  else
  {
    if (_from_age.not_empty())
    {
      s.format("&&(%d->CODAG>=\"%s\")", LF_DOC, (const char*)_from_age);
      filter_expr << s;
    }
    
    if (_to_age.not_empty())
    {
      s.format("&&(%d->CODAG<=\"%s\")", LF_DOC, (const char*)_to_age);
      filter_expr << s;
    }
  }
  
  // Filtro sulla data ordine...
  if (_from_date.ok())
  {
    s.format("&&(ANSI(%d->DATADOC)>=\"%s\")", LF_DOC,
                 (const char*)_from_date.string(ANSI));
    filter_expr << s;
  }
  if (_to_date.ok())
  {
    s.format("&&(ANSI(%d->DATADOC)<=\"%s\")", LF_DOC,
                 (const char*)_to_date.string(ANSI));
    filter_expr << s;
  } 
                                               
  // Filtro sulla data consegna...
  if (_from_cons.ok())
  {
    s.format("&&(ANSI(DATACONS)>=\"%s\")", 
                 (const char*)_from_cons.string(ANSI));
    filter_expr << s;
  }
  if (_to_cons.ok())  
  {
    s.format("&&(ANSI(DATACONS)<=\"%s\")", 
                 (const char*)_to_cons.string(ANSI));
    filter_expr << s;
  }

  if (_detail_rows)
  {
    // Setta i range per il codice articolo
    if (_from_art.full())
    {
      s.format("&&(%d->CODART>=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_from_art);
      filter_expr << s;
    }
    if (_to_art.full())
    {
      filter_expr << "&&";
      s.format("(%d->CODART<=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_to_art);
      filter_expr << s;
    }
    // Setta i range per i livelli di giacenza (da 1 a 4)
    if (_detail_level > 0)
      for (int lev=1, index=0; lev <= _detail_level; lev++)
      {
        if (!_codgiac->enabled(lev))
          continue;
        TString& from = (TString&) _from_giac[index];
        TString& to   = (TString&) _to_giac[index++];
        const int starts = _codgiac->code_start(lev);
        const int ends   = starts+_codgiac->code_length(lev);
        if (from.not_empty())
        {
          s.format("&&(%d->LIVELLO[%d,%d]>=\"%s\")",
            LF_RIGHEDOC,starts,ends,(const char*)from);
          filter_expr << s;
        }
        if (to.not_empty())
        {
          s.format("&&(%d->LIVELLO[%d,%d]<=\"%s\")", 
            LF_RIGHEDOC,starts,ends,(const char*)to);
          filter_expr << s;
        }
      }
    // Setta i range per il codice magazzino (deposito incluso)
    if (_from_mag.not_empty())
    {
      s.format("&&(%d->CODMAG>=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_from_mag);
      filter_expr << s;
    }
    if (_to_mag.not_empty())
    {
      s.format("&&(%d->CODMAG<=\"%s\")", 
                   LF_RIGHEDOC, (const char*)_to_mag);
      filter_expr << s;
    }
  }
  
  s = "";
  if (!_detail_rows)
  {
    if (_TEA_ord == 'E')
      s.format("&&(%d->DOCEVASO==\"X\")",LF_DOC);
    else
      if (_TEA_ord == 'A')
        s.format("&&(%d->DOCEVASO!=\"X\")",LF_DOC);
  }
  else
  {
    if (_TEA_rord == 'E')
    {
      s.format("&&(%d->RIGAEVASA==\"X\")",LF_RIGHEDOC);
      if (_force_evase)
        s << "&&(STR(" << LF_RIGHEDOC << "->QTAEVASA<" << LF_RIGHEDOC << "->QTA))";
    }
    else
      if (_TEA_rord == 'A')
        s.format("&&(%d->RIGAEVASA!=\"X\")",LF_RIGHEDOC);
  } 
   
  if (s.not_empty())
    filter_expr << s;

  cur->setfilter(filter_expr,true,2);
  
  // Alla fine setta i campi da vedere
  if (!is_for_cli && _detail_cli)
  {
  // Solo stampa per agenti: se si e' settato il distinguo per clienti
  // mostra l'intestazione prima di ogni cambio cliente
    TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "HCLIENTI");
    ssec.enable();
  }
  
  if (!_detail_rows || _detail_doc) // Stampa distinguendo per documento e non per righe articolo...
  {
    TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "DOCUMENTI");
    if (!is_for_cli)
      ssec.enable(); // Se stampa per agenti e dettaglia documenti per cliente  abilita la sezione
    else
    { // Se stampa per cli/fo abilita i campi corrispondenti al distinguo per documento (valuta, residuo evaso ecc...)
      ssec.printsection().find_field(BODY_COL_CODART + 100).show();
      for (short id = BODY_COL_DESART + 100; id <= (BODY_COL_VALRES + 100); id++)
         ssec.printsection().find_field(id).enable();
    }
    // Deve essere abilitata ma nascosta, per eseguire i raggruppamenti sulle righe
    TForm_subsection& dsec = (TForm_subsection&) _frm->find_field('B', odd_page, "RIGHEDOC");
    dsec.enable();  
    dsec.hide(); 
  }

  // In qualsiasi caso va fatta questa abilitazione                                         
  bool is_art = _detail_rows && !_detail_doc;                                                                                                 
  
  ((TForm_subsection&) _frm->find_field('B', odd_page, "DOCUMENTI")).printsection().find_field(BODY_COL_VALORE + 100).enable(_opz_valore && !is_art);
  ((TForm_subsection&) _frm->find_field('B', odd_page, "DOCUMENTI")).printsection().find_field(BODY_COL_VALRES + 100).enable(_opz_valore && !is_art);
  
  if (_detail_rows) // Stampa dettaglio righe...
  {
    for (short i = BODY_COL_UM; i<=BODY_COL_LAST; i++)
      _frm->find_field('B', odd_page, i).show(); // Aggiunge le colonne di dettaglio
    // dulcis in fundo (Dulcinea mia adorata), si abilita la sezione RIGHEART
    // anziche' RIGHEDOC nel qual caso sia stato specificato il raggruppamento per Articoli (e sotto-opzioni)
    if (!_detail_doc) // Se la stampa deve distinguere e dettagliare per articoli e non per documenti...
    {
      TString cond;
      TForm_item& ff = _frm->find_field('B', odd_page, "RIGHEDOC");
      ff.y() = 1;
      
      if (!is_for_cli) // Abilita la sottosezione principale se stampa per agenti
      {
        TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "ARTCLI");
        ssec.enable();
        ssec.printsection().find_field(BODY_COL_VALORE  + 400).enable(_opz_valore);
        ssec.printsection().find_field(BODY_COL_VALRES  + 400).enable(_opz_valore);
        ssec.printsection().find_field(BODY_COL_PRZSCON + 400).enable(_opz_prezzo);
        ssec.printsection().find_field(BODY_COL_INTEST + 400).enable(_opz_residuo);
        ssec.printsection().find_field(BODY_COL_GIACATT + 400).enable(_opz_giacenza);
        
        if (_detail_cli) // Se e' abilitata la distinzione per clienti setta l'espressione di raggruppamento
        {
          cond = ssec.condition();
          cond << "+" << LF_CLIFO << "->TIPOCF+" << LF_CLIFO << "->CODCF+" << LF_DOC << "->OCFPI";
          ssec.setcondition(cond, _strexpr);
        }
      }
      
      // Setta la condizione di raggruppamento principale per articoli (comune alla stampa per cli/fo e per agenti)
      TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "RIGHEART");
      ssec.enable(); 
      cond = ssec.condition();
      if (lev_str.not_empty())
        cond << "+" << lev_str;
      if (mag_str.not_empty())
        cond << "+" << mag_str;
      ssec.setcondition(cond, _strexpr);
      
      if (is_for_cli)
      { // I seguenti campi non necessitano di abilitazione se la stampa e' per agente
        TForm_subsection& dsec = (TForm_subsection&) _frm->find_field('B', odd_page, "DOCUMENTI");
        for (short id = BODY_COL_FIRST + 400; id <= (BODY_COL_LAST + 400); id++)
           dsec.printsection().find_field(id).enable();
        dsec.printsection().find_field(BODY_COL_VALORE  + 400).enable(_opz_valore);
        dsec.printsection().find_field(BODY_COL_VALRES  + 400).enable(_opz_valore);
        dsec.printsection().find_field(BODY_COL_PRZSCON + 400).enable(_opz_prezzo);
        dsec.printsection().find_field(BODY_COL_INTEST + 400).enable(_opz_residuo);
        dsec.printsection().find_field(BODY_COL_GIACATT + 400).enable(_opz_giacenza);
      }
    }
    else
    {
      _frm->find_field('B', odd_page, "RIGHEDOC").enable(); // Abilita la sezione di dettaglio righe PER DOCUMENTO
      TForm_subsection& rd = (TForm_subsection&) _frm->find_field('B', odd_page, "RIGHEDOC");
      rd.printsection().find_field(BODY_COL_VALORE  + 200).enable(_opz_valore);
      rd.printsection().find_field(BODY_COL_VALRES  + 200).enable(_opz_valore);
      rd.printsection().find_field(BODY_COL_PRZSCON + 200).enable(_opz_prezzo);
      rd.printsection().find_field(BODY_COL_INTEST + 200).enable(_opz_residuo);
      rd.printsection().find_field(BODY_COL_GIACATT + 200).enable(_opz_giacenza);
    }
  }
  // Abilitazione intestazioni di colonna
  show_body_field_for_clifo_agent(BODY_COL_VALORE, _opz_valore);
  show_body_field_for_clifo_agent(BODY_COL_VALRES, _opz_valore);
  show_body_field_for_clifo_agent(BODY_COL_PRZSCON, _opz_prezzo);
  show_body_field_for_clifo_agent(BODY_COL_INTEST, _opz_residuo);
  show_body_field_for_clifo_agent(BODY_COL_GIACATT, _opz_giacenza);  

  //Totali generali nel footer last
  _frm->find_field('F', last_page, BODY_COL_VALORE+200).show(_opz_valore);
  _frm->find_field('F', last_page, BODY_COL_VALRES+200).show(_opz_valore);

  show_giac_levels();

  set_totvaluta_items();
}


//Per Articolo
//************

void TStampa_ordini::show_body_field_for_articolo(short id, bool on, int from, int to)
{
  TForm_item* i = _frm->exist_field('B', odd_page, id);
  if (i != NULL)
  {
    i->enable(on);
    if (on && (to > from))
      i->width() = to - from;

    i = _frm->exist_field('B', odd_page, id+400);
    if (i != NULL)
    {
      i->enable(on);
      if (on && (to > from))
      {
        TForm_string& fld = (TForm_string&) _frm->find_field('B', odd_page, id+300);
        i->width() = to - from;
        fld.width() = to - from;
        fld.field(0).set_from(from);
        fld.field(0).set_to(to);
      }    
    }
  
    TForm_subsection& asec = (TForm_subsection&)_frm->find_field('B', odd_page, "TOTVAL1");
    i = asec.printsection().exist_field(id+500);
    if (i != NULL)
    {
      i->enable(on);
      if (on && (to > from))
        i->width() = to - from;
    } 
  }
}

void TStampa_ordini::filter_for_articolo()
{
  CHECK(_frm, "Form non valido");
  
  TString s, ws,lev_str, mag_str;
  TSorted_cursor* cur = (TSorted_cursor*)_frm->cursor();

  if (_detail_level > 0)
    lev_str.format("LIVELLO[1,%d]",_codgiac->packed_length(_detail_level));
  if (_detail_mag)
    mag_str.format("CODMAG[1,3]");
  if (_detail_dep)
    mag_str.format("CODMAG");
    
  s << "CODART|";
  if (lev_str.not_empty())
    s << lev_str << "|";
  if (mag_str.not_empty())
    s <<  mag_str << "|";
	s << "DATACONS|ANNO|NDOC"; // MODIFICATO DA CRISTINA AGGIUNTO ANNO + NDOC
  cur->change_order(s); // Setta l'ordine 

  
  TRectype f(LF_RIGHEDOC), t(LF_RIGHEDOC);
  TString filter_expr;
  
  f.put(DOC_CODNUM, _codnum);
  f.put(RDOC_CODART, _from_art);
  if (_anno != 0)
  {
    f.put(DOC_PROVV, _provv);
    f.put(DOC_ANNO, _anno);
  }
  else
  {
    s.format("(PROVV==\"%c\") &&", _provv);
    filter_expr << s;
  }
  
  t = f;
  t.put(RDOC_CODART, _to_art);

  int tilde = 0x2;
  if (_to_art.empty() || cache().get(LF_ANAMAG, _to_art).empty())
    tilde = 0x0;    // Se scrivo un articolo parziale non mettere ~ alla fine della chiave

  cur->setkey(2); // Questa chiave rende piu' veloce la costruzione se indicato un range di articoli
  cur->setregion(f,t,tilde); // This is the region...

  s.format("(%d->TIPOCF==\"",LF_DOC);
  filter_expr << s << _tipocf << "\")"; // Nel caso di stampa per agenti e' sempre "C"
  
  s.format("&&(%d->CODART!=\"\")", LF_RIGHEDOC);
  filter_expr << s;

  // Filtro su Cli/Fo
  if (_from_cf > 0L)
  {
    s.format("&&(STR(NUM(%d->CODCF)>=%ld))", LF_DOC, _from_cf);
    filter_expr << s;
  }
    
  if (_to_cf > 0L)
  {
    s.format("&&(STR(NUM(%d->CODCF)<=%ld))", LF_DOC, _to_cf);
    filter_expr << s;
  }
  // Filtro sulla data ordine...
  if (_from_date.ok())
  {                                             
    s.format("&&(ANSI(%d->DATADOC)>=\"%s\")", LF_DOC,
                 (const char*)_from_date.string(ANSI));
    filter_expr << s;
  }
  if (_to_date.ok())
  {
    s.format("&&(ANSI(%d->DATADOC)<=\"%s\")", LF_DOC,
                 (const char*)_to_date.string(ANSI));
    filter_expr << s;
  } 
                                               
  // Filtro sulla data consegna...
  if (_from_cons.ok())
  {
    s.format("&&(ANSI(DATACONS)>=\"%s\")", 
                 (const char*)_from_cons.string(ANSI));
    filter_expr << s;
  }
  if (_to_cons.ok())  
  {
    s.format("&&(ANSI(DATACONS)<=\"%s\")", 
                 (const char*)_to_cons.string(ANSI));
    filter_expr << s;
  }
  
  // Setta i range per i livelli di giacenza (da 1 a 4)
  if (_detail_level > 0)
    for (int lev=1, index=0; lev <= _detail_level; lev++)
    {
      if (!_codgiac->enabled(lev))
        continue;
      TString& from = (TString&) _from_giac[index];
      TString& to   = (TString&) _to_giac[index++];
      const int starts = _codgiac->code_start(lev);
      const int ends   = starts+_codgiac->code_length(lev);
      if (from.not_empty())
      {
        s.format("&&(%d->LIVELLO[%d,%d]>=\"%s\")",
          LF_RIGHEDOC,starts,ends,(const char*)from);
        filter_expr << s;
      }
      if (to.not_empty())
      {
        s.format("&&(%d->LIVELLO[%d,%d]<=\"%s\")", 
          LF_RIGHEDOC,starts,ends,(const char*)to);
        filter_expr << s;
      }
    }
  // Setta i range per il codice magazzino (deposito incluso)
  if (_from_mag.not_empty())
  {
    s.format("&&(%d->CODMAG>=\"%s\")", 
                 LF_RIGHEDOC, (const char*)_from_mag);
    filter_expr << s;
  }
  if (_to_mag.not_empty())
  {
    s.format("&&(%d->CODMAG<=\"%s\")", 
                 LF_RIGHEDOC, (const char*)_to_mag);
    filter_expr << s;
  }

  if (_TEA_rord > ' ')
  {
    s = "";
    if (_TEA_rord == 'E')
    {
      s.format("&&(%d->RIGAEVASA==\"X\")",LF_RIGHEDOC);
      if (_force_evase)
        s << "&&(STR(" << LF_RIGHEDOC << "->QTAEVASA<" << LF_RIGHEDOC << "->QTA))";
    }
    else
      if (_TEA_rord == 'A')
        s.format("&&(%d->RIGAEVASA!=\"X\")",LF_RIGHEDOC);
    if (s.not_empty())
      filter_expr << s;
  }

  cur->setfilter(filter_expr,true,2);       // Setta il filtro e serra i ranghi

  // Setta la condizione di raggruppamento principale per articoli 
  TForm_subsection& ssec = (TForm_subsection&) _frm->find_field('B', odd_page, "ARTMAIN");
  ssec.enable(); 
  s = ssec.condition();
  if (lev_str.not_empty())
    s << "+" << lev_str;
  if (mag_str.not_empty())
    s << "+" << mag_str;
  ssec.setcondition(s, _strexpr);
  
  for (short id = BODY_COL_FIRST + 400; id <= (BODY_COL_LAST + 400); id++)
     _frm->find_field('B',odd_page,id).enable();

  // Abilitazione intestazioni di colonna
  show_body_field_for_articolo(BODY_COL_VALORE,_opz_valore);
  show_body_field_for_articolo(BODY_COL_VALRES,_opz_valore);
  show_body_field_for_articolo(BODY_COL_PRZSCON,_opz_prezzo);
  show_body_field_for_articolo(BODY_COL_INTEST,_opz_residuo);
  show_body_field_for_articolo(BODY_COL_GIACATT,_opz_giacenza);

  //Totali generali nel footer last
  _frm->find_field('F', last_page, BODY_COL_VALORE+200).show(_opz_valore);
  _frm->find_field('F', last_page, BODY_COL_VALRES+200).show(_opz_valore);

  //Abilitazione di eventuali colonne livelli di giacenza
  show_giac_levels();

  set_totvaluta_items();
}

//Parte comune
//************

void TStampa_ordini::show_giac_levels()
{
//accende le colonne con i livelli di giacenza esistenti  ;

  for (int l = 1; l <= _codgiac->max_levels(); l++)
  {
    const int level_fld = BODY_COL_LIVGIAC1 + l -1;
    const bool on = (l <= _detail_level) && _codgiac->enabled(l);
    const int from = _codgiac->code_start(l)-1;
    const int len = _codgiac->code_length(l);
    const int to = from + len;
    switch (_tipo)
    {
    case clifo:
    case agente:
      show_body_field_for_clifo_agent(level_fld, on, from, to);
      break;
    case articolo:
      show_body_field_for_articolo(level_fld, on, from, to);
      break;
    default:
      show_body_field_for_number(level_fld, on, from, to);
      break;
    }
  }
}

void TStampa_ordini::main_loop()
{
  while (_m->run()!=K_QUIT)
  {
    // selezione tipo di stampa per il form appropriato
    _tipo   =  (tipo_stampa) _m->get_int(F_TIPO);
    _codnum = _m->get(F_CODNUM);
    _provv  = _m->get(F_PROVV)[0];
    _anno   = _m->get_int(F_ANNO);
    _order  = _m->get(F_DATA_O_NUM)[0] == 'N' ? num_doc : data_doc;
    _from_ndoc = _m->get_long(F_NDOCFROM);
    _to_ndoc   = _m->get_long(F_NDOCTO);
    _from_date = _m->get_date(F_EMISFROM);
    _to_date   = _m->get_date(F_EMISTO);
    _from_cons = _m->get_date(F_CONSFROM);
    _to_cons   = _m->get_date(F_CONSTO);
    _from_age  = _m->get(F_AGEFROM);
    _to_age    = _m->get(F_AGETO);
    _from_cf   = _m->get_long(F_CFFROM);
    _to_cf     = _m->get_long(F_CFTO);
    _from_mag  = _m->get(F_MAGFROM);
    _to_mag    = _m->get(F_MAGTO);
    _from_dep  = _m->get(F_DEPFROM);
    _to_dep    = _m->get(F_DEPTO);
    if (_from_mag.not_empty())
      _from_mag.left_just(3);
    if (_to_mag.not_empty())
      _to_mag.left_just(3);
    _from_mag << _from_dep;
    _to_mag << _to_dep;
    
    _from_art    = _m->get(F_ARTFROM);
    _to_art      = _m->get(F_ARTTO);
    
    _from_giac.destroy();
    _to_giac.destroy();
    _from_giac.add(_m->get(F_GIAC1_FROM),0);
    _to_giac.add(_m->get(F_GIAC1_TO),0);
    _from_giac.add(_m->get(F_GIAC2_FROM),1);
    _to_giac.add(_m->get(F_GIAC2_TO),1);
    _from_giac.add(_m->get(F_GIAC3_FROM),2);
    _to_giac.add(_m->get(F_GIAC3_TO),2);
    _from_giac.add(_m->get(F_GIAC4_FROM),3);
    _to_giac.add(_m->get(F_GIAC4_TO),3);
    
    if (!_from_date.ok())
      _from_date = botime;
    if (!_to_date.ok())
      _to_date = eotime;
    _tipocf        = _m->get(F_TIPOCF)[0];
    _detail_rows   = _m->get_bool(F_DETTAGLIO);
    _detail_doc    = _m->get_bool(F_DETAIL_BY_DOC);
    _detail_cli    = _m->get_bool(F_DETAIL_BY_CLI);
    _detail_mag    = _m->get_bool(F_DETAIL_MAG);
    _detail_dep    = _m->get_bool(F_DETAIL_DEP);

    if (_m->field(F_DETAIL_LEV).active())
      _detail_level  = _m->get_int(F_DETAIL_LEV);
    else
      _detail_level = _detail_rows ? _codgiac->last_level() : 0;
    
    _pr_spese      = _m->get_bool(F_PRINTSPESE);
    _pr_prest      = _m->get_bool(F_PRINTPREST);
    _pr_sconti     = _m->get_bool(F_PRINTSCONTI);
    _pr_omaggi     = _m->get_bool(F_PRINTOMAGGI);
    _pr_descr      = _m->get_bool(F_PRINTDESCR);
    
    _opz_valore    = _m->get_bool(F_OPZ_VALORE);
    _opz_prezzo    = _m->get_bool(F_OPZ_PREZZO);
    _opz_residuo   = _m->get_bool(F_OPZ_RESIDUO);
    _opz_giacenza  = _m->get_bool(F_OPZ_GIACENZA);
    
    _force_evase   = _m->get_bool(F_FORCE_EVASE);

    _TEA_ord     = _m->get(F_STATOORD)[0];
    _TEA_rord    = _m->get(F_STATORORD)[0];
    
    const char* form_name = NULL;
    switch (_tipo)
    {
    case clifo:    form_name = "or1100b"; break;
    case agente:   form_name = "or1100c"; break;
    case articolo: form_name = "or1100d"; break;
    default:       form_name = "or1100a"; break;
    }
    
    _frm = new TOrdine_form(form_name);
    _frm->set_options(_detail_level, _detail_mag, _detail_dep);
    // Selezione cursore & filtro
    switch (_tipo)
    {
    case clifo   :
    case agente  : filter_for_clifo_agent(); break;
    case articolo: filter_for_articolo();    break;
    default      : filter_for_number();      break;
    }
    
    const int hh = 6;
    const int fl = printer().formlen();
    
    int rows[4];         // Righe orizzontali
    rows[0] = hh-2;
    rows[1] = hh;
    rows[2] = fl;
    rows[3] = 0;
    _frm->genera_intestazioni(odd_page, hh-1);
    _frm->genera_fincatura(odd_page, hh-2, fl, rows);
    
    // Crea il cursore
    if (_frm->cursor()->items() > 0)
    {
      // Sostituzione curr del cursore
      TCursor* cur = _frm->cursor();
      TDocumento *doc = new TDocumento; // Don't delete!
  
      cur->file(LF_DOC).set_curr(doc);
      cur->file(LF_RIGHEDOC).set_curr(new TRiga_documento(doc));// Don't delete!

      // stampa
      _frm->print();
    }
    delete _frm;
  }
}

int or1100(int argc, char** argv)
{
  TStampa_ordini a;
  a.run(argc,argv, TR("Stampa ordini"));
  return 0;
}