#include <checks.h>

#define __TABUTIL_CPP
#include <tabutil.h>

#include <config.h>
#include <extcdecl.h>
#include <scanner.h>
#include <utility.h>

int TTable::name2log(const char* n)
{
  return *n == '%' ? LF_TABCOM : (*n == '#' ? LF_TABGEN : LF_TAB);
}


TTable::TTable(const char* tabname)
: TLocalisamfile(name2log(tabname))
{
  if ((*tabname == '%') || (*tabname == '#')) tabname++;
  _tabname = tabname;
  _tabname.upper();
  curr().settab(_tabname);
  _des_mod_loaded = FALSE;
}

TTable::~TTable()
{}

int TTable::skip(TRecnotype nrec, word lockop)

{
  if (!nrec) return NOERR;
  TBaseisamfile::skip(nrec, lockop);
  if (_tabname != get("COD"))
  {
    if (nrec > 0)
    {
      if (lockop == _lock) 
        TBaseisamfile::reread(_unlock);
      last(lockop);
      setstatus(_iseof);
    }
    else
    {
      if (lockop == _lock) 
        TBaseisamfile::reread(_unlock);
      first(lockop);
      setstatus(_isbof);
    }
  }
  return status();
}


int TTable::_read(TRectype& rec, word op, word lockop)

{
  if (op == _isfirst)
  {
    zero();
    TBaseisamfile::_read(rec, _isgteq, lockop);
    if (_tabname != rec.get("COD"))
      setstatus(_isemptyfile);
    if (bad())
      zero();
  }
  else
    if (op == _islast)
    {
      zero();
      put("CODTAB", "\xFF");
      TBaseisamfile::_read(rec, _isgteq);
      if (!eof())
        TBaseisamfile::_read(rec, _isprev, lockop);
      else
        setstatus(NOERR);
      if (bof())
        setstatus(NOERR);
      if (_tabname != rec.get("COD"))
        setstatus(_isemptyfile);
      if (bad())
        zero();
    }
    else
      if (op == _isprev)
      {
        const TRecnotype nrec = recno();
      
        TBaseisamfile::_read(rec, _isprev, lockop);
        if (_tabname != rec.get("COD"))
        {
          if (lockop == _lock) reread(_unlock);
          readat(rec, nrec, lockop);
          setstatus(_isbof);
        }
      }
      else
      if (op == _isnext)
      {
        const TRecnotype nrec = recno();
      
        TBaseisamfile::_read(rec, _isnext, lockop);
        if (_tabname != rec.get("COD"))
        {
          if (lockop == _lock) reread(_unlock);
          readat(rec, nrec, lockop);
          setstatus(_iseof);
        }
      }
      else
      {
        TBaseisamfile::_read(rec, op, lockop);
        if (_tabname != rec.get("COD"))
        {
          if (lockop == _lock) reread(_unlock);
          last(lockop);
          setstatus(_iseof);
        }             
      }
  return status();
}

int TTable::_readat(TRectype& rec ,TRecnotype nrec, word lockop)
{
  TBaseisamfile::_readat(rec, nrec, lockop);
  CHECKS(_tabname == rec.get("COD"), "Invalid position : Table ", (const char *)_tabname);
  return status();
}

void  TTable::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.
  _des_mod_loaded = TRUE;
  TFilename n;
  n << "recdesc/d" << _tabname;
  n.ext("des");
  n.lower();
  if (n.exist())
  {
    TConfig des(n, "TabDescr");
    _module = des.get("Module");
  }
  n = "??tb";
  n << _tabname;
  n.ext("msk");
  n.lower();

  TString_array f;
  if (list_files(n, f) == 1)
  {
    n = f.row(0);
    if (!n.exist())
      n.overwrite("ba",0);
    if (n.exist())
    {
      if (_module.empty())
      {
        _module = n.left(2);
        _module.lower();
      }
      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);
      }  
    } 
    else
      _module = "ba";
  }
  else
    _module = "ba";
}

const char* TTable::module()
{
  if (!_des_mod_loaded)
    load_module_description();
  return _module;
}

const char* TTable::description()
{
  if (!_des_mod_loaded)
    load_module_description();
  return _description;
}

struct TCallbackTableinfo
{
  TString16 _var1, _var2, _var3;
  TString4 _module;
  TFilename _tabapp, _relapp;
};

HIDDEN int find_relapp(TConfig& cfg, void* jolly)
{
  TCallbackTableinfo& info = *((TCallbackTableinfo*)jolly);
  
  if (cfg.exist(info._var1))
  {
    info._tabapp = cfg.get(info._var1);
    if (info._tabapp.not_empty())
      return 1;
  }
  if (cfg.get_paragraph().compare(info._module, 2, TRUE) == 0)
  {
    if (cfg.exist(info._var2))
    {
      info._relapp = cfg.get(info._var2);
      if (info._relapp.not_empty())
        return 2;
    }
    if (cfg.exist(info._var3))
    {
      info._relapp = cfg.get(info._var3);
      if (info._relapp.not_empty())
        return 3;
    }
  }
  return 0;
}

bool TTable::get_relapp(TString& app) const
{
  TConfig ini("install.ini");
  TCallbackTableinfo fi;
  fi._var1.format("Edit_%s", (const char*)_tabname);
  fi._var2.format("Edit_%d", num());
  fi._var3.format("Edit_%d", num() == LF_TAB ? LF_TABCOM : LF_TAB);
  fi._module = ((TTable*)this)->module();
  ini.for_each_paragraph(find_relapp, &fi);
  
  app = fi._tabapp;
  if (app.empty())
    app = fi._relapp;
  if (app.empty())
  {
    app = "ba3 -0";
    if (fi._module.compare("ba", 2, TRUE) != 0)
    {
      TConfig c(CONFIG_STUDIO, fi._module);
      if (c.exist("TabPrg"))
        app = c.get("TabPrg");
    }
  }
  app << ' ';
  if (num() == LF_TABCOM)
    app << '%';
  app << _tabname;
  return app.not_empty();
}