#include <automask.h>
#include <diction.h>

#include "777200.h"
#include "777200a.h"

class TCU_editor : public TAutomask
{
  TTrasferimentoCU* _recset;
  int _quality;
  bool _simplyfied;

  TBit_array _dirty_row;
  bool _dirty_file;
  TString _txt;

protected:
  void save_page();
  bool save_page_if_dirty();
  void load();
  void save_file();
  bool find_text();

public:
  virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
  TCU_editor(const TFilename& fn, int quality, bool simple);
  ~TCU_editor() { delete _recset; }
};

void TCU_editor::load()
{
  TSheet_field& sheet = sfield(F_PATH);
  sheet.hide();
  sheet.destroy();

  const unsigned int cols = _recset->columns();

  TString8 name, last;
  for (unsigned int c = 0; c < cols; c++)
  {
    const TRecordset_column_info& ci = _recset->column_info(c);
    if (ci._type == _nullfld)
      continue;

    const TVariant& var = _recset->get(c);
    if (ci._name.len() == 8 && isdigit(ci._name[2]))
      name = ci._name;
    else
      name.format("%d", int(c+1));
    if (name == last)
    {
      TToken_string& prev = sheet.row(sheet.items()-1);
      TString tmp;
      tmp << prev.get(2) << var.as_string().mid(1);
      prev.add(tmp, 2);
      continue;
    }
    last = name;
    
    TToken_string row;
    row = name;
    switch (ci._type)
    {
    case _charfld:
    case _alfafld: 
      row.add(" "); 
      row.add(var.as_string());
      break;
    case _datefld: 
      row.add("D"); 
      row.add(var.as_date().string());
    break;
    case _realfld: 
      row.add("V"); 
      row.add(var.as_string());
      break;
    case _boolfld: 
      row.add("B"); 
      row.add(var.as_bool() ? "1" : "0");
    break;
    default      : 
      row.add("N"); 
      row.add(var.as_string());
      break;
    }
    row.add(ci._name, 3);
    const int nr = sheet.rows_array().add(row);
    if (c == 0 || name.len() == 8)
      sheet.disable_row(nr);
  }
  sheet.force_update();
  sheet.show();
  _dirty_row.reset();

  const TFilename n = _recset->query_text();
  TString80 msg; msg.format(FR("%s Record n. %ld"), n.name(), _recset->current_row()+1);
  xvtil_statbar_set(msg);
}

void TCU_editor::save_page()
{
  TSheet_field& sheet = sfield(F_PATH);
  TString8 code;
  FOR_EACH_SHEET_ROW(sheet, r, row) if (_dirty_row[r])
  {
    code = row->get(0);
    TVariant var = row->get(2);
    const bool positional = real::is_natural(code);
    if (positional) 
      _recset->set_field(atoi(code), var);
    else
      _recset->set_field(code, var);
  }
  _dirty_row.reset();
}

void TCU_editor::save_file()
{
  const TFilename fn = _recset->query_text(); 
  save_page();
  if (_recset->save(fn))
    _dirty_file = false;
  else
    cantwrite_box(fn);
}

bool TCU_editor::save_page_if_dirty()
{
  bool go = true;
  if (_dirty_row.first_one() >= 0)
  {
    const KEY k = yesnocancel_box(TR("Alcuni campi risultano modificati:\nSi desidera aggiornarli prima di proseguire?"));
    go = k != K_ESC;
    if (k == K_YES)
      save_page();
  }
  return go;
}

