#include <recarray.h>

#include <rdoc.h>

#include "ps0077.h"
#include "ps0077300.h"
#include "ps0077300a.h"

//la dichiarazione delle classi è nel ps0077300.h (come si dovrebbe sempre fare...)
//-----FORM--------------------------------------------------------------------------------------//
  
TEntrFor_form::TEntrFor_form() :TForm ("ps0077300a")
{                              
  // Usiamo esattamente la relazione e la chiave del from,
  // ma ne cambiamo l'ordinamento
  TRelation* rel = relation(); 
  const int key = TForm::cursor()->key();
  _sc = new TSorted_cursor(rel, "CODARTMAG|33->CODCF|NDOC", "", key);
} 

TEntrFor_form::~TEntrFor_form()
{ 
  delete _sc;
}

const TRectype* TEntrFor_form::find_original_rdoc(const TRectype& row) const
{
  const long id = row.get_long(RDOC_DAIDRIGA);
  if (id > 0L)
  {
    TToken_string key;
    key.add(row.get(RDOC_DACODNUM));
    key.add(row.get(RDOC_DAANNO));
    key.add(row.get(RDOC_DAPROVV));
    key.add(row.get(RDOC_DANDOC));
    for (int r = 1; ; r++)
    {
      key.add(r, 4);
      const TRectype& rec = cache().get(LF_RIGHEDOC, key);
      if (rec.empty()) break;
      if (rec.get_long(RDOC_IDRIGA) == id)
        return &rec;
    }
  }
  return NULL;
}

void TEntrFor_form::output_values(const TRectype & rec, const char * output, TForm_item & cf)
{
  TToken_string out(output, '!');
  TString curr;
  for (const char * str = out.get(0); str; str = out.get())
  { // scansione sugli elementi dell'output
    curr = str;
    int poseq = curr.find('='); // divide la stringa corrente in lvalue e rvalue
    if (poseq < 0)
      cf.set(rec.get(curr));
    else
    {
      int posrv = poseq+1;
      if (poseq >= 0 && curr[posrv] == '=')
        posrv++;
      TString16 fld(curr.left(poseq)); // preleva il nome del campo del form alla sinistra dell'uguale
      const TString dat(rec.get(curr.mid(posrv))); // preleva il nome del campo del file alla destra dell'uguale e lo legge dal record
      if (fld[0] == '#') fld.ltrim(1);
      
      if (fld.right(1) == "@")
      { // se c'è la a-commerciale è un gruppo
        char sec = cf.section().section_type();
        pagetype pt = cf.section().page_type();
        int group = atoi(fld);
        
        if (fld.find("->") >= 0)
        { // se nel gruppo c'è la freccia si riferisce ad un'altra sezione
          sec = fld[0]; 
          pt= (fld[1] != '-') ? char2page(fld[1]) : even_page;
        }

        TPrint_section &fs = section(sec, pt);
        word itms = fs.fields();

        for (word j=0; j<itms; j++)
        {
          TForm_item & fi = fs.field(j);
          
          if (fi.in_group(group))
            fi.set(dat);
        }
      }
      else
      {
        TForm_item & fi= cf.find_field(fld);
        fi.set(dat);
      }
    }
  }
}

