#include <stdlib.h>

#include <applicat.h>
#include <utility.h>
#include <prefix.h>
#include <isam.h>
#include <msksheet.h>
#include <urldefid.h>
#include <validate.h>
#include <xvtility.h>

#include "ba1.h"
#include "ba1100.h"


class BA1100_application : public TApplication
{
  TDir_sheet * _browse;
  TMask  * _mask; 
  long    _firm;
  TRec_sheet*     _rec;

protected:
  virtual bool menu (MENU_TAG);
  virtual bool create () ;
  virtual bool destroy();
  void insert_riga(long, TToken_string&);
  void edit_riga(long, TToken_string&);
  void delete_riga();
  virtual bool extended_firm() const { return TRUE; }
  void update();
  void update_dir();
  void convert_dir();
  virtual void print();
  const char* dumpfilename(const FileDes& dep) const;

public:
  BA1100_application() : _browse(NULL), _rec(NULL), _mask(NULL) {}

};

void BA1100_application::print()

{
  if (_rec == NULL) return;
  const char* table[] =  {"", "Alfanumerico", "Intero", "Intero Lungo",
                          "Reale", "Data", "Intero", "Carattere",
                          "Booleano", "Intero Zerofilled", 
                          "Intero Lungo Zerofilled"};
  TPrinter& p = printer();
  TPrintrow row;
  TToken_string s;

  p.open();
  p.headerlen(6);
  p.footerlen(4);
  row.reset();
  row.put(format("Lista tracciato %s (%s)", _rec->dir()->des(),
                 _rec->dir()->name()), 2);
  row.put("Pag. @#", 66);
  p.setheaderline(2, row);
  row.reset();
  row.put("Nome", 7);
  row.put("Tipo", 18);
  row.put("Lunghezza", 45);
  row.put(" Decimali", 55);
  row.put("Posizione", 65);
  p.setheaderline(4, row);
  p.setbackground("l[1,6,75,6]");
  for (int i = 0; i < _rec->rec()->fields(); i ++)
  {
    row.reset();
    s = _rec->rec()->fielddef(i);
    row.put(format("%3d", i + 1), 2);
    row.put(s.get(), 7);
    row.put(table[s.get_int()], 18);
    row.put(format("     %4d", s.get_int()), 45);
    row.put(format("     %4d", s.get_int()), 55);
    row.put(format("     %4d", _rec->rec()->rec()->Fd[i].RecOff), 65);
    p.print(row);
  }  
  p.formfeed();
  row.reset();
  row.put("Espressione chiave", 7);
  row.put("Duplicabile", 68);
  p.setheaderline(4, row);
  for (i = 0; i < _rec->rec()->keys(); i ++)
  {
    row.reset();
    s = _rec->rec()->keydef(i);
    row.put(format("%3d", i + 1), 2);
    row.put(s.get(), 7);
    row.put(*s.get() == 'X' ? "Si" : "No", 68);
    p.print(row);
  }
  p.formfeed();
  p.close();
}

bool BA1100_application::create() // initvar e arrmask

{
  _firm = get_firm();
  
  if (argc() > 2)
  {
    update();
    return FALSE;
  }
  else
  {
    _mask = new TMask ("ba1100a");
    set_firm();
    _browse = new TDir_sheet ("Manutenzione file di sistema") ;  
    _browse->add_button(DLG_INSFILE, "Inserisce", K_F6);
    _browse->add_button(DLG_CONVERT, "Converte", K_F7);
    _browse->add_button(DLG_ADDFILE, "Aggiunge", K_F8);
    dispatch_e_menu(BAR_ITEM(1));
  }  
  return TRUE ;
}

bool BA1100_application::destroy() // releasev e arrmask

{
  if (_firm) set_firm(_firm);
  if (_browse != NULL) delete  _browse;
  if (_mask != NULL) delete  _mask;
  return TRUE ;
}


