#include <automask.h>

#include "velib04.h"
#include "velib04d.h"

#include <doc.h>
#include <rdoc.h>

///////////////////////////////////////////////////////////
// TConsegna ordini mask
///////////////////////////////////////////////////////////

class TConsegna_mask : public TAutomask
{
  bool _ordina_per_codice;
  bool _ignora_descrizioni;
  const TDocumento* _doc;

protected:
  virtual bool on_field_event(class TOperable_field& f, TField_event e, long jolly);

public:
  void doc2mask(const TDocumento& doc, const TString & articolo);

  TConsegna_mask(int header_code = 0, bool per_codice = false, bool ignora_descrizioni = false);
  virtual ~TConsegna_mask() { }
};

bool TConsegna_mask::on_field_event(class TOperable_field& f, TField_event e, long jolly)
{
  bool update_row = false;
  switch (f.dlg())
  {
  case S_QTADAEVADERE:
    if (e == fe_modify && jolly > 0)
    {
      TMask& m = f.mask();
      const real qta_residua   = m.get_real(S_QTARESIDUA);
      const real qta_daevadere = m.get_real(S_QTADAEVADERE);
      if (qta_daevadere > ZERO)
      {
        m.set(S_RIGACONSEGNATA, "X");
        if (qta_daevadere >= qta_residua)
        {
          m.set(S_RIGAEVASA, "X");
          m.disable(S_RIGAEVASA);
        }
        else
          m.enable(S_RIGAEVASA);
      }
      else
      {
        m.set(S_RIGAEVASA, " ");
        m.enable(S_RIGAEVASA);
      }
      update_row = !m.is_running();
    }
    break;
  case S_RIGAEVASA:
    if (e == fe_modify && jolly > 0 && f.get().not_empty())
    {
      TMask& m = f.mask();
      const real qta_daevadere = m.get_real(S_QTADAEVADERE);
      if (qta_daevadere.is_zero())
      {
        const TString& residuo = m.get(S_QTARESIDUA);
        m.set(S_QTADAEVADERE, residuo, true);
        update_row = !m.is_running();
      }  
    }
    break;
  case F_CONSEGNA:
    if (e == fe_button)
    {
      TSheet_field& s = sfield(F_ROWS);
      FOR_EACH_SHEET_ROW(s, n, row) if (!s.cell_disabled(n,S_RIGACONSEGNATA-FIRST_FIELD))     
      {        
        bool select = true;
        const real residuo = row->get(S_QTARESIDUA-FIRST_FIELD);
        const real evaso = row->get(S_QTADAEVADERE-FIRST_FIELD);   
        if (evaso == ZERO && residuo > ZERO)
        {
          row->add(residuo.string(), S_QTADAEVADERE-FIRST_FIELD);
          row->add("X", S_RIGAEVASA-FIRST_FIELD);
          s.disable_cell(n, S_RIGAEVASA-FIRST_FIELD);
        }
        if (evaso == ZERO && residuo == ZERO)
        {
          const int nriga = row->get_int(S_NUMRIGA-FIRST_FIELD);
          const TRiga_documento& rdoc = (*_doc)[nriga];
          select = rdoc.quantita().is_zero();
        }
        if (select)
          row->add("X", S_RIGACONSEGNATA-FIRST_FIELD);
      }
      s.force_update();
    }
    break;
  case F_ROWS:
    if (e == se_query_add || e == se_query_del)
      return false;
  default:break;
  }
  
  if (update_row)
  {
    TSheet_field& s = sfield(F_ROWS);
    const int riga = s.selected();
    s.update_row(riga);
    s.force_update(riga);
  }

  return true;
}

int rows_sort_func(TSheet_field & s, int i, int j)
{
  TToken_string & s1 = (TToken_string & )(s.row(i));
  TToken_string & s2 = (TToken_string & )(s.row(j));
  TString ss1, ss2;
  TDate dd1, dd2;
  real rr1, rr2;
  int fields[] = {S_CODART, S_LIVGIAC1, S_LIVGIAC2, S_LIVGIAC3, S_LIVGIAC4, 
    S_CODMAG, S_CODDEP, S_RIGAEVASA, S_DATACONS, S_QTARESIDUA, -1};
  int ret = 0, field = 0;
  while (fields[field] >= 0)
  {
    if (fields[field] == S_QTARESIDUA)
    {
      s1.get(fields[field]-FIRST_FIELD, rr1);
      s2.get(fields[field]-FIRST_FIELD, rr2);
      ret = rr2 < rr1 ? -1 : (rr2 > rr1 ? 1 : 0);
    } 
    else 
    {
      s1.get(fields[field]-FIRST_FIELD ,ss1);
      s2.get(fields[field]-FIRST_FIELD ,ss2);
      if (fields[field] == S_DATACONS)
      {
        dd1 = ss1;
        dd2 = ss2;
        ret = int (dd1.date2ansi() - dd2.date2ansi());
      } 
      else
        ret = ss1.compare(ss2);
    }
    if (ret != 0)
      break;
    field++;
  }
  return ret;
}