bool TCU_editor::find_text()
{
  _txt.trim(); _txt.upper();
  const int txtlen = _txt.len();
  if (txtlen <= 0)
    return false;

  const TRecnotype cur_pos = _recset->current_row();
  
  TRecnotype best = cur_pos;
  double score = (txtlen-1.1)/txtlen;
  TString str;

  while (score < 1.0)
  {
    if (!_recset->move_next())
      if (!_recset->move_first())
        break;
    if (_recset->current_row() == cur_pos)
      break;

    const unsigned int cols = _recset->columns();
    for (unsigned int i = 1; i < cols; i++)
    {
      const TVariant& var = _recset->get(i);
      if (var.type() == _alfafld)
      {
        str = var.as_string(); str.trim();
        const int slen = str.len();
        if (slen >= txtlen-1)
        {
          str.upper();
          if (str.find(_txt) >= 0)
          {
            best = _recset->current_row();
            score = 1.0;
            break;
          }
          else
          {
            if (score > 0.75) // Provo a cercare la sottostringa pi� simile
            {
              for (int i = str.find(_txt[0]); i >= 0; i = str.find(_txt[0], i+1))
              {
                const double k = xvt_str_fuzzy_compare(str.mid(i, txtlen), _txt);
                if (k > score)
                {
                  best = _recset->current_row();
                  score = k;
                }
              }
            }
          }
        }
      }
    }
  }
  _recset->move_to(best);
  return best != cur_pos;
}

bool TCU_editor::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
  static char _code[16];

  switch (o.dlg())
  {
  case DLG_FIRSTREC: if (e == fe_button && save_page_if_dirty() && _recset->move_first()) load(); return false;
  case DLG_PREVREC : if (e == fe_button && save_page_if_dirty() && _recset->move_prev())  load(); return false;
  case DLG_NEXTREC : if (e == fe_button && save_page_if_dirty() && _recset->move_next())  load(); return false;
  case DLG_LASTREC : if (e == fe_button && save_page_if_dirty() && _recset->move_last())  load(); return false;
  case DLG_PREVIEW : 
    {
      const TFilename fn = _recset->query_text(); 
      if (fn.exist())
        print_cu(fn, _quality, _simplyfied);
    } 
    return false;
  case DLG_SAVEREC:
    if (e == fe_button && _dirty_file)
    {
      save_file();
      o.enable(_dirty_file);
    }
    break;
  case DLG_FINDREC:
    if (e == fe_button)
    {
      ::xvt_dm_post_string_prompt(TR("Inserire il codice da ricercare"), _txt.get_buffer(81), 80);
      if (_txt.full() && save_page_if_dirty())
      {
        if (find_text())
          load();
        else
          warning_box("Nessuna corrispondenza");
      }
      return false;
    }
    break;
  case F_PATH:
    switch (e)
    {
    case fe_init         : 
      if (jolly <= 0)
        load(); 
      break;
    case fe_close        : 
      if (_dirty_file)
      {
        const KEY k = yesnocancel_box(TR("Alcuni record risultano modificati:\nSi desidera salvare il file?"));
        if (k == K_ESC)
          return false;
        if (k == K_YES)
          save_file();
      }
      break;
    case se_notify_modify: 
      if (o.shown()) 
      {
        _dirty_row.set(jolly); 
        enable(DLG_SAVEREC, _dirty_file = true);
      }
      break;
    case se_query_modify : 
      return ((TSheet_field&)o).row_enabled(jolly);
    case se_query_del    : 
      return false;
    case se_query_add:
      if (jolly > 0)
      {
        TSheet_field& s = ((TSheet_field&)o);
        if (s.row(jolly-1).get_char(0) >= 'A')
        {
          xvt_dm_post_string_prompt(TR("Codice campo"), _code, 9);
          if (strlen(_code) == 8)
            return true;
          else
            error_box("Codice non valido");
        }
      }
      return false;
    case se_notify_add:
      if (strlen(_code) == 8)
      {
        TSheet_field& s = ((TSheet_field&)o);
        TToken_string& r = s.row(jolly);
        r = _code; r.upper(); r.add("AN");
        _code[0] = '\0';
      }
      break;
    default: break;
    }
    break;
  default: break;
  }
  return true;
}

TCU_editor::TCU_editor(const TFilename& fn, int quality, bool simple) : TAutomask("777200b"), _quality(quality), _simplyfied(simple)
{ 
  _recset = new TTrasferimentoCU(fn, 'r');
  _recset->move_first();
  enable(DLG_SAVEREC, _dirty_file = false); 
}

void edit_cu(const TFilename& datafile, int quality, bool simple)
{
  if (datafile.exist())
  {
    TCU_editor m(datafile, quality, simple);
    m.run();
    xvtil_statbar_set(NULL);
  }
  else
    cantread_box(datafile);
}