void BA1100_application::insert_riga (long riga_sel, TToken_string& riga)
{
  const int logicnum = int(riga_sel) + 1;
  const int num_files = (int)_browse->items();
  
  _mask->disable(DLG_PACK);
  _mask->disable(DLG_RECORD);
  _mask->disable(DLG_LOAD);
  _mask->disable(DLG_DUMP);
  _mask->hide(FLD_EXTEND);
  _mask->hide(FLD_EOX);
  _mask->set (FLD_NUM, riga.get(0));
  
  if (_mask->run() == K_ENTER)
  {
    /* shift di uno in avanti degli elementi del direttorio partendo dall'ultimo */
    for (int i=num_files; i>=logicnum; i--)
    {
      _browse->dir()->get (i, _nolock, _nordir, _sysdirop);
      _browse->dir()->put (i + 1, _nordir, _sysdirop);
      _browse->rec()->get (i);
      _browse->rec()->put (i + 1);
    }
    _browse->dir()->set(_mask->get(FLD_NOME), _mask->get_long(FLD_EOD),
                        _mask->get_long(FLD_FLAG), _mask->get (FLD_DESC),
                        _mask->get (FLD_FORMULA));
    _browse->dir()->put(logicnum, _nordir, _sysdirop);
    _browse->rec()->zero();
    _browse->rec()->put(logicnum);
    _browse->dir()->get(LF_DIR);
    _browse->dir()->eod()++;
    _browse->set_items(_browse->dir()->eod());
    _browse->dir()->put(LF_DIR);
  }
}

const char* BA1100_application::dumpfilename(const FileDes& dep) const
{
  TFilename n; n.tempdir();
#if XVT_OS == XVT_OS_SCOUNIX  
  n << '/';
#else  
  n << '\\';
#endif  
  n << dep.SysName;
  n.strip("$%");
  n.ext("txt");
  n.lower();
  
  strcpy(__tmp_string, n);
  return __tmp_string;
}

void BA1100_application::edit_riga (long riga_sel, TToken_string& riga)