void TConsegna_mask::doc2mask(const TDocumento& doc, const TString & articolo)
{                   
  TWait_cursor hourglass;
  _doc = &doc;

  for (int n = fields()-1; n >= 0; n--)
  {
    TMask_field& f = fld(n);
    const TFieldref* fr = f.field();
    if (fr) 
    {
      const TString& val = doc.get(fr->name());
      f.set(val);
    }
  }
  
  const bool show_evaded = doc.tipo().mostra_righe_evase_in_elaborazione();
  
  TSheet_field& s = sfield(F_ROWS);
  s.destroy();
  const int rows = doc.physical_rows();
  for (int i = 0; i < rows; i++)
  {
    const TRiga_documento& rec = doc[i+1];
    const real residuo = rec.qtaresidua();
    const bool evasa = residuo.is_zero();
    bool show_line = show_evaded || !evasa;
    if (rec.is_descrizione())
      show_line = !_ignora_descrizioni;

    if ( show_line && (articolo.empty() || articolo == rec.get(RDOC_CODART)))
    {
      TToken_string& r = s.row(-1);
      r = " ";
      if (evasa)
        r.add(" ");
      else
        r.add(residuo.string());
      r.add(" ");              // Da evadere
      if (evasa) 
      {
        s.disable_cell(i, -1); // Disbilita tutta la riga ...
        s.enable_cell(i, 0);   // ... tranne il flag di consegna
        r.add("X");            // La considera evasa
      }
      else
        r.add(" ");
      r.add(rec.get(RDOC_CODMAG).left(3));
      r.add(rec.get(RDOC_CODMAG).mid(3));
      r.add(rec.get(RDOC_CODART));
      const TString& livello = rec.get(RDOC_LIVELLO);
      for (int l = 1; l <= 4; l++)
        r.add(livelli_giacenza().unpack_grpcode(livello, l));
      if (rec.get_date(RDOC_DATACONS).ok())
        r.add(rec.get_date(RDOC_DATACONS));
      else
        r.add(doc.get_date(DOC_DATACONS));
      r.add(rec.get(RDOC_PREZZO), s.cid2index(S_PREZZO));
      r.add(rec.get(RDOC_DESCR), s.cid2index(S_DESCR));
      r.add(rec.get(RDOC_TIPORIGA), s.cid2index(S_TIPORIGA));
      r.add(rec.get(RDOC_NRIGA),s.cid2index(S_NUMRIGA));
    }
  }                                                   
  if (_ordina_per_codice)
    s.sort(rows_sort_func);
} 

TConsegna_mask::TConsegna_mask(int header_code, bool per_codice, bool ignora_descrizioni)
               : TAutomask("velib04d")  , _ordina_per_codice(per_codice), _doc(NULL),
                 _ignora_descrizioni(ignora_descrizioni)
{ 
  TCodgiac_livelli cl;
  TSheet_field& s = sfield(F_ROWS);
  cl.set_sheet_columns(s, S_LIVGIAC1);
  if (header_code == 1)
  {                                   
    TString h; 
    h = "Quantita'\nconsegnata";
    s.set_column_header(S_QTARESIDUA, h);
    s.sheet_mask().field(S_QTARESIDUA).set_prompt("Q.ta' consegnata");
    
    h = "Quantita'\nda fatturare";
    s.set_column_header(S_QTADAEVADERE, h);
    s.sheet_mask().field(S_QTADAEVADERE).set_prompt("Q.ta' da fatturare");
  }
  else
    if (header_code == 2)
    {                                   
      TString h; 
      h = "Residuo";
      s.set_column_header(S_QTARESIDUA, h);
      s.sheet_mask().field(S_QTARESIDUA).set_prompt("Residuo         ");
    
      h = "Da evadere";
      s.set_column_header(S_QTADAEVADERE, h);
      s.sheet_mask().field(S_QTADAEVADERE).set_prompt("Da evadere        ");
    }
}

