#include <extcdecl.h>

#include <applicat.h>
#include <automask.h>
#include <colors.h>
#include <filetext.h>
#include <prefix.h>
#include <relation.h>
#include <sheet.h>
#include <utility.h>

#include "ba1800.h"

///////////////////////////////////////////////////////////
// Utilities
///////////////////////////////////////////////////////////

HIDDEN int get_isamfiles()
{
  FileDes dir;
  CGetFile(LF_DIR, &dir, _nolock, NORDIR);
  return (int)dir.EOD;
}

HIDDEN int str2isamfile(const TString& str)
{
  int logic_num = 0;
  if (!str.blank())
  {                                          
    const int logic = atoi(str);
    if (logic > 0)
    {              
      if (logic > LF_DIR && logic < LF_EXTERNAL)
      {
        if (logic < get_isamfiles())
        {
          TBaseisamfile file(logic);
          if (file.is_valid(FALSE) == NOERR)
            logic_num = logic;
        }  
      }
    }  
    else
    {
      const int len = str.len();
      if (len == 3 || (str[0] == '%' && len == 4))
      {
        const int first = len == 3 ? 0 : 1;
        if (isalpha(str[first]) && isalnum(str[first+1]) && isalnum(str[first+2]))
          logic_num = str[0] == '%' ? LF_TABCOM : LF_TAB;
      }
    }  
  }
  return logic_num;
}

HIDDEN int choose_isamfile(int selected)
{
  TArray_sheet sht(-1,-1,-4,-4,TR("Selezione archivio"), HR("Codice|Descrizione archivio@70"));
  TToken_string tt(80);
  
  long sel = 0;
  
  const int nfiles = get_isamfiles();
  for (int logic = LF_TABCOM; logic < nfiles; logic++)
  {     
    if (logic == selected)
      sel = sht.items();
    const TFixed_string desc = prefix().description(logic);
    if (desc.full() && desc.compare("File non presente", -1, true) != 0)
    {
      tt.format("%d", logic);
      tt.add(desc);
      sht.add(tt);
    }  
  }
  
  sht.select(sel);
  if (sht.run() == K_ENTER)
  {
    sel = sht.selected();
    selected = sht.row(sel).get_int(0);
  }
  else
    selected = 0;  
  return selected;
}

///////////////////////////////////////////////////////////
// TColumnizer_win & TColumnizer_field
///////////////////////////////////////////////////////////

class TColumnizer_field;

class TColumnizer_win : public TField_window
{ 
  enum { RULER_HEIGHT = 2, NUM_WIDTH = 5 };

  TString_array _rows;        // Righe di testo da stampare
  TPointer_array _column;     // Array delle posizioni di inizio campo
  bool _clickable;            // E' possibile cliccare

protected: // TScroll_window
  virtual void handler(WINDOW win, EVENT* ep);
  virtual void update();

protected: // Internal use
  int on_column(long col);                                            

public:
  void recalc_layout(int dx, int dy);

  bool clickable() const { return _clickable; }
  void set_clickable(bool on = TRUE) { _clickable = on; }
  
  void destroy_rows() { _rows.destroy(); }
  void add_row(const char* row) { _rows.add(row); }
  
  void destroy_columns() { _column.destroy(); }
  long add_column(long col) { return _column.add_long(col); }
  long get_column(int index) const { return _column.get_long(index); }

  TColumnizer_win(int x, int y, int dx, int dy, WINDOW parent, TColumnizer_field* field);
  virtual ~TColumnizer_win() { }
};

class TColumnizer_field : public TWindowed_field
{   
protected: // TWindowed_field
  virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent)
  { return new TColumnizer_win(x, y, dx, dy, parent, this); }

protected: // Internal use
  TColumnizer_win& col_win() const 
  { return (TColumnizer_win&)win(); }
  