{
  KEY  tasto;
  FileDes  dep;
  TDir d;
  const int logicnum = int(riga_sel) + 1;

  _mask->enable(DLG_PACK);
  _mask->enable(DLG_RECORD);
  _mask->enable(DLG_LOAD);
  _mask->enable(DLG_DUMP);
  _mask->set (FLD_NUM, riga.get(0));
  _mask->set (FLD_NOME, riga.get());
  _mask->set (FLD_EOD, riga.get());
  _mask->set (FLD_EOX, riga.get());
  _mask->set (F_LEN, riga.get());
  _mask->set (FLD_DESC, riga.get());
  _mask->set (FLD_FORMULA, riga.get());
  _mask->set (FLD_FLAG, riga.get());
  _mask->reset (FLD_EXTEND);

  const TRecnotype oldeox = atol(_mask->get(FLD_EOX));
  const bool com = strcmp(prefhndl->name(), "com") == 0 || !*prefhndl->name();
  const char* name = _mask->get(FLD_NOME);
  const bool enable_extend = (com ? *name == '%' : *name != '%') && (riga_sel > 0);

  _mask->show(FLD_EXTEND, enable_extend);
  _mask->show(FLD_EOX, enable_extend);
  tasto = _mask->run();

  switch (tasto)
  {
  case K_F4:
  {
    const TFilename filename(_mask->get(FLD_NOME));

    if (logicnum > 1) 
    {
      TEdit_file ef;
      ef.browse(logicnum, filename);
    }
  }    
  break;
 case K_F5:
 case K_F6:
 case K_F7:
 case K_F8:
 case K_ENTER:
{
  strcpy (dep.SysName,_mask->get (FLD_NOME));
  dep.EOD = atol(_mask->get (FLD_EOD));
  dep.Flags = atol(_mask->get (FLD_FLAG));
  strcpy (dep.Des,_mask->get (FLD_DESC));
  strcpy (dep.FCalc,_mask->get (FLD_FORMULA));
  const TRecnotype eox = atol(_mask->get(FLD_EOX));

  _browse->dir()->get(logicnum, _lock, _nordir, _sysdirop);
  _browse->dir()->set(dep.SysName, dep.EOD, dep.Flags,
                      dep.Des, dep.FCalc);
  _browse->dir()->put(logicnum, _nordir, _sysdirop);

{
  TSystemisamfile f(logicnum);

  if (eox != oldeox)
  {
    d.get(logicnum);
    if (!fexist(d.name())) f.build(eox);
    else f.extend(eox);
    _browse->dir()->get(logicnum, _nolock, _nordir, _sysdirop);
  }
  if (tasto == K_F5)
  {
    f.packfile();
    f.packindex();
  }
  else
    if (tasto == K_F6)
    {
      enable_menu_item(M_FILE_PRINT);
      _rec = new TRec_sheet(logicnum);
      _rec->edit();
      delete _rec;
      _rec = NULL;
      disable_menu_item(M_FILE_PRINT);
    }
    else
      if (tasto == K_F7)
      {
        TMask m("ba1100b");
        
        TFilename nout(dumpfilename(dep));
        m.set(FLD_OUTFILE, nout);

        if (m.run() == K_ENTER)
        {
          nout = m.get(FLD_OUTFILE);
          if (nout.not_empty())
          {
            const char fs = *esc(m.get(FLD_FS));
            const char fd = *esc(m.get(FLD_FD));
            const char rs = *esc(m.get(FLD_RS));
            const bool withdel = m.get_bool(FLD_WITHDEL);
            const int keyno = m.get_int(FLD_KEYNO);
            f.dump(nout, keyno, fs, fd, rs, withdel);
          }  
        }
      }
      else
        if (tasto == K_F8)
        {
          TMask m("ba1100c");
          TFilename ninp(dumpfilename(dep));
          m.set(FLD_INFILE, ninp);
          if (m.run() == K_ENTER)
          {
            char fs = *esc(m.get(FLD_FS));
            char fd = *esc(m.get(FLD_FD));
            char rs = *esc(m.get(FLD_RS));
            ninp = m.get(FLD_INFILE);
            f.load(ninp, fs, fd, rs);
          }
        }
}
}
break;
default:
break;
}
}

void BA1100_application::delete_riga ()

{
  _browse->dir()->get(LF_DIR);
  if (_browse->dir()->eod() == 0) return;

  int logicnum = (int)_browse->items();

  _browse->dir()->get(logicnum);
  if (yesnocancel_box("Confermare l'eliminzione dell'archivio %s", _browse->dir()->name()) != K_YES) return;
  _browse->dir()->get(LF_DIR);
  _browse->dir()->eod()--;
  _browse->set_items(_browse->dir()->eod());
  _browse->dir()->put(LF_DIR);

}

void BA1100_application::update_dir()

{
  const TString pref(prefhndl->name());

  prefhndl->set(""); 
  
  TDir d;
  const bool update_com = ( pref == "com");
  d.get(LF_DIR);                 
  const int orig_items = (int)d.eod();
  
  prefhndl->set(pref); 

  d.get(LF_DIR);                 
  const int items = (int)d.eod();

  for (int i = 2; i <= items; i++)
  {              
    prefhndl->set(""); 
    d.get(i, _nolock, _nordir, _sysdirop);                 
    TString desc(d.des());
    TString s(d.name());
    bool towrite = FALSE;

    long flags = d.flags();
    word len = d.len();
    prefhndl->set(pref);
    d.get(i, _nolock, _nordir, _sysdirop); 
    bool to_create = (update_com ? *d.name() == '%' : *d.name() == '$');
    
    if (flags == -1 && len != d.len() && s != d.name())
    {
      d.set(s, d.eox(), 0L, desc, d.expr()); 
      towrite = TRUE;
    }
    else
    {
      towrite = (desc != d.des());
      if (towrite)
        strcpy((char *) d.des(), desc);
    }
    if (towrite)
      d.put(i, _nordir, _sysdirop);                 
    d.get(i);
    TFilename datafile(d.name());

    if (to_create && !fexist(datafile))
    {
      TSystemisamfile f(i);
      f.build(10L);
    }
  }
  prefhndl->set(pref);

  if (items >= orig_items) return;
  
  for (i = items + 1; i <= orig_items; i++)
  {
    prefhndl->set(""); 
    d.get(i, _nolock, _nordir, _sysdirop);                 
    prefhndl->set(pref);
    d.set_len(0); 
    d.flags() = 0L; 
    d.put(i, _nordir, _sysdirop);                 
  }
  prefhndl->set(pref);
  d.get(LF_DIR, _nolock, _nordir, _sysdirop);                 
  d.eod() = orig_items; 
  d.put(LF_DIR, _nordir, _sysdirop);                 
} 

