#include "velib.h"

///////////////////////////////////////////////////////////
// TFatturazione bolle
///////////////////////////////////////////////////////////

TFatturazione_bolle::TFatturazione_bolle(const char* cod) 
                   : TElaborazione(cod)
{
}

void TFatturazione_bolle::tipi_validi(TToken_string& tipi) const
{
  const TString& s2 = get("S2");
  tipi.cut(0);
  TString16 t;
  for (int i = 0; i < 5; i++)
  {
    t = s2.mid(i*4, 4);
    t.trim();
    if (t.not_empty())
      tipi.add(t);
  }
  CHECK(!tipi.empty_items(), "Nessun tipo documento valido");
}

void TFatturazione_bolle::stati_validi(TToken_string& stati) const
{
  const TString& s7 = get("S7");
  stati.cut(0);
  TString16 s;
  for (int i = 0; i < 5; i++)
  {
    s = s7.mid(i*4, 1);
    s.trim();
    if (s.not_empty())
      stati.add(s);
  }
  CHECK(!stati.empty_items(), "Nessuno stato documento valido");
}


bool TFatturazione_bolle::raggruppa(TDocumento& doc_in, TDocumento& doc_out)
{                 
#ifdef DBG
  const TString tipi = get("S2");
  const TString& tipodoc = doc_in.tipo().codice();                 
  for (int i = 0; i < 5; i++)
  {                  
    if (tipodoc == tipi.mid(i*4, 4))
      break;
  } 
  if (i >= 5)
  {
    NFCHECK("Tipo documento non valido: '%s'", (const char*)tipodoc);
    return FALSE;
  }  
#endif
  
  const char stato_finale_in = get_char("S4");
  doc_in.stato(stato_finale_in);
  
//  const TString& tipo_out = get("S8");
//  doc_out.put("TIPODOC", tipo_out);
  
  const char stato_finale_out = get_char("S9");
  doc_out.stato(stato_finale_out);           
  
  if (gestione_riferimenti())
  { 
    // Determina ed eventualmente crea la riga di riferimento
    const int riga_rif = riferimenti_in_testa() ? 1 : doc_out.physical_rows()+1;
    if (riga_rif > doc_out.physical_rows())
    {
      TRiga_documento& rout = doc_out.new_row();
      rout.forza_sola_descrizione();
    }  
    
    TRiga_documento& rout = doc_out[riga_rif];     
    
    // Costruisce la stringa di riferimento
    TString riferimento(80);
    riferimento = doc_in.tipo().riferimento();
    if (riferimento.empty()) 
      riferimento = doc_in.tipo().descrizione();
    riferimento << " n. " << doc_in.numero();
    riferimento << " del " << doc_in.data().string();
    
    // Setta la descrizione se vuota
    if (rout.get("DESCR").empty())
      rout.put("DESCR", riferimento);
    else
    {                               
      // Altrimenti aggiungi il riferimento al memo
      TString memo(1024);
      memo = rout.get("DESCEST");
      if (memo.empty())
        rout.put("DESCLUNGA", "X");
      else
        memo << '\n';
      memo << riferimento;
      rout.put("DESCEST", memo);
    }  
  }

  const bool ignora_desc = ignora_descrizioni();

  TToken_string campi_riga(80);   
  const bool ragg_rig = raggruppa_righe();
  if (ragg_rig)
  {
    campi_riga = "CODART|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");
  }
  
  for (int r = 1; r <= doc_in.physical_rows(); r++)
  {                
    const TRiga_documento& rin = doc_in[r];
    const bool rindesc = rin.sola_descrizione(); // La riga di input e' descrittiva
    if (ignora_desc && rindesc)
      continue;
    
    bool elaborata = FALSE;
    
    // Raggruppo le righe se e' settato il falg di raggruppamento e 
    // se la riga non contiene solo una descrizione
    if (ragg_rig && !rindesc)                    // Se devo raggruppare le righe ...
    {              
      const int last = doc_out.physical_rows();
      for (int o = 1; o <= last; o++)            // ... cerca una riga compatibile
      {
        TRiga_documento& rout = doc_out[o];  
        if (rout.sola_descrizione())             // Ignora le righe descrittive
          continue;
        if (rin.raggruppabile(rout, campi_riga)) // Se esiste una riga compatibile ...
        {
          rout += rin;                           // ... sommaci la quantita' ecc.
          elaborata = TRUE;                      // Ricorda di averla gia' elaborata
          break;
        }  
      }  
    }
    if (!elaborata)                              // Se la riga non e' stata gia' sommata ...
    {
      TRiga_documento& rout = doc_out.new_row(); // ... crea una riga nuova e ...
      doc_out.copy_data(rout, rin);              // ... copiaci tutti i campi della riga sorgente.
    }  
  }
  
  return TRUE;
}

bool TFatturazione_bolle::elabora(TLista_documenti& doc_in, TLista_documenti& doc_out,
                                  const TDate& data_elab)
{       
  bool ok = TRUE;
  
  TToken_string campi_doc(128);             // Lista di campi che devono essere uguali
  campi_doc = "TIPOCF|CODCF|CODVAL|CODLIN"; // Uguali sempre
      
  // Uguali opzionalmente
  const char* cond[] = { "CAMBIO", "SCONTO", "TIPODOC", "CODNUM",
                         "CODPAG", "CODABIA|CODCABA", "CODLIST", "CODAG",
                         "CODSPMEZZO", "CODPORTO", "CAUSTRASP", "CODVETT1|CODVETT2|CODVETT3",
                         NULL };
  for (int u = 0; cond[u]; u++)  
    if (doc_uguale(u)) campi_doc.add(cond[u]);

  for (int id = 0; id < doc_in.items() && ok; id++)
  {                                             
    TDocumento& campione = doc_in[id];
    const int tot = doc_out.items();
    int od = tot;                    
    
    if (campione.raggruppabile())    // Se il documento ha il flag di raggruppabilita' ...
    {
      for (od = 0; od < tot; od++)   // ... cerca un documento compatibile.
      {
        if (campione.raggruppabile(doc_out[od], campi_doc))
          break;
      }
    }  
    if (od >= tot)   // Se non ho trovato un documento compatibile ...
    {                // ... creane uno nuovo (certamente compatibile)                  
      const char    provv  = tipo_numerazione();
      const int     anno   = campione.anno();
//      const TString codnum = codice_numerazione_finale();
      const TString16 codnum(campione.get("CODNUM"));
      TDocumento* new_doc  = new TDocumento(provv, anno, codnum, -1);
      // Copia i dati della testata
      TDocumento::copy_data(new_doc->head(), campione.head());   
      
      new_doc->put("DATADOC", data_elab);
 
      // Aggiungilo alla lista dei documenti in uscita
      od = doc_out.add(new_doc);               
    }                      
    
    ok = raggruppa(campione, doc_out[od]);
  }

  const int tot = doc_out.items();
  const TString codnum(codice_numerazione_finale());
  const TString16 tipo_out(get("S8"));
  
  for (int i = 0; i < tot; i++)   // ... cerca un documento compatibile.
  {
    TDocumento & d = doc_out[i];
    
    d.put("CODNUM", codnum);
    d.put("TIPODOC", tipo_out);
  }
  return ok;
}