#include <diction.h>
#include "orlib.h"
#include "or1100a.h"

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

// Prima colonna quantita' nel form per stampa disponibilita'
#define COL1      4

TOrdine_form::TOrdine_form(const char* name) : TForm(name)
{
  _art_giac = new TArticolo_giacenza;
  _codgiac = new TCodgiac_livelli;
}

TOrdine_form::~TOrdine_form()
{
  delete _codgiac;
  delete _art_giac;
}

const int TOrdine_form::find_period(const TDate& dc)
{

  CHECK(_date_array, "Invalid date array in TOrdine_form");

	if (dc <= (TDate&)*_date_array->objptr(0))
		return 0;
  
	const int last = _date_array->last();
	
	for (int i = last; i >= 0; i--)
	{
		TDate& dt = (TDate&)*_date_array->objptr(i);
		if (dc > dt && i < last)
			return i + 1;
	}
  return -1;
}

bool TOrdine_form::genera_intestazione_supplementare(pagetype p, short y)
{
  CHECK(_date_array, "L'array delle date non e' impostato.");
  TPrint_section* body = exist('B', p);
  if (body == NULL || !body->columnwise()) 
    return FALSE;

  TPrint_section* header = exist('H', p);
  if (header == NULL) 
    return FALSE;

  const int items = _date_array->items();//body->fields();
  TForm_string* s;
  TString des;
  for (int j=0;j<items;j++)
  {
    TForm_item& fi = body->find_field(COL1+j*2);
    des = "Situaz. al ";
    des << ((TDate*)_date_array->objptr(j))->string();
    des.center_just(fi.width()*2);
    s = new TForm_string(header);
    s->id() = -1;
    s->set_x(fi.x());
    s->y() = y;
    s->set_prompt(des);
    s->temp() = TRUE;
    header->add_field(s);
  }
  
  return TRUE;
}