public:
  void destroy_rows() { col_win().destroy_rows(); }
  void add_row(const char* row) { col_win().add_row(row); }
  void recalc_layout(int dx, int dy) const { col_win().recalc_layout(dx, dy); }
  int visible_rows() const { return col_win().rows() - 1; }
  
  void destroy_columns() { col_win().destroy_columns(); }
  void add_column(long col) { col_win().add_column(col); }
  long get_column(int index) const { return col_win().get_column(index); }

  TColumnizer_field(TMask* m) : TWindowed_field(m) { }
  virtual ~TColumnizer_field() { }
};

int TColumnizer_win::on_column(long col)
{  
  int index = -1;            
  if (col > 0)
  {              
    int action = 1;  // 1 = Add, 2 = Remove
    int i;
    for (i = _column.items()-1; i >= 0; i--)
    {
      const long cur_col = _column.get_long(i);
      if (cur_col == col)
      {
        action = 2;
        break;
      }  
      if (cur_col < col)
      {
        action = 1;
        break;
      }
    }
    
    TSheet_field& sf = owner().mask().sfield(F_FIELDS);
    switch(action)
    {
    case 1:
      index = _column.insert_long(col, i+1);
      break;
    case 2:
      _column.destroy(i, TRUE);
      index = i;
      break;
    default:
      break;
    }  
  }    
  return index;
}

void TColumnizer_win::update()
{
  const int x = int(origin().x);  
  const int maxx = x + columns() + 1;
  const int y = int(origin().y);  
  const int maxy = y + rows() + 1;
  int i;
  TString80 str; 

  TField_window::update();

  set_color(NORMAL_COLOR, NORMAL_BACK_COLOR);
  for (i = y; i < maxy-RULER_HEIGHT; i++)
  {
    TToken_string* row = (TToken_string*)_rows.objptr(i);
    if (row)
      stringat(NUM_WIDTH, i+RULER_HEIGHT, _rows.row(i));
    else
      break;  
  }  
  
  set_brush(DISABLED_BACK_COLOR);

  bar(x, y, maxx, y+RULER_HEIGHT);
  TString points(maxx); 
  points.fill('.');
  for (int n = x+1; n < maxx; n++) 
  {
    if ((n % 5) == 0)
    {
      if ((n & 0x1) == 0)
      {
        str.format("%d", n);
        points.overwrite(str, n - str.len());
      }
      else
        points.overwrite(":", n-1);
    }
  }  
  stringat(NUM_WIDTH, y, points);
  
  bar(x, y, x+NUM_WIDTH, maxy);
  for (i = y; i < maxy; i++)
  {         
    str.format("%*d", NUM_WIDTH, i+1);
    stringat(x, i+RULER_HEIGHT, str);
  }  

  set_pen(COLOR_BLACK);
  
  int last_column = 0;
  for (i = 0; i < _column.items(); i++)
  {
    const int j = (int)_column.get_long(i);
    if (j > x)  
    {
      _pixmap = TRUE;                
      line((j+NUM_WIDTH)*CHARX, (y+1)*CHARY, (j+NUM_WIDTH)*CHARX, maxy*CHARY);
      _pixmap = FALSE;
    }               
    
    const int available = j-last_column;
    str.format("%d(%d)", i+1, available);
    int len = str.len();
    if (len > available)
    {
      len = str.find('(');
      str.cut(len);
    }
    if (len <= available)
    {                   
      int cx = (j+last_column-len) / 2;
      if (cx >= x)
        stringat(cx+NUM_WIDTH, y+1, str);
    }      

    last_column = j;
  }
  
  _pixmap = TRUE;                
  line((x+NUM_WIDTH)*CHARX, (y+1)*CHARY, maxx*CHARX, (y+1)*CHARY);
  line(x*CHARX, (y+RULER_HEIGHT)*CHARY, maxx*CHARX, (y+RULER_HEIGHT)*CHARY);
  line((x+NUM_WIDTH)*CHARX, y*CHARY, (x+NUM_WIDTH)*CHARX, maxy*CHARY);
  _pixmap = FALSE;
}

