#include <ctype.h>
#include <stdlib.h>

#include <isam.h>
#include <utility.h>

#include "conto.h"

// Certified 90%
TBill::TBill(TToken_string& s, int from, int mode)
: _tipo_cr(-1), _sezione(' ')
{
  const char* first = s.get(from);
  if (mode & 0x1)
  {
    _tipo = first ? toupper(*first) : ' ';
    first = s.get();
  } else _tipo = ' ';

#ifdef DBG
  if (strchr(" CF", _tipo) == NULL)
  {
    error_box("Tipo conto errato: '%c'", _tipo);
    _tipo = ' ';
  }
#endif

  _gruppo = first ? atoi(first) : 0;
  _conto = s.get_int();
  _sottoconto = s.get_long();
  if (mode & 0x2)
    _descrizione = s.get();
}


const TBill& TBill::copy(const TBill& bill)
{
  _tipo = bill._tipo;
  _gruppo = bill._gruppo;
  _conto = bill._conto;
  _sottoconto = bill._sottoconto;
  _descrizione = bill._descrizione;
  _tipo_cr = bill._tipo_cr;
  _sospeso = bill._sospeso;
  _sezione = bill._sezione;
  return *this;
}


// Certified 100%
const TBill& TBill::set(int g, int c, long s, char t, const char* d, int r)
{
  _tipo = (t > ' ') ? toupper(t) : ' ';
  _gruppo = g;
  _conto = c;
  _sottoconto = s;
  _descrizione = d;
  _tipo_cr = r;
  return *this;
}

const TBill& TBill::add_to(TToken_string& ts, int from, int mode)
{
  if (mode & 0x4) 
  {
    const int cr = tipo_cr();
    if (cr > 0) ts.add(cr, from++); else ts.add(" ", from++);
  }  
  
  if (mode & 0x1) 
    ts.add(_tipo, from++);
  
  if (_gruppo > 0) ts.add(_gruppo, from++); else ts.add(" ", from++);
  if (_conto > 0) ts.add(_conto, from++); else ts.add(" ", from++);
  if (_sottoconto > 0L) ts.add(_sottoconto, from++); else ts.add(" ", from++);
  
  if (mode & 0x2) 
    ts.add(descrizione(), from++);
  
  return *this;  
}


const char* TBill::field_name(int n, bool contro) const
{             
  CHECKD(n >= 0 && n <= 3, "Invalid bill field", n);        

  const char* f;
  if (contro)
    switch(n)
    {
    case 0: f = "GRUPPOC"; break;
          case 1: f = "CONTOC"; break;
          case 2: f = "SOTTOCONTC"; break;
          default:f = "TIPOCC"; break;
          }
  else
    switch(n)
    {
    case 0: f = "GRUPPO"; break;
          case 1: f = "CONTO"; break;
          case 2: f = "SOTTOCONTO"; break;
          default:f = "TIPOC"; break;
          }
  return f;
}

void TBill::put(TRectype& r, bool c) const
{  
  r.put(field_name(0, c), gruppo());
  r.put(field_name(1, c), conto());
  r.put(field_name(2, c), sottoconto());
  r.put(field_name(3, c), tipo());
}

bool TBill::get(const TRectype& r, bool c)
{ 
  set(r.get_int(field_name(0, c)), 
      r.get_int(field_name(1, c)),
      r.get_long(field_name(2, c)), 
      r.get_char(field_name(3, c)));
  
  if (r.num() == LF_RMOVIVA)      
    tipo_cr(r.get_int("TIPOCR"));
  
  return ok();
}


// Certified 100%
bool TBill::ok() const
{
  return _gruppo != 0 && _conto != 0 && _sottoconto != 0L;
}

// Certified 99%
int TBill::compare(const TSortable& s) const
{
  CHECK(class_name()==s.class_name(), "Can't compare TBill with TObject");
  const TBill& c = (const TBill&)s;

  int res = _gruppo - c._gruppo;
  if (res) return res;

  res = _conto - c._conto;
  if (res) return res;

  const long lres = _sottoconto - c._sottoconto;
  if (lres < 0L) res = -1; else
    if (lres > 0L) res = +1;

  return res;
}