bool TOrdine_form::validate(TForm_item &cf, TToken_string &s)
{
  if (strcmp(s.get(0), "_ORDINE") == 0)
  {
    TDocumento& doc = (TDocumento&)cf.form().cursor()->curr(LF_DOC);
    TRiga_documento& rdoc = (TRiga_documento&)cf.form().cursor()->curr(LF_RIGHEDOC);
    // Add custom messages here
    // All the following messages takes 1 parameter: the field number to set
    TString action(s.get(1));
    
    if (action == "DESCRIZIONE")
    {
      // Scrive: Cod articolo/cod livello1/cod livello2/.../denominazione ultimo livello   codifica /cod mag /cod dep
      // Nel caso di stampa disponibilita' articoli stampa un pezzo della descrizione
      // vera e proprio dell'articolo.
      TString codart,livello, coddep, codmag;
      codart = rdoc.get(RDOC_CODART);
      if (_art_giac->read(rdoc.get(RDOC_CODART)) == NOERR)
      { 
        if (_normale)
          codart << " " << _art_giac->get(ANAMAG_DESCR);
        else
          codart = _art_giac->get(ANAMAG_DESCR);
        
        if (codart.len() > 40)
          codart.cut(40);
      }
      if (_level > 0)
        livello = rdoc.get(RDOC_LIVELLO);
      if (livello.not_empty())
      {
        for (int lev=1; lev <= _level; lev++)
        {
          if (!_codgiac->enabled(lev))
            continue;
          const int starts = _codgiac->code_start(lev) -1;
          const int length   = _codgiac->code_length(lev);
          codart << "/";
          codart << livello.mid(starts,length);
        }
        codart << "   " << _codgiac->name(_level);
        codart << " " << _codgiac->group_descr(livello,_level);
      }
      
      codmag = rdoc.get(RDOC_CODMAG).left(3);
      coddep = rdoc.get(RDOC_CODMAG).right(2);
      if (_detail_mag && codmag.not_empty())
        codart << TR(" Mag. ") << codmag;
      if (_detail_dep && coddep.not_empty())
        codart << TR(" Dep. ") << coddep;
      
      cf.set(codart);
    }
    else
    if (action == "SELECTUM")
    {
      const TString8 um(rdoc.get(RDOC_UMQTA));
      const TString8 cur_um(cf.find_field("407").get());
      
      if (cur_um.empty()) // Se l'unita' di misura non e' ancora stata settata prende quella principale
        cf.set(um);
      else
        if (cur_um != um) // Se c'e' ma e' diversa dalla prec. allora setta l'unita' di misura su quella principale
          if (_art_giac->read(rdoc.get(RDOC_CODART)) == NOERR)
          {
            TForm_item& qo = cf.find_field("408");
            TForm_item& qe = cf.find_field("409");
            TForm_item& qr = cf.find_field("411");
            real qtaor(qo.get());
            real qtaev(qe.get());
            real qtare(qr.get());
            
            // Converte i totali q.ta evasa e ordinata nella unita' di misura principale
            qtaor = _art_giac->convert_to_um(qtaor, "", cur_um, TRUE);
            qtaev = _art_giac->convert_to_um(qtaev, "", cur_um, TRUE);
            qtare = _art_giac->convert_to_um(qtare, "", cur_um, TRUE);

            qo.set(qtaor.string());
            qe.set(qtaev.string());
            qr.set(qtare.string());
                        
            cf.set(_art_giac->um().row(1).get("UM")); // UM principale
          }
        // TBI: 
        // Riga merce non a magazzino o non e' possibile reperire l'UM principale per art.
        // non posso interrompere la sezione di stampa da qui, e neppure cambiare il raggruppamento...
        // This seems to be a great dilemma... For now leave it as is: Somme dure e crude di quantita'
    }
    else
    if (action == "CONVUM") // Converte cazzilli quantitativi nella unita' di misura corrente
    {
      const TString4 um = rdoc.get(RDOC_UMQTA);
      const TString4 cur_um = cf.find_field("407").get();
      
      if (cur_um != um)
        if (_art_giac->read(rdoc.get(RDOC_CODART)) == NOERR)   // Perche' non  RDOC_CODARTMAG ???
        {
          real qt(cf.get());
          qt = _art_giac->convert_to_um(qt, cur_um, um, TRUE);

          cf.set(qt.string());
        }
    }
    else
      if (action == "VALTABLE") // Comandi per stampa riepilogo per valuta
      {
        TString subcommand(s.get(2));
        if (subcommand == "RESET")
        {
          _totvaluta.destroy();
          cf.find_field("TOTVAL1").disable();
          cf.find_field("TOTVAL2").disable();
          cf.find_field("TOTVAL3").disable();
          cf.find_field("TOTVAL4").disable();
        }
        else
        {
          const int valute = _totvaluta.items();
          TString codval(doc.get(DOC_CODVAL));
          const bool is_key = _totvaluta.is_key(codval);
          const bool is_new = !is_key && valute < 4;

          if (is_new) // Aggiunge l'elemento se non c'e'
            _totvaluta.add(codval,(_TTotale_valuta*)new _TTotale_valuta,is_key);
          // Controlla/stampa al massimo 4 valute
          if (is_key || is_new)
          {
            _TTotale_valuta& tv = (_TTotale_valuta&)_totvaluta[codval];
            const bool is_valord = subcommand == "VALORD";
            real& r =  is_valord ? tv.totord() : tv.totres();
            TString s_id;
            int i_id;
  
            // Abilita la sezione corrispondente e setta i valori all'interno
            if (!is_key)
            {
              TString16 sec_name = "TOTVAL";
              sec_name << valute+1;
              tv.secnum() = valute+1;
              cf.find_field(sec_name).enable();
              // Setta anche il codice valuta
              i_id = BODY_CODVAL + valute*10;
              s_id.format("%d",i_id);
              cf.find_field(s_id).set(codval);
              if (valute == 0)
              {
                i_id--;
                s_id.format("%d",i_id);
                cf.find_field(s_id).set("@bTotali");
              }
            }
            const int sn = tv.secnum();
            i_id = is_valord ? BODY_TOTVALORD : BODY_TOTVALRES;
              
            i_id += (sn-1)*10;
            s_id.format("%d",i_id);
            r +=  ((real) cf.get()); // Somma il valore corrente
            cf.find_field(s_id).set(r.string());
          }
        }
      }
      else
        if (action == "CALCDISP") // messaggi per calcolo disponibilita'
        {
          TString command(s.get(2));
          if (command == "RESET") // resetta la tabella
          {
            _totdisp.destroy();
            const real rz = ZERO;
            const int items = _date_array->items();
            for (int i = 0; i<items; i++)
              _totdisp.add(rz);
            // Legge anche una volta per tutte il TArticolo_giacenza (uargh uargh)
            if (_art_giac->read(rdoc.get(RDOC_CODART)) == NOERR)
            {
              _codmag  = rdoc.get(RDOC_CODMAG);
              _livello = rdoc.get(RDOC_LIVELLO);
            }
            else
              cf.set("Errore in lettura articolo");
          }
          else
          if (command == "CALC") // Effettua il calcolo per questa riga articolo, 
           //cumulando nell'array le quantita', espresse sempre in UM principale
          {
            const bool is_ordine_cliente = doc.get(DOC_TIPOCF)[0] == 'C';
            const TString16 causmag(doc.get(DOC_CAUSMAG));
            const TString16 um(rdoc.get(RDOC_UMQTA));
            const TDate datacons(rdoc.get_date(RDOC_DATACONS));
            int segno = is_ordine_cliente ? -1 : +1; // default 
            if (causmag.not_empty()) // se la causale esiste consulta il segno 
            {                         
              TCausale_magazzino cm(causmag);
              segno *= cm.sgn(is_ordine_cliente ? s_ordc : s_ordf);
            }
            // Reperisce fattore di conversione per UM principale,
            // la quantita residua
            real qtares = rdoc.qtaresidua(); // ZIO PERA! ag v�l la riga dal document       
            qtares = _art_giac->convert_to_um(qtares, "", um, TRUE);
            qtares *= segno; // mette a posto il segno...
            // Trova il periodo giusto
            const int index = find_period(datacons);
            if (index >= _totdisp.items()) 
              _totdisp.add(ZERO, index);    // Added by Guy!  Should never happen :-)
            real& rv = (real&) _totdisp[index];
            rv += qtares;

            const TDate datascimp(doc.get_date("DATASCIMP"));
						
						if (datascimp.ok())
						{
	            const int last_index = find_period(datascimp);
							if (last_index >= 0)
							{
								real& rv = (real&) _totdisp[last_index];
								rv -= qtares;
							}
						}
          }
          else
            if (command == "PRNUM") // Stampa l'unita' di misura principale
            {
              const TRecord_array& um = _art_giac->um();
              if (um.rows() > 0)             // Controlla che ci sia almeno una unita' di misura  
                cf.set(um.row(1).get("UM")); // UM principale
              else
                cf.set("");
            }
            else
            {
              const int period = s.get_int(3);
              //const int items  = _date_array->items();
              TString16 annoes;
              real giacenza, scorta_min;

              TEsercizi_contabili esc;
              annoes << esc.date2esc(doc.get_date(DOC_DATADOC));
              //TString16 codmag(rdoc.get(RDOC_CODMAG));
              //TString16 livello(rdoc.get(RDOC_LIVELLO));
              const int codmag_len  = (_detail_dep || _detail_mag) ? _codmag.len() : 0;
              const int livello_len = _level > 0 ? _livello.len() : 0;
              //if (_art_giac->read(rdoc.get(RDOC_CODART)) == NOERR)
              {
                // Serve l'anno esercizio del magazzino... 
                
                // Ciclo sulle giacenze di magazzino
                TRecord_array& mmgg = _art_giac->mag(annoes);
                const int rows = mmgg.rows();
                // Cumula raggruppando le giacenze per lo stesso mag/dep/liv.giac
                // Scurre alla ruvescia
                for (int i=mmgg.last_row();i>0;i--)
                {
                  const TRectype& rec = mmgg.row(i); // gosh!?
                  
                  //checkka se trattasi di medesimo liv giac/mag/dep in caso sia stato spec. il dettaglio
                  // altrimenti cumula el todo
                  if (codmag_len == 0 || (rec.get(MAG_CODMAG).compare(_codmag, codmag_len) == 0))
                    if (livello_len == 0 || (rec.get(MAG_LIVELLO).compare(_livello, livello_len) == 0))
                    {
                      giacenza       += _art_giac->giacenza_corretta(rec, _giac_eff, _val_comp);
                      scorta_min     = rec.get_real(MAG_SCORTAMIN);
                    }
                }
              }
              for (int i = 0; i< period/*items*/; i++)
                giacenza += (real&)_totdisp[i];
              if (command == "PRNGIAC") // Stampa la giacenza prevista
              {
                cf.set(giacenza.string());
              }
              else
                if (command == "PRNSOTT") // Stampa il sottoscorta
                {
                  if (giacenza < scorta_min)
                  {
                    giacenza = scorta_min - giacenza;
                    cf.set(giacenza.string());
                  }
                  else
                    cf.set("");
                }
                // Ignore any other command
             }
        }
        else
        if (action == "PREZZONS")
        {
          real pns = rdoc.prezzo(TRUE,FALSE); // Prezzo netto scontato
          cf.set(pns.string());
        }
        else
          if (action == "RAGSOC")
          { 
            // Compone la ragione sociale (considera gli occasionali)
            // Il formato � il seguente: CODICE (OCFPI) RAGIONE_SOCIALE
            TString ws;
            const bool print_cod = s.get_int(2) != 0;
            TDocumento&   documento = (TDocumento&)cf.form().cursor()->curr(LF_DOC);
            TCli_for&     cli_for   = documento.clifor();
            TOccasionale& cli_occ   = documento.occas();
            const bool occasionale  = cli_for.occasionale();
            if (print_cod)
              ws << cli_for.get("CODCF") << " ";
            if (occasionale)
            {
              ws << "(" << cli_occ.get("CFPI") << ") " ;
              ws << cli_occ.get("RAGSOC");
            }
            else
              ws << cli_for.get("RAGSOC");
            cf.set(ws);
          }
          else
          if (action == "QTA")
          {
            cf.set(rdoc.quantita().string());
          } else
          if (action == "QTAEVASA")
          {
            cf.set(rdoc.qtaevasa().string());
          } else
          if (action == "RESIDUO")
          {
              cf.set(rdoc.qtaresidua().string());
          } else
          if (action == "VALORE")
          {
            cf.set(rdoc.valore(true, false,AUTO_DECIMALS).string());
          } else
          if (action == "VALRES")
          {
              cf.set(rdoc.valore(true, false, AUTO_DECIMALS).string());
          } else
          if (action == "GIACENZA")
          {          
            real g = ZERO;
            const TString& codart = rdoc.get(RDOC_CODARTMAG);
            if (codart.not_empty() && _art_giac->read(codart) == NOERR)
            {  
              TEsercizi_contabili esc;
              const TDate oggi(TODAY);
              TString16 annoes; annoes.format("%04d", esc.date2esc(oggi));
              const TString16 codmag(rdoc.get("CODMAG")); // Riferito al magazzino indicato sulla riga...
              const TString16 livello(_level > 0 ? rdoc.get(RDOC_LIVELLO) : "");
              g = _art_giac->disponibilita(annoes, codmag, livello, TRUE);  // Giacenza attuale
            }
            cf.set(g.string());
          }
      //Ignore any other command
    return TRUE;
  }
  return TForm::validate(cf, s);
}