void TColumnizer_win::handler(WINDOW win, EVENT* ep)
{             
  switch(ep->type)  
  {
  case E_MOUSE_DOWN:
    if (_clickable)
    {
      long column = (ep->v.mouse.where.h + CHARX/2) / CHARX;
      column += origin().x - NUM_WIDTH;
      if (on_column(column) >= 0)
        force_update();
    }  
    break;
  default:
    TField_window::handler(win, ep);
    break;
  }
}

void TColumnizer_win::recalc_layout(int dx, int dy)
{            
  long maxy = _rows.items() - rows()/2 + 1;
  long maxx = dx;
  if (maxx <= 0)
    maxx = _column.get_long(_column.items()-1) + 384;
  maxx -= columns()/2 + NUM_WIDTH;
  if (maxx < 0) maxx = 0;
  if (maxy < 0) maxy = 0;
  set_scroll_max(maxx, maxy);
  update_thumb(0, 0);
  force_update();
}

TColumnizer_win::TColumnizer_win(int x, int y, int dx, int dy, 
                                 WINDOW parent, TColumnizer_field* field) 
               : TField_window(x, y, dx, dy, parent, field), 
                 _clickable(field->enabled())
{ 
  set_scroll_max(columns(), rows());
}

///////////////////////////////////////////////////////////
// TWizard_mask
///////////////////////////////////////////////////////////

class TWizard_mask : public TAutomask
{        
  TRelation* _rel;
  TRelation_description* _reldesc;

  bool _frozen;

protected:  // TMask
  virtual TMask_field* parse_field(TScanner& scanner);

protected: // TAutomask
  virtual bool on_field_event(TOperable_field& f, TField_event e, long jolly);

protected: // Internal use only
  bool file_open(TFilename& name) const;
  void load_ini(const TString& ininame);
  void save_ini(const TFilename& ininame) const;
  bool load_aga(const TFilename& name);
  void file_preview() const;
  bool is_aga_file(const TFilename& name) const;
  bool import_file();

  TRelation_description* rel_desc(int logicnum);
 
  // First non-static handlers in history!
  bool file_handler(TOperable_field& f, TField_event e);
  bool ini_handler(TOperable_field& f, TField_event e);
  bool isamfile_handler(TOperable_field& f, TField_event e);

public:  
  TRelation_description* rel_desc();

  TWizard_mask();
  virtual ~TWizard_mask();
};

///////////////////////////////////////////////////////////
// TFields_mask
///////////////////////////////////////////////////////////

class TFields_mask : public TAutomask
{ 
  
protected: // Internal use 
  bool field_handler(TOperable_field& of, TField_event fe);
 
public:
  virtual bool on_field_event(TOperable_field& of, TField_event fe, long jolly);
  TRelation_description* rel_desc() const;
  
  TFields_mask(const char* name, int number);
  virtual ~TFields_mask();
};

bool TFields_mask::on_field_event(TOperable_field& of, TField_event fe, long jolly)
{  
  bool ok = TRUE;
  switch(of.dlg())
  {       
  case F_FIELD:
    ok = field_handler(of, fe);
    break;
  default:
    break;
  }
  return ok;
}

TRelation_description* TFields_mask::rel_desc() const
{
  TSheet_field* sf = get_sheet();
  TWizard_mask& wm = (TWizard_mask&)sf->mask();
  TRelation_description* rd = wm.rel_desc();
  return rd;
}

bool TFields_mask::field_handler(TOperable_field& of, TField_event fe)
{           
  bool ok = TRUE;

  if (fe == fe_button)
  {                             
    TRelation_description* rd = rel_desc();
    if (rd)
    {
      if (rd->choose_field(of.get()))
      {
        of.set(rd->field_name());
        fe = fe_modify;
      }  
    }  
    else
      ok = error_box(TR("Selezionare un file valido"));
  }

  if (fe == fe_modify || fe_close)
  {                               
    const TString& n = of.get();
    if (n.not_empty())
    {
      TRelation_description* rd = rel_desc();
      if (rd)
      {
        const char* d = rd->get_field_description(n);
        if (d && *d)
          set(F_DESCR, d);
        else
          ok = error_box(FR("Il campo %s non esiste"), 
                         (const char*)n, rd->file_desc());
      }
    }
  }
  return ok;
}