///////////////////////////////////////////////////////////
// TConsegna ordini
///////////////////////////////////////////////////////////

bool TConsegna_ordini::calcola_ncolli_tara_pnetto(const TString& codart, const real& qta,
                                                  real& ncolli, real& tara, real& pnetto) const
{
  const TRectype& articolo = cache().get(LF_ANAMAG, codart);
  const real ppcollo = articolo.get_real(ANAMAG_PPCOLLO);
  const bool ok = ppcollo > ZERO;
  if (ok)
  {
    ncolli = qta / ppcollo;
    ncolli.ceil(0);

    tara = ncolli * articolo.get_real(ANAMAG_TARA);
    pnetto = qta * articolo.get_real(ANAMAG_PESO);
  }

  return ok;
}

bool TConsegna_ordini::aggiorna_ncolli_tara_pnetto(TRiga_documento& r) const
{
  const TString& codart = r.get(RDOC_CODARTMAG);
  TArticolo articolo(codart);
  const real qta = articolo.convert_to_um(r.quantita(), NULL, r.get(RDOC_UMQTA));
  real ncolli, tara, pnetto;

  const bool ok = calcola_ncolli_tara_pnetto(codart, qta, ncolli, tara, pnetto);
  if (ok)
  {
    r.put(RDOC_NCOLLI, ncolli);
    r.put(RDOC_TARA, tara);
    r.put(RDOC_PNETTO, pnetto);
  }

  return ok;
}

