#include <applicat.h>
#include <expr.h>
#include <isam.h>
#include <msksheet.h>
#include <progind.h>
#include <statbar.h>
#include <urldefid.h>
#include <utility.h>

#include "ba1100.h"

TMask* TRec_sheet::_mask = NULL;

void TDir_sheet::add()
{
  _dir->get(LF_DIR, _lock, _nordir, _sysdirop);
  const int nitems = (int)_dir->eod() + 1;

  _dir->eod() = nitems;   
  if (_dir->eox() < _dir->eod())
    _dir->eox() += 10;
  _dir->put(LF_DIR, _nordir, _sysdirop);  
  TDir d;
  
  d.zero();
  d.put(nitems, _nordir, _sysdirop);
  _items = nitems;
}

TDir_sheet::TDir_sheet(const char* title, bool superprassi, const char* colonne)
          : TSheet(0, 0, 0, 0, title, colonne, superprassi ? 0xC : 0x8)
{
  add_button(DLG_PRINT, TR("Tracciati"), K_F3, BMP_PRINT);
  add_button(-1, "", 0, 1); // Separatore

  if (superprassi)
  {
    add_button(DLG_OTHERFILE, TR("File Esterni"), K_F5, 113);
    add_button(DLG_CONVERT, TR("Conversione"), K_F7, 156);
	  if (is_power_station())
      add_button(DLG_ADDFILE, TR("Nuovo file"), K_F8, BMP_NEWREC);
    add_button(-1, "", 0, 1); // Separatore
  }

  add_button(DLG_INFO, TR("Info"), K_F2, BMP_INFO);
  add_button(DLG_HELP, TR("Help"), K_F1, BMP_HELP);
  xvt_toolbar_set_last_tool(toolbar(), DLG_QUIT);

  _dir = new TDir;
  _rec = new TTrec;
  rebuild();
}

TDir_sheet::~TDir_sheet()
{
  delete _dir;
  delete _rec;
}

void TDir_sheet::get_row(long n, TToken_string& l)
{
  n++;
  _dir->get ((int)n,_nolock,_nordir,_sysdirop);
  l.format("%d", n); // Numero progressivo del file
  l.add(_dir->name());
  l.add(_dir->eod());
  l.add(_dir->eox());
  l.add((long)_dir->len());
  l.add(_dir->des());
  l.add(_dir->expr());
  l.add(_dir->flags());
}


TRec_sheet::TRec_sheet(int logicnum, const char * tab)
          : _descr(NULL), _tab(tab)
{
  _external = FALSE;
  _dir = new TDir;
  _rec = new TTrec;
  _rec_old = new TTrec;
  _mask = new TMask("ba1100d");

  _dir->get(logicnum, _lock, _nordir, _sysdirop);
  _rec->get(logicnum);
  if (_dir->len() == 0)
   _rec->zero();
  *_rec_old = *_rec;
  _tab.lower();
  if (fexist(DESCDIR))
  {
    if (logicnum >= LF_TABGEN && logicnum <= LF_TAB && _tab.not_empty())
      _descfname.format("%s/d%s.des", DESCDIR, (const char *) _tab);
    else
      _descfname.format("%s/d%d.des", DESCDIR, _dir->num());
    FILE * fd = NULL;

    if (!fexist(_descfname) && (fd = fopen(_descfname, "w")) == NULL)
      error_box(TR("Impossibile creare il file delle descrizioni"));
    else
    {
      if (fd != NULL)
        fclose(fd);
      _descr = new TConfig(_descfname, DESCPAR);
    }
  }
}

TRec_sheet::TRec_sheet(TExternisamfile* file)
          : _descr(NULL), _tab("")
{
  _external = TRUE;
  _dir = new TDir;
  _rec = new TTrec;
  _rec_old = new TTrec;
  _mask = new TMask("ba1100d");

  const FileDes& d = prefix().get_filedes(file->num());
  const RecDes& r = prefix().get_recdes(file->num());
  memcpy(_dir->filedesc(),&d,sizeof(FileDes));
  memcpy(_rec->rec(),&r,sizeof(RecDes));
  if (_dir->len() == 0)
   _rec->zero();
  *_rec_old = *_rec;
}