TFields_mask::TFields_mask(const char* name, int number)
            : TAutomask(name, number)
{
}

TFields_mask::~TFields_mask()
{
}

///////////////////////////////////////////////////////////
// TFields_sheet
///////////////////////////////////////////////////////////

class TFields_sheet : public TSheet_field
{     
  TFields_mask* _sheet_mask;
 
protected: // TSheet_field
  virtual void create(WINDOW win);

public:
  void describe_fields();
  virtual TMask& sheet_mask() const;

  TFields_sheet(TAutomask* m);
  virtual ~TFields_sheet();
};

TMask& TFields_sheet::sheet_mask() const
{                    
  return _sheet_mask ? *(TMask*)_sheet_mask : TSheet_field::sheet_mask();
}

void TFields_sheet::create(WINDOW win)
{
  TSheet_field::create(win);
 
  const TFilename& name = sheet_mask().source_file();
  const int number = sheet_mask().number();
  
  _sheet_mask = new TFields_mask(name, number);
  _sheet_mask->set_sheet(this);
}

void TFields_sheet::describe_fields()
{
  TRelation_description* rd = _sheet_mask->rel_desc();
  if (rd)
  {
    TString str;
    for (int r = items()-1; r >= 0; r--)
    {           
      TToken_string& riga = row(r);
      str = riga.get(0);
      str = rd->get_field_description(str);
      if (str.not_empty()) 
        riga.add(str, F_DESCR-FIRST_FIELD);
    }
    force_update();
  }  
}

TFields_sheet::TFields_sheet(TAutomask* m)
             : TSheet_field(m), _sheet_mask(NULL)
{
}

TFields_sheet::~TFields_sheet()
{
  if (_sheet_mask)
    delete _sheet_mask;
}

bool TWizard_mask::file_open(TFilename& fname) const
{
  DIRECTORY dir; 
  FILE_SPEC fs;

  xvt_fsys_get_dir(&dir);
  xvt_fsys_get_dir(&fs.dir);
  strcpy(fs.type, fname.ext());
  strcpy(fs.name, fname);
  strcpy(fs.creator, "WIZ");
    
  const bool good = xvt_dm_post_file_open(&fs, TR("Selezionare il file ...")) == FL_OK;
  xvt_fsys_set_dir(&dir);
                 
  if (good)                 
    fname = fs.name;
  
  return good;
}

void TWizard_mask::load_ini(const TString& ininame)
{                 
  TWait_cursor hourglass;
  if (!_frozen)
  {
    _frozen = TRUE;
  
    TConfig ini(ininame, "MAIN");
    const int recsize = ini.get_int("RECORDSIZE");
    if (recsize > 0)
    {                    
      set(F_FIXEDLEN, "X", TRUE);
      set(F_RECLEN, recsize, TRUE);
    }
    else
      set(F_RECSEP, ini.get("RECORDSEP").left(4), TRUE);
    set(F_SKIPLINES, ini.get_int("SKIPLINES"));
    
    const TString16 fldsep = ini.get("FIELDSEP").left(1);
    set(F_FIELDSEP, fldsep, TRUE);
    
    ini.set_paragraph("RECORD");
  
    if (fldsep.empty())
    {                                                                             
      TColumnizer_field& cf = (TColumnizer_field&)field(F_COLUMNIZER);
      for (int i = 0; ; i++)
      {                        
        if (i > 0) 
        {
          const long position = ini.get_long("POSITION", NULL, i);
          if (position > 0)
            cf.add_column(position);
          else
            break;  
        }    
        else  
          cf.destroy_columns();
      }
    }
    
    TString use = ini.get("USE");
    if (use.not_empty())
      set(F_ISAM, use);
    
    TRelation_description* rd = rel_desc();
    
    TFields_sheet& fs = (TFields_sheet&)sfield(F_FIELDS);
    TFieldref fr;
    for (int i = 0; ini.exist("NAME", i) || ini.exist("POSITION", i); i++)
    {                  
      const TString& campo = ini.get("FIELD", NULL, i);
      TToken_string& row = fs.row(i);
      if (campo.not_empty())
      {
        fr = campo;
        row = fr.name();
        
        if (rd == NULL)
        {
          int isam = fr.file();
          if (isam)
          {
            set(F_ISAM, isam);
            rd = rel_desc();
          }  
        }
        
        if (rd)
          row.add(rd->get_field_description(fr.name()));
      }  
    }
    fs.force_update();
    _frozen = FALSE;  
  }
}