// Certified 95%
bool TBill::find()
{   
  bool ok = FALSE;

  if ((_tipo != 'C' && _tipo != 'F') || _sottoconto == 0L)
  {                 
    TRectype pcon(LF_PCON);
    ok = read(pcon);
  } 
  else
    if ((_tipo == 'C' || _tipo == 'F') && _sottoconto != 0L)
    {
      TLocalisamfile clifo(LF_CLIFO, FALSE);
      clifo.setkey(1);
      clifo.put("TIPOCF", _tipo);
      clifo.put("CODCF", _sottoconto);
      ok = clifo.read() == NOERR;
      if (ok)
      {        
        _descrizione = clifo.get("RAGSOC");
        if (_tipo_cr < 0) 
        {
          _tipo_cr = 0;
          _sezione = ' ';
        }  
        _sospeso = clifo.get_bool("SOSPESO"); 
        
        const char tipoa = clifo.get_char("TIPOAPER");
        if (tipoa == 'F')
        {
          TString nome(_descrizione.mid(30));
          if (nome.not_empty())
          {
            _descrizione.cut(30);
            _descrizione.trim(); nome.trim();
            _descrizione << ' ' << nome;
          }  
        }
        if (_gruppo == 0 || _conto == 0)
        {
          _gruppo = clifo.get_int("GRUPPO");
          _conto = clifo.get_int("CONTO");
        }
      }  
    }
  
  return ok;
}


bool TBill::read(TRectype &r)
{
  TLocalisamfile pcon(LF_PCON, FALSE);
  pcon.setkey(1);
  pcon.put("GRUPPO", _gruppo);
  pcon.put("CONTO", _conto);
  pcon.put("SOTTOCONTO", _sottoconto);

  const int err = pcon.read();
  if (err == NOERR)
  {
    r = pcon.curr();
    _tipo_cr = r.get_int("TIPOSPRIC");    
    _sezione = r.get_char("SEZSALDI");
    _descrizione = r.get("DESCR");
    _sospeso     = r.get_bool("SOSPESO"); 
  }  
  else
    r.zero();  
  
  return err == NOERR;
}

int TBill::tipo_att()
{
  int tipo_att = 1;
  if (tipo() <= ' ' && ok())               
  { 
    TBill bill(gruppo(), conto());
    TRectype rec(LF_PCON); bill.read(rec);
    const TIndbil ib = (TIndbil)rec.get_int("INDBIL");
    if (ib == ib_passivita || ib == ib_ricavi)
    {
      read(rec);
      const int ricser = rec.get_int("RICSER");  // 0 = Altre attivita  1 = Servizi
      tipo_att = (ricser == 1) ? 1 : 2;
    }
  }                      
  return tipo_att;
}  

// Certified 99%
const TString& TBill::descrizione()
{                         
  if (_descrizione.empty() && !empty())
  {
    if (!find())
      _descrizione = "Sconosciuto";
  }
  return _descrizione;
}

int TBill::tipo_cr()
{
  if (_tipo_cr < 0) 
    find();
  return _tipo_cr;
}


// Certified 99% (uses __tmp_string)
const char* TBill::string(int mode)
{
  TFixed_string s(&__tmp_string[256], 80);
  s.cut(0);
  
  if (mode & 0x4)
  {
    const int cr = tipo_cr();
    if (cr > 0) s << cr << '|';
    else s << " |";
  }  
  
  if (mode & 0x1)
    s << _tipo << '|';
  
  if (_gruppo > 0) s << _gruppo  << '|';
  else s << " |";
  
  if (_conto > 0) s << _conto  << '|';
  else s << " |";
  
  if (_sottoconto > 0L) s << _sottoconto;
  else s << ' ';
  
  if (mode & 0x2) 
    s << '|' << descrizione();

  return s;
}