bool TEntrFor_form::validate(TForm_item& cf, TToken_string& s)
{ 
  const TString code(s.get(0)); // prende il primo parametro, il codice del messaggio
  TString valore;
  
  if (code== "_PARENTDOC")
  {
    const TRectype * rdoc = &cursor()->curr();
    int level = s.get_int(1);
      
    for (; rdoc != NULL && level > 0; level--)
      rdoc = find_original_rdoc(*rdoc);
      
    if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
    {
      TString16 codnum(rdoc->get(RDOC_CODNUM));
      int anno = rdoc->get_int(RDOC_ANNO);
      TString16 provv(rdoc->get(RDOC_PROVV));
      long ndoc = rdoc->get_long(RDOC_NDOC);         
                            
      TToken_string key;
      key.add(provv);
      key.add(anno);
      key.add(codnum);
      key.add(ndoc);
          
      const TRectype& doc = cache().get(LF_DOC, key);
      output_values(doc, s.get(2), cf);
    }
    return TRUE;
  }
  
  if (code== "_PARENTROW")
  {
    const TRectype * rdoc = &  cursor()->curr();
    int level = s.get_int(1);
      
    for (; rdoc != NULL && level > 0; level--)
      rdoc = find_original_rdoc(*rdoc);
      
    if (rdoc != NULL && rdoc->get(RDOC_PROVV).not_empty())
    {
      output_values(*rdoc, s.get(2), cf);
    }
    return TRUE;
  }

  if (code== "_RITARDO")
  { 

// deve prima controllare se è stato selezionato un valore limite x il ritardo\anticipo
    const TString4 tiporit = app().get_tiporit();
    const TString16 id1 = s.get(1);
    const TString16 id2 = s.get(2);
    
    const TForm_item& fd1 = cf.find_field(id1);
    const TForm_item& fd2 = cf.find_field(id2);
    
    const TDate d1 = fd1.get();
    const TDate d2 = fd2.get();
    
    TString16 rit;
    long ritardo;
    
    if (d1.ok() && d2.ok())
    {
      ritardo = d1 - d2;
      
      if (ritardo > 0)
        rit.format("@b%ld@r",ritardo);
      else
        rit.format("%ld",ritardo);
    }
    else
      rit = "@b???@r";

//   if (app().get_dettaglio())
//   {    
//     const bool salta = ((tiporit == "R") && (ritardo < valrit)) ||
//                       ((tiporit == "A") && (ritardo > -valrit));
//      find_field('B',odd_page,"FORNITORI").set_height(salta ? 0 : 1);
//    }  
    cf.set(rit);  //scrive nel campo del form
    return TRUE;
  }
    
  return TForm::validate(cf, s);
}


//-----AUTOMASK---------------------------------------------------------------------------------//
  
TEntrFor_mask::TEntrFor_mask() :TAutomask ("ps0077300a")
{
}  
  
bool TEntrFor_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{ 
/*  switch (o.dlg())
  {
  default:
    break;
  } */
  return TRUE;
}

//-------SKELETON APPLICATION------------------------------------------------------------------------------//

// creazione dell'applicazione
bool TEntrFor::create()
{                        
  open_files(LF_DOC, LF_RIGHEDOC, LF_ANAMAG, LF_UMART, LF_CLIFO, 0);
  _mask = new TEntrFor_mask;
  _form = new TEntrFor_form();

  return TSkeleton_application::create();
}

// distruzione dell'applicazione
bool TEntrFor::destroy()
{
  delete _mask;
  delete _form;
  return TSkeleton_application::destroy();
}

//stampa dei parametri di testata
void TEntrFor::print_header()
{  
  _form->find_field('H', odd_page, FH_DACODART).set(_mask->get(F_DACODART));
  _form->find_field('H', odd_page, FH_ACODART).set(_mask->get(F_ACODART));
  _form->find_field('H', odd_page, FH_DACODFORN).set(_mask->get(F_DACODFOR));
  _form->find_field('H', odd_page, FH_ACODFORN).set(_mask->get(F_ACODFOR));
  _form->find_field('H', odd_page, FH_DADATA).set(_mask->get(F_DADATA));
  _form->find_field('H', odd_page, FH_ADATA).set(_mask->get(F_ADATA));
  
  _form->set_testata();
}

void TEntrFor::add_filter_expr(TString& filtro, short id, const char* campo, const char* cmp) const
{
  TMask_field& f = _mask->field(id);
  if (! f.empty())
  {
    if (filtro.not_empty())
      filtro << "&&";
      
    filtro << '(';  
    if (f.class_id() == CLASS_DATE_FIELD)
    {
      const TDate d(f.get());
      filtro << "ANSI(" << campo << ')' << cmp << '"' << d.string(ANSI) << '"';
    }
    else  
      filtro << campo << cmp << '"' << f.get() << '"';
    filtro << ')';
  }
}