void TWizard_mask::save_ini(const TFilename& ininame) const
{                 
  if (!ininame.blank())
  {
    if (!ininame.exist() || 
        yesno_box(FR("Si desidera sovrascrivere il file %s"), (const char*)ininame))
    {    
      TConfig ini(ininame, "MAIN");
      ini.remove_all();
      ini.set("RECORDSEP", get(F_RECSEP));
      ini.set("RECORDSIZE", get(F_RECLEN));
      ini.set("SKIPLINES", get(F_SKIPLINES));
      const TString& fieldsep = get(F_FIELDSEP);
      ini.set("FIELDSEP", fieldsep);
      ini.set("TYPEFIELD", -1);
 
      ini.set_paragraph("RECORD");
      ini.remove_all();
      ini.set("USE", get(F_ISAM));

      if (fieldsep.empty())
      {        
        const TColumnizer_field& cf = (const TColumnizer_field&)field(F_COLUMNIZER);
        long last_column = 0;
        for (int i = 0; ; i++)
        {
          const long column = cf.get_column(i);
          if (column <= 0)
            break; 
          const long len = column - last_column;
          ini.set("POSITION", last_column, NULL, TRUE, i);  
          ini.set("LENGTH", len, NULL, TRUE, i);
          last_column = column;
        }
      }
      
      TSheet_field& sf = sfield(F_FIELDS);
      FOR_EACH_SHEET_ROW(sf, r, row)
      {                             
        ini.set("FIELD", row->get(0), NULL, TRUE, r);
        
        const char* name = row->get(1);
        if (name == NULL || *name <= ' ')
          name = row->get(0);
        ini.set("NAME", name, NULL, TRUE, r);
      }
    }  
  }  
}

bool TWizard_mask::is_aga_file(const TFilename& name) const
{
  bool yes = xvt_str_compare_ignoring_case(name.ext(), "txt") == 0;
  if (yes)
  {
    TScanner aga(name);
    yes = aga.paragraph("Data"); // Esiste il paragrafo dati?
  }
  return yes;
}

bool TWizard_mask::load_aga(const TFilename& name)
{   
  TWait_cursor hourglass;
  if (!_frozen)
  {
    _frozen = TRUE;
    TSheet_field& sf = sfield(F_FIELDS);
    TScanner aga(name);
    TToken_string riga(1024);
    TToken_string campo(15, ',');
    TString isam;
    bool inside_header = FALSE;
    
    while (aga.line().not_empty())
    {     
      riga = aga.token(); 
  
      if (riga.compare("[Data]", -1, TRUE) == 0)  
      {
        set(F_FIXEDLEN, "", TRUE);
        set(F_RECLEN, "", TRUE);
        set(F_RECSEP, "", TRUE);
        set(F_FIELDSEP, "|", TRUE);
        set(F_SKIPLINES, aga.linenum(), TRUE);
        if (isam.not_empty())
          set(F_ISAM, isam, TRUE);
        break;
      }
  
      if (inside_header)
      {
        if (riga.compare("Fields", 6, TRUE) == 0)  
        {
          const int uguale = riga.find('=');
          if (uguale >= 0)
          {
            riga.ltrim(uguale+1);
            for(campo = riga.get(0); campo.not_empty(); campo = riga.get())
            {
              sf.row(-1) = campo.get(0);
              sf.check_row(sf.items()-1);
            }
          }
        } else
        if (riga.compare("File", 4, TRUE) == 0)  
        {
          const int uguale = riga.find('=');
          if (uguale >= 0)
          {
            isam = riga.mid(uguale+1);
            isam.trim();
          }
        }
        else
          inside_header = riga[0] != '[';
      } 
      else
      {
        if (riga.compare("[Header]", -1, TRUE) == 0)
        {
          sf.destroy();
          inside_header = TRUE;
        }
      }
    }
    _frozen = FALSE;
  }
  return TRUE;
}

