#include "velib.h"

/////////////////////////////////////////////////////////////
// TCodice_numerazione
/////////////////////////////////////////////////////////////

TCodice_numerazione::TCodice_numerazione(const char* codnum)
                   : TRectype(LF_TABCOM)
{
  settab("NUM");
  if (codnum && *codnum)
    read(codnum);
  else
    setempty(TRUE);  
}

TCodice_numerazione::TCodice_numerazione(const TRectype& rec)
               : TRectype(rec)
{ }

TCodice_numerazione::~TCodice_numerazione()
{ }

const TString& TCodice_numerazione::tipo_doc(int i) const
{
  CHECK(i < 36, "Impossibbile tipo documento"); 
  const char * field = i < 17 ? "S2" : "S3";
  
  if (i >= 17)
    i -= 17;
	TString & tmp = get_tmp_string();
	tmp = get(field).mid(i * 4, 4);
	tmp.trim();
  return tmp;
}                                             

int TCodice_numerazione::ntipi_doc() const
{
  int l = get("S3").len(); 
  if (l > 0)
    return ((l - 1) / 4) + 18;
  l = get("S2").len();
  return l ? (((l - 1) / 4) + 1) : 0;
}

void TCodice_numerazione::complete_num(long num, TString& codnum) const
{
  codnum = prefisso();
  codnum << num;
  codnum << postfisso();
}

