#include <applicat.h>
#include <scanner.h>
#include <tabmod.h>

TModule_table::TModule_table(const char* tabname)
             : TLocalisamfile(LF_TABMOD), _customer(0)
{
	TString8 name(tabname);
  if (!isalnum(name[0])) // Toglie eventuali prefissi inutili d'ora in poi
    name.ltrim(1); 
	name.upper();

  if (name.len() >= 5)
  {
    _module = name.left(2);
    name.ltrim(2);
    if (name.len() > 3)
    {
      _customer = atol(name);
      _tabname = name.right(3);
    }
		else
			_tabname = name;
  }
	else _tabname = name;

	if (_module.blank() || _customer <= 0L)
  {
    TFilename app = main_app().argv(0); app.ext("");
	  const TFixed_string appname(app.name());

	  if (_module.blank())
		  _module = appname.left(2);

    if (_customer <= 0L && real::is_natural(appname.mid(3)))
		  _customer = atol(app.mid(2));
  }
  _module.upper();
}

void TModule_table::zero_rec(TRectype& rec, char c)
{
	rec.zero(c);
	rec.put("MOD", _module);
	rec.put("CUST", _customer);
	rec.put("COD", _tabname);
}

// @cmember Vuota tutto il record
void TModule_table::zero()
{
	zero_rec(curr(), '\0');
}

// @cmember Vuota tutto il record usando il carattere <p c>
void TModule_table::zero(char c)
{
	zero_rec(curr(), c);
}

bool TModule_table::in_table() const
{
	const TRectype& rec = curr();
	return _tabname == rec.get("COD") && _module == rec.get("MOD") && _customer == rec.get_long("CUST");
}

int TModule_table::skip(TRecnotype nrec, word lockop)
{
  if (nrec == 0) 
    return NOERR;
  int err = TBaseisamfile::skip(nrec, lockop);
  if (err == NOERR && not_in_table())
  {
    if (lockop == _lock || lockop == _testandlock) 
      TBaseisamfile::reread(_unlock);
    if (nrec > 0)
    {
      last(lockop);
      setstatus(err = _iseof);
    }
    else
    {
      first(lockop);
      setstatus(err = _isbof);
    }
  }
  return err;
}

int TModule_table::_read(TRectype& rec, word op, word lockop)
{
  switch (op)
  {
  case _isfirst:
    {
      zero_rec(rec, '\0');
      TBaseisamfile::_read(rec, _isgteq, lockop);
  		
	    if (not_in_table())
        setstatus(_isemptyfile);
      if (bad())
        zero_rec(rec, '\0');
    }
    break;
  case _islast:
    {
      zero_rec(rec, '\0');
      put("CODTAB", "\xFF");
      TBaseisamfile::_read(rec, _isgteq);
      if (!eof())
        TBaseisamfile::_read(rec, _isprev, lockop);
      else
        setstatus(NOERR);
      if (bof())
        setstatus(NOERR);
		  if (not_in_table())
        setstatus(_isemptyfile);
      if (bad())
        zero_rec(rec, '\0');
    }
    break;
  case _isprev:
    {
      const TRecnotype nrec = recno();
      TBaseisamfile::_read(rec, _isprev, lockop);
		  if (not_in_table())
      {
        if (lockop == _lock || lockop == _testandlock) 
          reread(_unlock);
        readat(rec, nrec, lockop);
        setstatus(_isbof);
      }
    }
    break;
  case _isnext:
    {
      const TRecnotype nrec = recno();
      TBaseisamfile::_read(rec, _isnext, lockop);
		  if (not_in_table())
      {
        if (lockop == _lock || lockop == _testandlock) 
          reread(_unlock);
        readat(rec, nrec, lockop);
        setstatus(_iseof);
      }
    }
    break;
  default: // read normale
    {
			rec.put("COD", _tabname);
			rec.put("MOD", _module);
			rec.put("CUST", _customer);
			TBaseisamfile::_read(rec, op, lockop);
		  if (not_in_table())
      {
        if (lockop == _lock || lockop == _testandlock) 
          reread(_unlock);
        last(lockop);
        setstatus(_iseof);
      }             
    }
    break;
  }
  return status();
}

int TModule_table::_readat(TRectype& rec ,TRecnotype nrec, word lockop)
{
  TBaseisamfile::_readat(rec, nrec, lockop);
  CHECKS(in_table(), "Invalid module table position in ", (const char *)_tabname);
  return status();
}

int TModule_table::_write(const TRectype& rec)
{
	((TRectype &)rec).put("COD", _tabname);
	((TRectype &)rec).put("MOD", _module);
	((TRectype &)rec).put("CUST", _customer);

	return TLocalisamfile::_write(rec);
}

int TModule_table::_rewrite(const TRectype& rec)
{
	((TRectype &)rec).put("COD", _tabname);
	((TRectype &)rec).put("MOD", _module);
	((TRectype &)rec).put("CUST", _customer);

	return TLocalisamfile::_rewrite(rec);
}

bool TModule_table::empty()
{ 
  return read(_isfirst) != NOERR;
}

void  TModule_table::load_module_description()
{
  // Setta il modulo al quale appartiene la tabella e la relativa descrizione.
  // Cerca prima in RECDESC il relativo file di descrizione: D<TAB_NAME>.DES
  // Se il file esiste, se il paragrafo [TabDescr] esiste e se esiste la
  // variabile Module ne prende il valore.
  // Se non si verificano le suddette condizioni procede come segue:
  // cerca se esiste il file ??<TAB_NAME>.MSK tramite la funzione list_files(),
  // ne estrae il module dai primi 2 caratteri e la descrizione dalla intestazione
  // della prima pagina.
  TFilename n;
  n = _module;
  if (_customer > 0)
  {
    TString8 c;
    c.format("%06ld", _customer);
    n << c;
  }
  n << "tb" << _tabname;
  n.ext("msk");

  if (n.custom_path())
  {
    TScanner m(n);
    bool ok = true;
    while (ok) 
    {
      const TString& l2 = m.line().left(2);
      if (l2.empty())
        ok = false; 
      else
        if (l2 == "PA")
          break;  
    }  
    if (ok)
    {
      const int apicia = m.token().find('"')+1;
      const int apicic = m.token().find('"', apicia);
      _description = m.token().sub(apicia, apicic);
    }  
  }
  if (_description.blank())
  {
    _description = TR("Tabella");
    _description << ' ' << _tabname << ' ' << TR("Modulo") << ' ' << _module;
    if (_customer > 0)
      _description << _customer;
  }
}

const char* TModule_table::module() const
{ return _module; }

long TModule_table::customer() const
{ return _customer; }

const char* TModule_table::description()
{
  if (_description.empty())
    load_module_description();
  return _description;
}
static bool find_relapp(TString& app, const char * para, const char * tabname)
{
	TString8 var;
	var << "Edit_" << tabname;

	app = ini_get_string(CONFIG_GENERAL, para, var);
	if (app.empty())
	{
		var.cut(0) << "Edit_" << LF_TABMOD;
		app = ini_get_string(CONFIG_GENERAL, para, var);
	}
	return app.full();
}

bool TModule_table::get_relapp(TString& app) const
{
  TString8 para = _module;

  if (_customer > 0L)
    para.format("%s%06ld", (const char*)_module, _customer);
	para.lower();

	bool ok = ::find_relapp(app, para, _tabname);

	for (int i = 0; !ok && i <= 9; i++)
	{
		para = _module;
		para << i;
		ok = ::find_relapp(app, para, _tabname);
	}
	if (!ok)
		app << _module << "0 -0";
	app << " &" << _tabname;
  return true;
}