TRec_sheet::~TRec_sheet()
{
  if (!_external)
    _dir->get(_dir->num(), _unlock, _nordir, _sysdirop);
  delete _dir;
  delete _rec;
  delete _rec_old;
  delete _mask;
  _mask = NULL;
  if (_descr)
    delete _descr;
}

bool TRec_sheet::check_key_expr(int key, const char * key_expr)
{
  TExpression expr("", _strexpr);
  return expr.set(key_expr, _strexpr);
}

HIDDEN bool len_handler(TMask_field& f, KEY key)
{
  const int len = atoi(f.get());
  if (len < 0) 
    return false;

  const int typef = atoi(f.mask().get(FLD_TIPO));
  switch (typef)
  {
  case _alfafld: 
    return len <= 254;
  case _intfld: 
    return len <= 5;
  case _longfld: 
    return len <= 10;
  case _realfld:  
    return len <= 18;
  case _wordfld:  
    return len <= 5;
  case _intzerofld:  
    return len <= 5;
  case _longzerofld:  
    return len <= 10;
  default: 
    return TRUE;
  }
  return TRUE;
}

bool TRec_sheet::fld_notify(TSheet_field& f, int r, KEY k)
{
  if (k == K_CTRL + K_INS)
  {                 
    TToken_string & row = f.row(r);  
    row.add(1, f.cid2index(FLD_TIPO));       
  }    
  return TRUE;
}

bool TRec_sheet::key_notify(TSheet_field& f, int r, KEY k)
{
  if (k == K_INS)
  {                   
    const int items = f.items();
    if (items >= 8) return FALSE;
  }    
  else
    if (k == K_CTRL + K_INS)
      f.enable_cell(r, 1, r > 0); 
  return TRUE;
}

void TRec_sheet::save_desc()
{
  if (_descr)
  {
    TSheet_field& f1 = (TSheet_field&) _mask->field(F_FIELDS);
    const int nfields = f1.items();

    for (int i = 0; i < nfields; i++)
      _descr->set(_rec->rec()->Fd[i].Name, f1.row(i).items() > 4 ?
                                           f1.row(i).get(-2) : "");
    delete _descr;
    _descr = new TConfig(_descfname, DESCPAR);
  }
}

void TRec_sheet::save()

{
  if ((*_rec == *_rec_old && !_descr) ||
      !yesnocancel_box(TR("Salvare le modifiche"))) return;
      
  if (prefix().name()[0])    // Non fare conversioni sui dati standard
  {
    TSystemisamfile f(_rec->num());
    f.update(*_rec, true);
  }

  save_desc();  
  *_rec_old = *_rec;
  // modifica del 16-1-98, Augusto :
  // Il bottone "salva" salva anche il trr e dir in recdesc
      
  TFilename nf;
  nf << "recdesc\\f" << _dir->num();
  nf.ext("trr");
  {
    _rec->set_des(_descr,_tab.upper());
    ofstream out(nf);
    out << *_rec;
    _rec->set_des();
  }
  
  nf.ext("dir");
  ofstream out(nf);
  out << *_dir;
}