int TCodice_numerazione::read(const char* codnum)
{                                   
  *this = cache().get("%NUM", codnum);
  int err = empty() ? _iskeynotfound : NOERR; 
#ifdef DBG  
  if (err != NOERR)
    NFCHECK("Codice numerazione errato: %s", codnum);
#endif    
  return err;  
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//  trova le numerazioni documenti in base ai tipi richiesti (ca3800,ca3900,ps1001)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int numerazioni_documenti(TString_array& num_doc, TString_array& tip_doc, const int tipo)
{
  //cominciamo con i tipi
  TISAM_recordset tipi_recset("USE %TIP\nSELECT STR(I1=#TIPO)");
  tipi_recset.set_var("#TIPO", TVariant(long(tipo)));
  for (bool ok = tipi_recset.move_first(); ok; ok = tipi_recset.move_next())    //giro sui vari tipi ordine
  {
    const TString4 tipo = tipi_recset.get("CODTAB").as_string();
    tip_doc.add(tipo);
  }

  //e adesso cerca le numerazioni che contengono tipi ordine
  TISAM_recordset num_recset("USE %NUM");
  for (bool ok = num_recset.move_first(); ok; ok = num_recset.move_next())    //giro sui vari tipi numerazione
  {
    const TString4 codtab = num_recset.get("CODTAB").as_string();

    const TCodice_numerazione numerazione(codtab);
    for (int t = numerazione.ntipi_doc() - 1; t >= 0; t--)
    {
      const TString& tipo_doc = numerazione.tipo_doc(t);
      if (tip_doc.find(tipo_doc) >= 0)
      {
        if (num_doc.find(codtab) < 0) // Evito aggiunta di doppioni
          num_doc.add(codtab);
        break;
      }
    } //for (int t = codnum..
  } //for (bool ok = num_recset...

  return num_doc.items();
}


int numerazioni_ordini(TString_array& num_ordini, TString_array& tip_ordini)
{
  //i documenti che vanno presi in cosiderazione sono quelli che generano un IMPEGNATO secondo le auree regole del..
  //..nostro invincibile Adolf!
  num_ordini.destroy();
  tip_ordini.destroy();
  
  numerazioni_documenti(num_ordini, tip_ordini, 3);

  return num_ordini.items();
}

int numerazioni_fatture(TString_array& num_fatture, TString_array& tip_fatture)
{
  //i documenti che vanno presi in cosiderazione sono quelli non ancora contabilizzati di tipo 0=Altro 2=Fattura
  num_fatture.destroy();
  tip_fatture.destroy();
  
  numerazioni_documenti(num_fatture, tip_fatture, 0);
  numerazioni_documenti(num_fatture, tip_fatture, 2);

  return num_fatture.items();
}

/////////////////////////////////////////////////////////////
// TSpesa_prest
/////////////////////////////////////////////////////////////

TSpesa_prest::TSpesa_prest(const char* codice, char tipo)
       : TRectype(LF_TAB)
{ 
	switch (tipo)
	{
		case RIGA_SPESEDOC :
			settab("SPP");
			break;
		case RIGA_PRESTAZIONI :
			settab("PRS");
			break;
		case RIGA_RISORSE :
			settab("RSS");
			break;
		case RIGA_ATTREZZATURE :
			settab("ATR");
			break;
		default :
			settab("SPP");
			break;
	}
  if (codice && *codice)
  {
    const int err = read(codice);
#ifdef DBG
    if (err != NOERR)
			switch (tipo)
			{
				case RIGA_SPESEDOC :
				  error_box("Spesa %s assente", codice);
					break;
				case RIGA_PRESTAZIONI :
					error_box("Prestazione %s assente", codice);
					break;
				case RIGA_RISORSE :
				  error_box("Risorsa %s assente", codice);
					break;
				case RIGA_ATTREZZATURE :
				  error_box("Attrezzatura %s assente", codice);
					break;
				default :
				  error_box("Spesa %s assente", codice);
					break;
			}
#endif

  }
}

TSpesa_prest::TSpesa_prest(const TRectype& rec)
      : TRectype(rec)
{
}

char TSpesa_prest::genere() const
{ 
	const TString & tipo = get("COD"); 
	if (tipo == "SPP")
		return RIGA_SPESEDOC;
	else
		if (tipo == "PRS")
			return RIGA_PRESTAZIONI;
	else
		if (tipo == "RSS")
			return RIGA_RISORSE;
		else
			if (tipo == "ATR")
				return  RIGA_ATTREZZATURE;
	return ' ';
}
int TSpesa_prest::read(const char* codice)
{                      
  const TString8 cod = get("COD");
  *this = cache().get(cod, codice);
  return empty() ? _iskeynotfound : NOERR;
}

const TString& TSpesa_prest::cod_iva() const 
{ 
  // La parte seguente di s3 e' utilizzata dalle atrezzature per altri campi
  TString& tmp = get_tmp_string();
  tmp = get("S3").left(4);
  tmp.trim();
  return tmp;
}

real TSpesa_prest::prezzo() const 
{ 
  real r = get("R10");   // Prezzo con tanti decimali
  if (r.is_zero())
    r = get_real("R0");  // Prezzo con pochi decimali
  return r;
}

bool is_real_discount(const TString& exp)
{
  if (exp.blank())
    return  false;

	TString80 good;
	real perc;

	return scontoexpr2perc(exp, false , good, perc) && perc != UNO;
}

bool scontoexpr2perc(const char * exp, bool signal , TString & goodexp, real & val_perc )
{
  bool valid = true;

  goodexp.cut(0);  
  // Elimina gli spazi molesti
//  work.strip_spaces( );
  val_perc = 1.0;
  if (exp && *exp)
  {
    TString80 num;
    bool dec = false;      // Flag che indica se si attende l'inizio di un numero
    bool startnum = true;  // Flag che indica se siamo all'inizio di un numero   
    int errorchar = ' ';
    
    // Flag che indica se sono nella parte decimale di un numero
    for (const char * s  = exp; *s  && errorchar == ' '; s++)
    { 
      const char c = *s;
      switch(c)
      {
      case '+': 
      case '-':
        // Se ero in in numero ...
        if( !startnum )
        {
          // Aggiunge il numero alla sequenza
          real newval( num );
          val_perc *= ( CENTO - newval ) / CENTO;
          goodexp << num;
        }
        // Inizia il nuovo numero
        num = (c == '-') ? "-" : "+";  
        startnum = true;
        dec = false;
        break;         
      case '0':  
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        num << c;
        startnum = false;
        break;
      case '.':
      case ',':
        if(!dec)
        {
          if( startnum )
            num << '0';        // Se occorreva un numero ci metto lo 0
          num << '.';          // Interpreto la virgola come punto
          dec = true;       
          startnum = true;
        }
        else
          errorchar = c;        // Se siamo gi` nella parte decimale segnala un errore
        break;
      case ' ':
        break;
      default:
        errorchar = c;
        break;         
      }
    }
    // Controlla la validita`
    valid = errorchar == ' ';
    
    if (valid)
    {
      // Aggiunge l'ultimo numero preso
      real lastval( num ); 
      val_perc *= ( CENTO - lastval ) / CENTO;
      goodexp << num; // Assegna la nuova espressione formattata bene     
    }
    else
    {
      if (signal)          // Se richiesto segnala l'errore
        warning_box( "Espressione di sconto non valida. Errore sul carattere %c.", errorchar);
      val_perc = UNO;      // Azzera la sequenza di percentuali
      goodexp = "";
    }
  }
  return valid;
}

real prezzo_scontato(const real& prezzo, const TString& sconto)
{    
  if (sconto.full())
  {
    TString80 exp;
    real val_sconto;
    if (scontoexpr2perc(sconto, false , exp, val_sconto) && val_sconto != UNO)
      return prezzo * val_sconto;
  }               
  return prezzo;
}