bool TConsegna_ordini::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
                               const TDate& data_elab, bool interattivo)
{ 
  const int items_in = doc_in.items();
  const int items_out = doc_out.items();
  CHECK(items_in > 0, "Nessun documento da elaborare");
  CHECK(items_out> 0, "Nessun documento da generare");
  CHECK(items_in == 1 || items_out == 1 || items_out == items_in, 
        "Numero di documenti da elaborare 'strano'");

  bool ok = true;

  const int header_code = intestazioni_sheet();
    
  TConsegna_mask m(header_code, ordina_per_codice(), get_bool("B3"));

  const int items_max = items_in > items_out ? items_in : items_out;
  for (int d = 0; d < items_max && ok; d++)
  {
    TDocumento& indoc = doc_in[d < items_in ? d : 0];
    TDocumento& outdoc = doc_out[d < items_out ? d : 0];
    const TString& articolo = params().get("ARTICOLO");
    
    m.doc2mask(indoc, articolo);
    TArticolo art;
    if (articolo.not_empty())
    {
      art.read(articolo);
      params().set("QUANTITA", ZERO);
    }
    ok = m.run() == K_ENTER;
    if (ok)
    {
      if (gestione_riferimenti())
      { 
        // Determina ed eventualmente crea la riga di riferimento
        const int riga_rif = riferimenti_in_testa() ? 1 : outdoc.physical_rows()+1;
        if (riga_rif > outdoc.physical_rows())
        {
          TRiga_documento& rout = outdoc.new_row();
          rout.forza_sola_descrizione();
        }  
        
        TRiga_documento& rout = outdoc[riga_rif];     
        
        // Costruisce la stringa di riferimento
        TString riferimento;
        indoc.riferimento(riferimento);
        if (riferimento.empty()) 
          riferimento = indoc.tipo().descrizione();
        if (usa_doc_rif() && indoc.get(DOC_NUMDOCRIF).not_empty())
        {
          riferimento << " n. " << indoc.get(DOC_NUMDOCRIF);
          riferimento << " del " << indoc.get(DOC_DATADOCRIF);
        }
        else
        {
          riferimento << " n. " << indoc.numero();
          riferimento << " del " << indoc.data().string();
        }
    
        
        // Setta la descrizione se vuota
        if (rout.get(RDOC_DESCR).empty()) 
          rout.put(RDOC_DESCR, riferimento);
        else
        {                               
          // Altrimenti aggiungi il riferimento al memo
          TString memo(1024);
          memo = rout.get(RDOC_DESCEST);
          if (memo.empty())
          { 
            TString80 rif(rout.get(RDOC_DESCR));
        
            rif << '\n';
            rout.put(RDOC_DESCR, rif);
            rout.put(RDOC_DESCLUNGA, "X");
          }
          else
            memo << '\n';
          memo << riferimento;
          rout.put(RDOC_DESCEST, memo);
        }  
      }

      TToken_string campi_riga(80);   
      const bool ragg_rig = raggruppa_righe();
      
      if (ragg_rig)
      {
        campi_riga = "CODART|LIVELLO|UMQTA";  // Uguali sempre
        // Uguali opzionalmente
        if (riga_uguale(0)) campi_riga.add("CODMAG");
        if (riga_uguale(1)) campi_riga.add("CODIVA");
        if (riga_uguale(2)) campi_riga.add("PREZZO|SCONTO");
      }
  
      TSheet_field& s = m.sfield(F_ROWS);   
      int r = 0;
      FOR_EACH_SHEET_ROW(s, n, row)
      {
        r = row->get_int(S_NUMRIGA - FIRST_FIELD);
        if (*row->get(0) > ' ') // E' da consegnare?
        {        
          TRiga_documento& inrec = indoc[r];
          const real daeva = row->get(S_QTADAEVADERE - FIRST_FIELD);
  
          if (daeva > ZERO || row->get_char(S_RIGAEVASA-FIRST_FIELD) > ' ')
          {  
            const char* fqe = inrec.field_qtaevasa();
            // const real qtaevasa = inrec.get_real(fqe) + daeva;
            // inrec.put(fqe, qtaevasa);
            inrec.add(fqe, daeva);  // nuovo modo di incrementare

            inrec.put(RDOC_RIGAEVASA, row->get(S_RIGAEVASA - FIRST_FIELD));
          }
          if (articolo.not_empty())
          {                                           
            const TString4 um(inrec.get(RDOC_UMQTA));
            const real qta = art.convert_to_um(daeva,  params().get("UM"), um);
            params().set("QUANTITA", qta + params().get_real("QUANTITA"));
          }

          bool elaborata = false;   
          if (ragg_rig)
          {
            for (int i = 1; i <= outdoc.physical_rows(); i++)
            {
              TRiga_documento& outrec = outdoc[i];  
              if (outrec.sola_descrizione())               // Ignora le righe descrittive
                continue;
              if (inrec.raggruppabile(outrec, campi_riga)) // Se esiste una riga compatibile ...
              {                                                     
                if (!daeva.is_zero())
                {
                  const TString& qta_field = outrec.field_qta();
                  outrec.add(qta_field, daeva); // nuovo modo di incrementare
                
                  real ncolli, tara, pnetto;
                  calcola_ncolli_tara_pnetto(outrec.get(RDOC_CODARTMAG), daeva, ncolli, tara, pnetto);
                  outrec.add(RDOC_NCOLLI, ncolli);
                  outrec.add(RDOC_TARA, tara);
                  outrec.add(RDOC_PNETTO, pnetto);
                
                  outrec.dirty_fields();                 // Forza ricalcolo formule 
                }
                elaborata = true;                      // Ricorda di averla gia' elaborata
                break;
              }  
            }  
          }
          if (!elaborata)                              // Se la riga non e' stata gia' sommata ...
          {  
            const TString4 tiporiga = inrec.get(RDOC_TIPORIGA);
            TRiga_documento& outrec = outdoc.new_row(tiporiga);
            const TString& qta_field = outrec.field_qta();
            const TString& qtaevasa_field = outrec.field_qtaevasa();
  
            TDocumento::copy_data(outrec, inrec);
            outrec.put(qta_field, daeva);
            if (qta_field != RDOC_QTA) 
            {
              const real q = inrec.get_real(RDOC_QTA);
              if (q.is_zero()) 
                outrec.put(RDOC_QTA, UNO);             // Pezza temporanea
            }
            aggiorna_ncolli_tara_pnetto(outrec);
            if (kill_descrizione_estesa())             // Cancello eventualmente la descrizione estesa
            {
              outrec.zero(RDOC_DESCLUNGA);
              outrec.zero(RDOC_DESCEST);
            }

            outrec.dirty_fields();                     // Forza ricalcolo peso etc. 
            outrec.zero(qtaevasa_field);               // Azzera quantita' evasa erroneamente copiata dall'ordine
            outrec.zero(RDOC_RIGAEVASA);               // Azzera flag di evasa erroneamente copiata dall'ordine
            outrec.set_original_rdoc_key(inrec);
          }
        }
      }  
    }

    if (indoc.is_evaso())
    {
      indoc.stato(stato_finale_doc_iniziale()[0]);
    }
  }
  return ok;     
}