void TWizard_mask::file_preview() const
{                 
  TWait_cursor hourglass;
  if (_frozen)
    return;
  
  const int MAXLINE = 8192;
  const bool fixedlen = get_bool(F_FIXEDLEN);
  const int reclen = fixedlen ? get_int(F_RECLEN) : 0;
  const long skiplines = get_long(F_SKIPLINES);
  const TString& recsep = get(F_RECSEP);
  const TString& fieldsep = get(F_FIELDSEP);

  const TString& fname = get(F_FILE);
  int flags = ios::in;
  if (fixedlen)
    flags |= ios::binary;
  ifstream f(fname, flags);

  if (fixedlen)
  {
    streamoff offset = reclen * skiplines;
    f.seekg(offset, ios::beg);
  }  
  else
  {
    for (long s = skiplines; s > 0; s--)
    {
      if (*recsep)
        f.ignore(MAXLINE, *recsep);
      else  
        f.ignore(MAXLINE, '\n');
    }  
  }
  
  TColumnizer_field& cf = (TColumnizer_field&)field(F_COLUMNIZER);
  
  int displines = get_int(F_DISPLINES);
  if (displines <= 0) 
    displines = cf.visible_rows();
  
  TString_array righe;
	int l;
  for (l = 0; l < displines; l++)
  {
    righe.add(new TToken_string(MAXLINE), l);
    TToken_string& riga = righe.row(l);
    char* buff = riga.get_buffer();
    
    if (fixedlen)
    {   
      f.read(buff, reclen);
      riga.cut(reclen);
    }
    else
    {   
      if (*recsep)
      {
        f.getline(buff, riga.size(), *recsep);
        f.ignore(strlen(recsep)-1);
      }  
      else
        f.getline(buff, riga.size());
    }
    if (f.eof()) 
      break;
  }
  
  if (fieldsep.blank())
  {   
    cf.enable();
  }
  else
  {
    TPointer_array maxlen;
    int maxcol = 0;
    int l;
    for (l = righe.items()-1; l >= 0; l--)
    {
      TToken_string& riga = righe.row(l);
      riga.separator(fieldsep[0]);
      int col = 0;
      FOR_EACH_TOKEN(riga, tok)
      {
        const long len = *tok ? strlen(tok) : 1;
        if (len > maxlen.get_long(col))
          maxlen.add_long(len, col);
        col++;
      }
      if (col > maxcol)
        maxcol = col;
    }
    cf.disable();
    cf.destroy_columns();
    long last_column = 0;
    for (l = 0; l < maxcol; l++)
    {
      const long len = maxlen.get_long(l);
      last_column += len;
      cf.add_column(last_column);
    }  
    
    TToken_string oldrow;
    TString str;
    for (l = righe.items()-1; l >= 0; l--)
    {
      TToken_string& riga = righe.row(l);
      oldrow = riga;
      riga.cut(0);
      int col = 0;
      FOR_EACH_TOKEN(oldrow, tok)
      {
        const int len = (int)maxlen.get_long(col);
        str = tok;        
        if (str[0] =='#' || real::is_real(str))
          str.right_just(len);
        else
          str.left_just(len);
        riga << str;
        col++;
      }
    }
  }

  cf.destroy_rows();
  for (int m = 0; m < righe.items(); m++)
  {
    TToken_string& riga = righe.row(m);
    cf.add_row(riga);
  }  
  cf.recalc_layout(reclen, righe.items());
}   

TRelation_description* TWizard_mask::rel_desc(int logicnum)
{             
  if (_rel && _rel->lfile().num() != logicnum)
  {
    delete _rel;
    _rel = NULL;
    delete _reldesc;
    _reldesc = NULL;
  }
  if (_rel == NULL && logicnum > 0)
  {
    _rel = new TRelation(logicnum);
    _reldesc = new TRelation_description(*_rel);
  }  
    
  return _reldesc;
}