void TRec_sheet::edit()
{
  bool import_dirty = FALSE;
  TSheet_field& f1 = (TSheet_field&) _mask->field(F_FIELDS);
  TSheet_field& f2 = (TSheet_field&) _mask->field(F_KEYS);
  
  if (!_external)
  {
    _mask->set (F_NUM, _dir->num());
    _mask->set (F_DES, _dir->des());
  }
  else
    _mask->disable(-1);
  f1.sheet_mask().field(FLD_LEN).set_handler(len_handler);
  f1.set_notify(fld_notify);
  f1.set_append(FALSE);
  int nfields = _rec->fields();

  f1.enable_column(FLD_DES - 101, _descr != NULL);
  
  int i;
  
  for (i = 0; i < nfields; i++)
  {
    f1.row(i) = _rec->fielddef(i);
    if (_descr)
      f1.row(i).add(_descr->get(_rec->rec()->Fd[i].Name));
    else
      f1.row(i).add(""); 
    const TFieldtypes type = (TFieldtypes) f1.row(i).get_int(1);
    switch (type)
    {
      case _datefld : 
      case _wordfld : 
      case _charfld :  
      case _boolfld :  
      case _memofld:  
        f1.disable_cell(i, 2);
      case _alfafld :
      case _intfld  : 
      case _longfld :  
      case _intzerofld :
      case _longzerofld:
        f1.disable_cell(i, 3);
      default:
        break;
     }
  }                          
  f2.set_notify(key_notify);
  f2.set_append(FALSE);
  int nkeys = _rec->keys();
  for (i = 0; i < nkeys; i++) f2.row(i) = _rec->keydef(i);
  f2.disable_cell(0, 1);
  while (TRUE)
  {
    f1.force_update(0); // Non togliere, serve per fare l'update della descrizione quando si fa l'import!!
    switch (_mask->run())
    {
    case K_SAVE:
    {
      nfields = f1.items();   
      int nf = 0;
      for (i = 0; i < nfields; i++)
      {
        TToken_string s(f1.row(i));
        
        if (s.items() > 4)
          s.destroy(-2);     
        if (s.items() > 0)
          _rec->update_fielddef(nf++, s);
      }
      _rec->set_fields(nf);
      _rec->rehash();
      nkeys = f2.items();
      _rec->set_keys(nkeys);
      for (i = 0; i < nkeys; i++)
      {
        TToken_string& s = f2.row(i);
        _rec->update_keydef(i, s);
      }    
      _dir->set_len(_rec->len());
      save();
      return;
    }
  case K_ESC:
    if (_descr && (_mask->dirty() || import_dirty))
    {
      // Se viene premuto Annulla NON deve salvare le descrizioni! Altrimenti che annulla e'?
      // Salva il vecchio file di descrizione con un altro nome...
      if (!import_dirty)
        fcopy(_descfname,"des.xxx");
      // libera _descr (scrivendo il file)
      delete _descr;
      _descr = NULL;
      // Ripristina il vecchio file e rimuove il file temporaneo
      fcopy("des.xxx",_descfname);
    }
    remove("des.xxx");
    return;
  case K_ENTER:
    main_app().print();
    break;
  case K_F6:
  {
    TMask m("ba1100f");
    TFilename nf;
    nf << 'f' << _dir->num();
    nf.ext("trr");
    m.set(F_NOMEF, nf);  
    if (m.run() == K_ENTER)
    {
      nf = m.get(F_NOMEF);
      if (nf.not_empty())
      {
        save_desc();
        {
          _rec->set_des(_descr,_tab.upper());
          ofstream out(nf);
          out << *_rec;
          _rec->set_des();
        }
        nf.ext("dir");
        ofstream out(nf);
        out << *_dir;
      }
    }
  }
    break;
  case K_F7:
  {
    TMask m("ba1100f");
    TFilename nout(_dir->name());

    nout.strip("$%");
    nout.ext("trr");
    m.set(F_NOMEF, nout);  
    if (m.run() == K_ENTER)
    {
      const TFilename nf(m.get(F_NOMEF));
      if (nf.not_empty())
      {
        import_dirty = TRUE;
        _rec->set_des(_descr,_tab.upper());
        ifstream in(nf);
        in >> *_rec;
        nfields = _rec->fields(); 
        fcopy(_descfname,"des.xxx"); // salva il vecchio file di descrizioni
        f1.destroy(-1);
        
        for (int i = 0; i < nfields; i++)
        { 
          f1.row(i) = _rec->fielddef(i);
          if (_descr)
            f1.row(i).add(_descr->get(_rec->rec()->Fd[i].Name));
          else
            f1.row(i).add(""); 
          const TFieldtypes type = (TFieldtypes) f1.row(i).get_int(1);
          switch (type)
          {
            case _datefld : 
            case _wordfld : 
            case _charfld :  
            case _boolfld :  
            case _memofld:  
              f1.disable_cell(i, 2);
            case _alfafld :
            case _intfld  : 
            case _longfld :  
            case _intzerofld :
            case _longzerofld:
              f1.disable_cell(i, 3);
            default:
            break;
          }
        }
        nkeys = _rec->keys();
        f2.reset();
        for (int i = 0; i < nkeys; i++) 
          f2.row(i) = _rec->keydef(i);
        f2.disable_cell(0, 1);
      }
    }
  }
    break;
  default: break;
  }
  }
}