void BA1100_application::convert_dir()

{         
  const TString pref(prefhndl->name());
  TDir d;
  TTrec r;
  
  d.get(LF_DIR);                 
  const int items = (int)d.eod();
  
  for (int i = 2; i <= items; i++)
  {  
    prefhndl->set(""); 
    r.get(i);                 
    prefhndl->set(pref); 
    TSystemisamfile f(i);
    f.update(r);         
  }
  prefhndl->set(""); 
  const long level = prefhndl->filelevel();
  prefhndl->set(pref);
  d.get(LF_DIR, _nolock, _nordir, _sysdirop);                 
  d.flags() = level; 
  d.put(LF_DIR, _nordir, _sysdirop);                 
}

void BA1100_application::update()

{ 
  long firm = get_firm();             
  TString pref;
  if (firm == 0) pref = prefhndl->name();
  
  do_events();
  CURSOR old_cur = get_cursor(TASK_WIN);
  
  set_cursor(TASK_WIN, CURSOR_WAIT);
  prefhndl->set("com");
  update_dir();
  convert_dir();
  
  TIsamfile ditte(LF_NDITTE);
  
  ditte.open();
  
  for (ditte.first(); !ditte.eof(); ditte.next())
  {
    const long codditta = ditte.get_long("CODDITTA");
    const TRecnotype rec = ditte.recno();
    
    if (prefhndl->exist(codditta))
    {
      set_firm(codditta);
      ditte.close();
      update_dir();
      convert_dir();
      ditte.open();
    }
    ditte.readat(rec);
  }
  if (firm > 0) set_firm(firm);
  else prefhndl->set(pref);
  set_cursor(TASK_WIN, old_cur);
}

bool BA1100_application::menu(MENU_TAG m)
{
  TToken_string riga;
  long  riga_selezionata;
  bool  done = FALSE;

  _browse->rebuild();

  while (!done)
  {

    disable_menu_item(M_FILE_NEW);

    switch (_browse->run())
    {
    case K_F6: 
      riga_selezionata = _browse->selected();
      riga = _browse->row();
      insert_riga (riga_selezionata, riga);
      break;
      
    case K_ENTER: 
      riga_selezionata = _browse->selected();
      riga = _browse->row();
      edit_riga (riga_selezionata, riga);
      break;

    case K_DEL: delete_riga(); break;

    case K_ESC: done = TRUE; break;         

    case K_F7: update(); break;
      
    case K_F8:
      _browse->add();
      riga_selezionata = _browse->items() - 1;
      riga = _browse->row(riga_selezionata);
      edit_riga (riga_selezionata, riga);
      break;
      
    default: break;
    } 
    
    enable_menu_item(M_FILE_NEW);
  }
  
  return xvt_test_menu_tag(BAR_ITEM(2));
}

int ba1100(int argc, char** argv)
{
  BA1100_application a;
  a.run(argc, argv, "Gestione files");
  return 0;
}