TRelation_description* TWizard_mask::rel_desc()
{           
  TRelation_description* rd = NULL;
  const TString& isam = get(F_ISAM);
  const int logicnum = str2isamfile(isam);
  if (logicnum > 0)
    rd = rel_desc(logicnum);
  return rd;  
}

bool TWizard_mask::file_handler(TOperable_field& f, TField_event e)
{ 
  bool ok = TRUE;
  
  if (e == fe_button)
  {
    TFilename n("*.txt");
    if (file_open(n))
    {
      f.set(n);
      e = fe_modify;
    }  
  }     
  
  if (e == fe_modify)
  {            
    TFilename n = f.get();
    if (n.exist())
    {    
      if (is_aga_file(n))
      {
        load_aga(n);
      }  
      else
      {
        const char* ext[] = { "imp", "ini", NULL };
        for (int e = 0; ext[e]; e++)
        {
          n.ext(ext[e]);
          if (n.exist())
          {
            set(F_INI, n, TRUE);
            return TRUE;
          }  
        }
      }  
      
      n = n.name();
      n.ext("");   
      if ((n[0] == 'f' || n[0] == 'F') && atoi(n.mid(1,-1)))
        n.ltrim(1);
      if (str2isamfile(n))
        set(F_ISAM, n, TRUE);
      
      file_preview();
    }  
    else
      ok = error_box(TR("Il file non esiste"));
  }
  return ok;
}

bool TWizard_mask::ini_handler(TOperable_field& f, TField_event e)
{           
  bool ok = TRUE;
  switch (e)
  {        
  case fe_button:
    {
      TFilename n("*.imp");
      if (file_open(n))
        f.set(n);
      else
        break;  
    }  
  case fe_init:
  case fe_modify:
    {                       
      const TFilename n = f.get();
      const bool pieno = !n.blank();
      enable(F_SAVE, pieno);
      if (pieno)
      {   
        if (n.exist())
        {
          load_ini(n);
          file_preview();
        }  
      }  
    }
    break;
  default:
    break;
  }
  return ok;
}

bool TWizard_mask::isamfile_handler(TOperable_field& f, TField_event e)
{          
  bool ok = TRUE;
  switch (e)
  {
  case fe_init:
    disable(F_IMPORT);
    break;
  case fe_button:
    {
      int logicnum = str2isamfile(f.get());
      logicnum = choose_isamfile(logicnum);
      if (logicnum > 0)
        f.set(logicnum);
      else
        break;
    }
  case fe_modify:
    {              
      bool can_import = str2isamfile(f.get()) > 0;
      if (can_import)
      {   
        TFields_sheet& fs = (TFields_sheet&)sfield(F_FIELDS); 
        fs.describe_fields();
      }
      else
        ok = error_box(TR("File dati non valido"));
      can_import &= fexist(get(F_FILE));
      enable(F_IMPORT, can_import);
      reset(F_ZAP);
    }
    break;
  }  
  return ok;
}