void TEntrFor::add_filter_range(TString& filtro, short id1, short id2, const char* campo) const
{
  add_filter_expr(filtro, id1, campo, ">=");
  add_filter_expr(filtro, id2, campo, "<=");
}

//metodo per far vedere o meno la subsection ARTICOLI in base alle lune dell'utente
void TEntrFor::set_dettaglio()
{
  _dettaglio = _mask->get_bool(F_DETAIL); 
  _form->find_field('B',odd_page,"FORNITORI").enable(_dettaglio);  
  _form->find_field('B',odd_page,"FORNITORI2").enable(!_dettaglio);
}


void TEntrFor::main_loop()
{
  while (_mask->run() == K_ENTER)
  {
    
    TRectype recrdoc(LF_RIGHEDOC);
    TString filtro;
    TCursor& cursore = *_form->cursor();
    filtro << "(" << RDOC_CODARTMAG << "!=\"\")";
    
//fighissimo metodo di costruzione del filtrone senza doversi perdere tra "" e \%s !!  
    add_filter_range(filtro, F_DACODART, F_ACODART, RDOC_CODARTMAG);
    
    add_filter_range(filtro, F_DACODFOR, F_ACODFOR, "33->CODCF");  //33 è DOC;si scrive così x' non è il file principale
    
    add_filter_range(filtro, F_DADATA, F_ADATA, "33->DATADOC");
//già che si lavora sulle date...stabiliamo eventuali margini per una setregion
    TRectype darec(LF_RIGHEDOC);
    TRectype arec(LF_RIGHEDOC);
    darec.put(RDOC_PROVV, "D");
    arec.put(RDOC_PROVV, "D");
    
    TSheet_field &fld = _mask->sfield(F_SHEETNUMS);
    TString filtrosheet;
    
    int lines = 0, valid_line = 0;
    FOR_EACH_SHEET_ROW(fld,i,row)
    {
      if (row->get_char(0) > ' ')
      { 
        filtrosheet << "(" << RDOC_CODNUM << "=\"" << row->get(0) << "\")";
        filtrosheet << "||";
        valid_line = i;
        lines++;        
      }
    }                     

//prendo i parametri su ritardo\anticipo che passo al form
    _ritant = _mask->get_long(F_RITARDO);
    _tiporit = _mask->get(F_TIPORIT);
    
    if (filtrosheet.not_empty())
    {
      filtrosheet.rtrim(2); //toglie l'ultimo ||
//aggancia al filtro l'espressione dovuta alla numerazione documento
      if (filtro.not_empty())
        filtro << "&&(" << filtrosheet << ")";
      else
        filtro = filtrosheet;
    }
//setta il filtro finale al cursore
    const TDate dadata = _mask->get_date(F_DADATA);
    if (dadata.ok())
    {
      const int daanno = dadata.year();
      darec.put(RDOC_ANNO, daanno);
      if (lines == 1)
        darec.put(RDOC_CODNUM, fld.row(valid_line).get(0));
    }
    const TDate adata = _mask->get_date(F_ADATA);
    if (adata.ok())
    {
      const int aanno = adata.year();
      arec.put(RDOC_ANNO, aanno);
      if (lines == 1)
        arec.put(RDOC_CODNUM, fld.row(valid_line).get(0));
    }

    cursore.setregion(darec, arec);    
    cursore.setfilter(filtro, TRUE);
    
    cursore.items();
// abilita la sezione del body con i dettagli delle righedoc   
    set_dettaglio();
    
//..e vai che si stampa!
    print_header();     
    _form->print();

  }
}

int ps0077300(int argc, char **argv)
{
  TEntrFor a ;
  a.run(argc, argv, TR("Stampa di riepilogo entrate fornitori"));
  return 0;
}