bool TWizard_mask::import_file()
{
  bool ok = FALSE;

  const TFilename filename = get(F_FILE);
  if (!filename.exist())
    return error_box(FR("Il file %s non esiste"), (const char*)filename);

  const int logicnum = str2isamfile(get(F_ISAM));
  if (logicnum <= 0)
    return error_box(TR("E' necessario specificare un file di destinazione valido"));

  rel_desc(0);  // Chiude il file isam correntemente in uso, altrimenti niente _excllock
  TSystemisamfile sif(logicnum);
  int err = sif.open_ex(_excllock);
  if (err != NOERR)
    return error_box(FR("Impossibile aprire il file %d: errore %d"), logicnum, err);
  const bool empty = sif.items() == 0L;
  sif.close();
    
  if (get_bool(F_ZAP))  
  {
    if (!empty && yesno_box(FR("Procedere con l'azzeramento del file %d?"), logicnum))
      sif.packfile(FALSE, TRUE);
  }
  
  const TFilename ininame = get(F_INI);
  if (ininame.exist())
  { 
    TFile_text txt(filename, ininame);
    err = txt.open('r');
    if (err == NOERR)
    {
      TRecord_text rec;
      for (long numrec = 1; txt.read(rec) == NOERR; numrec++)
      {
        err = txt.autosave(rec);
        if (err != NOERR)
        {
          ok = error_box(FR("Errore %d durante la scrittura del record %ld:"),
                         err, numrec);
          break;
        }
      }
    }
    else  
      ok = error_box(FR("Impossibile leggere il file %s"), (const char*)filename);
  }
  else
  {
    if (is_aga_file(filename))
    {
      err = sif.open_ex(_excllock);
      if (err == NOERR)
        ok = sif.load(filename) == NOERR;
      else
        ok = error_box(FR("Impossibile aprire il file %d: errore %d"), logicnum, err);
      sif.close();
    }
    else
      ok = error_box(FR("Il file %s non esiste"), (const char*)ininame);
  }
  return ok;
}

bool TWizard_mask::on_field_event(TOperable_field& f, TField_event e, long jolly)
{
  bool ok = TRUE;
	
	if (jolly == 0)
	{
		switch(f.dlg())
		{
			case F_FILE:
				ok = file_handler(f, e);
				break;
			case F_INI:
				ok = ini_handler(f, e);
				break;
			case F_RECLEN:
			case F_RECSEP:  
			case F_FIELDSEP:
			case F_SKIPLINES:
			case F_DISPLINES:
			case F_FIXEDLEN:
				if (e == fe_modify)
					file_preview();
				break;  
			case F_ISAM:  
				ok = isamfile_handler(f, e);
				break;
			case F_SAVE:
				if (e == fe_button)
					save_ini(get(F_INI));
				break;  
			case F_IMPORT:  
				if (e == fe_button)
					import_file();
				break;  
			case F_COLUMNIZER:
				if (e == fe_init)
					file_preview();   // Indispensabile!
				break;
			default:
				break;  
		}         
	}
	else
	{
		TFields_sheet& fs = (TFields_sheet&)sfield(F_FIELDS); 

		ok = ((TFields_mask&)fs.sheet_mask()).on_field_event(f, e, 0);
	}
  return ok;
}
                                                 
TMask_field* TWizard_mask::parse_field(TScanner& scanner)
{
  const TString& key = scanner.key();
  if (key == "BR") 
    return new TColumnizer_field(this);
  if (key == "SP") 
    return new TFields_sheet(this);
  return TAutomask::parse_field(scanner);
}

TWizard_mask::TWizard_mask()
            : _frozen(FALSE), _reldesc(NULL), _rel(NULL)
{                           
  read_mask("ba1800a", 0, 1);
  set_handlers();
}

TWizard_mask::~TWizard_mask() 
{
  if (_reldesc)
    delete _reldesc;
  if (_rel)  
    delete _rel;
}           

///////////////////////////////////////////////////////////
// Wizard main app
///////////////////////////////////////////////////////////

class TImport_wizard : public TSkeleton_application
{      
protected: // TSkeleton_application
  virtual void main_loop();

public:
  void import();
};  

void TImport_wizard::import()
{
  const int nLogicNum = atoi(argv(2));
  if (nLogicNum >= LF_USER)
  {  
    const TFilename strName = argv(3);
    if (strName.exist())
    {
      TSystemisamfile file(nLogicNum);
      file.load(strName);
    }
    else
      error_box("Nome file errato: %s", (const char*)strName);
  }
  else
    error_box("Numero file errato: %d", nLogicNum);
}

void TImport_wizard::main_loop()
{ 
  if (argc() < 3)
  {
    TWizard_mask m;
    m.run();
  }
  else
    import();
}

int ba1800(int argc, char* argv[])
{          
  TImport_wizard of_oz;
  of_oz.run(argc, argv, TR("Import Wizard"));
  return 0;
}