#include "../cg/conto.h"

#include "scselect.h"                    

#include <defmask.h>

TSelection_mask::TSelection_mask(const char* name)
               : TMask(name), _who('C'), _key(1), _clifo_rel(NULL),
                 _cli_cur_k1(NULL), _cli_cur_k2(NULL), _for_cur_k1(NULL), _for_cur_k2(NULL)
{
  // crea relazioni, cursori e cursor_sheets
  _clifo_rel  = new TRelation(LF_CLIFO);
  
  TRectype filter(LF_CLIFO);
  filter.put("TIPOCF", "C");
  _cli_cur_k1 = new TCursor(_clifo_rel, "", 1, &filter, &filter);
  _cli_cur_k2 = new TCursor(_clifo_rel, "", 2, &filter, &filter);
  
  _cli_sh_k1 = new TCursor_sheet(_cli_cur_k1, " |CODCF|RAGSOC", "Selezione clienti per codice",
                                 "@1|Codice|Ragione Sociale@50",0,1);
  _cli_sh_k2 = new TCursor_sheet(_cli_cur_k2, " |RAGSOC|CODCF", "Selezione clienti per ragione sociale",
                                 "@1|Ragione Sociale@50|Codice",0,1);
  
  if (id2pos(SC_CLIFO) >= 0)
  {
    filter.put("TIPOCF", "F");
    _for_cur_k1 = new TCursor(_clifo_rel, "", 1, &filter, &filter);
    _for_cur_k2 = new TCursor(_clifo_rel, "", 2, &filter, &filter);
    _for_sh_k1 = new TCursor_sheet(_for_cur_k1, " |CODCF|RAGSOC", "Selezione fornitori per codice",
                                   "@1|Codice|Ragione Sociale@50",0,1);
    _for_sh_k2 = new TCursor_sheet(_for_cur_k2, " |RAGSOC|CODCF", "Selezione fornitori per ragione sociale",
                                   "@1|Ragione Sociale@50|Codice",0,1);
  }
  else
  {
    _for_cur_k1 = NULL;
    _for_cur_k2 = NULL;
    _for_sh_k1 = NULL;
    _for_sh_k2 = NULL;
  }                               
  
  set_handler(SC_CLIFO,   rclifo_handler); 
  set_handler(SC_SORTCF,  rsortcf_handler);
  set_handler(SC_SELECT,  bselect_handler); 
  set_handler(SC_RESET,   breset_handler); 
  set_handler(SC_CFCODFR, ffrom_handler); 
  set_handler(SC_CFCODTO, fto_handler); 
  set_handler(SC_CFDESFR, fdfrom_handler); 
  set_handler(SC_CFDESTO, fdto_handler); 
}

TSelection_mask::~TSelection_mask()
{       
  if (_for_sh_k1 != NULL)
  {
    delete _for_sh_k2;
    delete _for_sh_k1;
    delete _for_cur_k2;
    delete _for_cur_k1;
  }

  delete _cli_sh_k2;
  delete _cli_sh_k1;
  delete _cli_cur_k2;
  delete _cli_cur_k1;

  delete _clifo_rel;
}             

bool TSelection_mask::stop_run(KEY k)
{     
  const bool ok = TMask::stop_run(k);
  if (ok && k == K_ENTER)
    update_assoc();
  return ok;  
}

void TSelection_mask::set_handler(short fld_id, CONTROL_HANDLER handler)
{                              
  const int pos = id2pos(fld_id);
  if (pos >= 0)
    fld(pos).set_handler(handler);
}

TCursor_sheet& TSelection_mask::cur_sheet() const
{             
  TCursor_sheet* cs;
  if (get_key() == 1) cs = get_who() == 'C' ? _cli_sh_k1 : _for_sh_k1;
  else                cs = get_who() == 'C' ? _cli_sh_k2 : _for_sh_k2;
  
  CHECK(cs, "Can't use a NULL TCursor_sheet");
  return *cs;
}                 

void TSelection_mask::reset_sheets()
{
  _cli_sh_k1->uncheck(-1);
  _cli_sh_k2->uncheck(-1);
  if (_for_sh_k1)
  {
    _for_sh_k1->uncheck(-1);
    _for_sh_k2->uncheck(-1);
  }  
  reset(SC_CFCODFR);
  reset(SC_CFCODTO);
  reset(SC_CFDESFR);
  reset(SC_CFDESTO);
  reset(SC_NSEL);
}


// Seleziona tutti i clienti con codice compreso tra due estremi
void TSelection_mask::select_clifo_range(long from, long to)
{
  TCursor_sheet& c = cur_sheet();
  const long items = c.items();
  const int key = get_key();
  
  TCursor* crs = c.cursor();
  if (to == 0 && items)
    to = c.row(items-1).get_long(key);
  
  if (from > to)                    // Controlla limiti
  {
    long tmp = to;
    to = from;
    from = tmp;
  }                           
  long last = 0;
  long firs = 0;
  
  TRectype& rec = crs->file().curr();
  rec.zero();
  rec.put(CLI_TIPOCF,get_who());
  rec.put(CLI_CODCF,from);
  
  const TRecnotype start = crs->read(_isgteq);
  firs = rec.get_long(CLI_CODCF);
  rec.zero();
  rec.put(CLI_TIPOCF,get_who());
  rec.put(CLI_CODCF,to);
  TRectype recx(rec);
  TRecnotype end = crs->read(_isgteq);
  if (rec > recx) 
  {
    end--;
    (*crs)-=1;
  }
  last = rec.get_long(CLI_CODCF);
  c.uncheck(-1);
  for (long i = start; i <= end; i++)
      c.check(i);
  if (get(SC_CFCODFR).not_empty())
    set(SC_CFCODFR, firs);
  if (get(SC_CFCODTO).not_empty())
    set(SC_CFCODTO, last);
  
  set(SC_NSEL, c.checked());
}

void TSelection_mask::select_des_clifo_range(const TString& from, const TString & to)
{
  TCursor_sheet& c = cur_sheet();
  const long items = c.items();
  const int key = get_key();   
  CHECK(key == 2, "La chiave deve essere la 2");
  TString s_from(from), s_to(to);
  
  if (s_to.empty() && items)
    s_to = c.row(items-1).get(1);
  s_from.upper();
  s_to.upper();
  
  if (s_from > s_to)                    // Controlla limiti
  {
    s_to = from;
    s_from = to;// ripristina i valori originali (!upper)
    set(SC_CFDESFR, to);
    set(SC_CFDESTO, from);
  } else
    {
      if (to.not_empty()) s_to = to;
      s_from = from; // ripristina i valori originali (!upper)
    }                          

  TString last;
  TString firs;
  
  TCursor* crs = c.cursor();
  TRectype& rec = crs->file().curr();
  rec.zero();
  rec.put(CLI_TIPOCF,get_who());
  rec.put(CLI_RAGSOC,s_from);
  const TRecnotype start = crs->read(_isgteq);
  firs = rec.get(CLI_RAGSOC);
  rec.zero();
  rec.put(CLI_TIPOCF,get_who());
  rec.put(CLI_RAGSOC,s_to);
  TRectype recx(rec);
  TRecnotype end = crs->read(_isgteq);
  if (rec > recx) 
  {
    end--;
    (*crs)-=1;
  }
  last = rec.get(CLI_RAGSOC);
  c.uncheck(-1);
  for (long i = start; i <= end; i++)
      c.check(i);
  if (get(SC_CFDESFR).not_empty())
    set(SC_CFDESFR, firs);
  if (get(SC_CFDESTO).not_empty())
    set(SC_CFDESTO, last);
  set(SC_NSEL, c.checked());
}

// Cerca il primo e l'ultimo cliente selezionati
void TSelection_mask::set_clifo_limits()
{  
  long from = 0, to = 0;
  
  TCursor_sheet& c = cur_sheet();
  const long items = c.items();
  const int key = get_key();
  long first = -1, last = -1;
  
  for (long i = 0; i < items; i++) 
    if (c.checked(i))
    {
      if (first == -1)
        first = i;
    }
  if (first != -1)  //Optimization... If nothing was found previously skip this test.
    for (long j = (items-1); j >= 0 ; j--)
      if (c.checked(j))
        if (last == -1)
        {
          last = j;
          break;
        }
  if (first!= -1 && last != -1) // Something selected?
  {
    TToken_string fitem(c.row(first));
    TToken_string litem(c.row(last));
    from = fitem.get_long(key);
    to   = litem.get_long(key);
    if (from>to)
    {
      long t = to;
      to=from;
      from=t;
    }
  }
  set(SC_CFCODFR, from);
  set(SC_CFCODTO, to);
  set(SC_NSEL,    c.checked());
}

void TSelection_mask::set_des_clifo_limits()
{  
  long first=-1, last=-1;
  TString from,to;
  TCursor_sheet& c = cur_sheet();
  const long items = c.items();
  const int key = get_key();
  CHECK(key == 2, "La chiave deve essere la 2");
  
  for (long i = 0; i < items; i++) 
    if (c.checked(i))
    {
      if (first == -1)
        first = i;
    }
  if (first != -1)
    for (long j = (items-1); j >= 0 ; j--)
      if (c.checked(j))
        if (last == -1)
        {
          last = j;
          break;
        }
  if (first!= -1 && last != -1)
  {
    TToken_string fitem(c.row(first));
    TToken_string litem(c.row(last));
    from = fitem.get(1);
    to   = litem.get(1);
    if (from>to)
    {
      TString temp(to);
      to=from;
      from=temp;
    }
  }
  set(SC_CFDESFR, from);
  set(SC_CFDESTO, to);
  set(SC_NSEL,    c.checked());
}

// handlers

bool TSelection_mask::ffrom_handler(TMask_field& f, KEY k)
{    
  TSelection_mask& m = (TSelection_mask&)f.mask();

  if (k == K_TAB && f.focusdirty())
  {
    const long cod1 = atol(f.get());
    const long cod2 = m.get_long(SC_CFCODTO); 
    m.select_clifo_range(cod1, cod2);
  }
  else 
    if (k == K_F9)
    {
      TSelection_mask& m = (TSelection_mask&)f.mask();
      TCursor_sheet& c = m.cur_sheet();
      c.disable_check();
      c.disable(DLG_USER);
      if (c.run() == K_ENTER)
      {      
        TToken_string& t = c.row(c.selected());
        const long cod1 = t.get_long(m.get_key());
        const long cod2 = m.get_long(SC_CFCODTO);
        m.set(SC_CFCODFR, cod1);
        m.select_clifo_range(cod1, cod2);
      }
      c.enable(DLG_USER);
      c.enable_check();
    }
  
  return TRUE;
}

bool TSelection_mask::fto_handler(TMask_field& f, KEY k)
{                                                
  TSelection_mask& m = (TSelection_mask&)f.mask();

  if (k == K_TAB && f.focusdirty())
  {
    const long cod1 = m.get_long(SC_CFCODFR); 
    const long cod2 = atol(f.get());
    m.select_clifo_range(cod1, cod2);
  }
  else 
    if (k == K_F9)
    {
      TSelection_mask& m = (TSelection_mask&)f.mask();
      TCursor_sheet& c = m.cur_sheet();
      c.disable_check();
      c.disable(DLG_USER);
      if (c.run() == K_ENTER)
      {      
        TToken_string& t = c.row(c.selected());
        const long cod2 = t.get_long(m.get_key());
        const long cod1 = m.get_long(SC_CFCODFR); 
        m.set(SC_CFCODTO, cod2);
        m.select_clifo_range(cod1, cod2);
      }
      c.enable(DLG_USER);
      c.enable_check();
    }
  return TRUE;
}

bool TSelection_mask::fdfrom_handler(TMask_field& f, KEY k)
{    
  TSelection_mask& m = (TSelection_mask&)f.mask();

  if (k == K_TAB && f.focusdirty())
  {
    const TString des1(f.get());
    const TString des2(m.get(SC_CFDESTO));
    m.select_des_clifo_range(des1, des2);
  }
  else 
    if (k == K_F9)
    {  
      TSelection_mask& m = (TSelection_mask&)f.mask();
      TCursor_sheet& c = m.cur_sheet();
      
      c.disable_check();
      c.disable(DLG_USER);
      if (c.run() == K_ENTER)
      {      
        TToken_string& t = c.row(c.selected());
        const TString des1(t.get(3 - m.get_key()));
        const TString des2 = m.get(SC_CFDESTO);
        m.set(SC_CFDESFR, des1);
        m.select_des_clifo_range(des1, des2);
      }
      c.enable(DLG_USER);
      c.enable_check();
    }
  
  return TRUE;
}

bool TSelection_mask::fdto_handler(TMask_field& f, KEY k)
{                                                
  TSelection_mask& m = (TSelection_mask&)f.mask();

  if (k == K_TAB && f.focusdirty())
  {
    const TString des2(f.get());
    const TString des1(m.get(SC_CFDESFR));
    m.select_des_clifo_range(des1, des2);
  }
  else 
    if (k == K_F9)
    {
      TSelection_mask& m = (TSelection_mask&)f.mask();
      TCursor_sheet& c = m.cur_sheet();
  
      c.disable_check();
      c.disable(DLG_USER);
      if (c.run() == K_ENTER)
      {      
        TToken_string& t = c.row(c.selected());
        const TString des1(m.get(SC_CFDESFR));
        const TString des2(t.get(3 - m.get_key()));
        m.set(SC_CFDESTO, des2);
        m.select_des_clifo_range(des1, des2);
      }
      c.enable(DLG_USER);
      c.enable_check();
    }
  return TRUE;
}

bool TSelection_mask::breset_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TSelection_mask& m = (TSelection_mask&)f.mask();
    m.reset_sheets();
  }  
  return TRUE;
}

bool TSelection_mask::bselect_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {
    TSelection_mask& m = (TSelection_mask&)f.mask();
    TCursor_sheet& c = m.cur_sheet();
    c.enable_check();
    c.run();
    if (m.get_key() == 2)
      m.set_des_clifo_limits();
    else
      m.set_clifo_limits();
  }
  return TRUE;
}

bool TSelection_mask::rclifo_handler(TMask_field& f, KEY k)
{   
  if (k == K_SPACE)
  {
    TSelection_mask& m = (TSelection_mask&)f.mask();
    m.set_who(f.get()[0]);
    m.reset_sheets();
  }
  return TRUE;
}

bool TSelection_mask::rsortcf_handler(TMask_field& f, KEY k)
{   
  if (k == K_SPACE)
  {
    TSelection_mask& m = (TSelection_mask&)f.mask();
    m.set_key(atoi(f.get()));
    m.reset_sheets();
  }
  return TRUE;
}

void TSelection_mask::update_assoc()
{                       
  _assoc.destroy();
  _all_selected = FALSE;
  
  TCursor_sheet& cs = cur_sheet(); // Sheet di selezione (CLI/FO/PCON)
  const long checked = cs.checked();
  if (checked == 0L || checked == cs.items())
    _all_selected =TRUE;
  else
  {
    const int first = get_key();
    const char who = get_who();
    TString16 key;
    
    for (long i = cs.items()-1; i >= 0; i--) if (cs.checked(i))
    {        
      TToken_string& row = cs.row(i);
      if (who == 'C' || who == 'F')
      {
        key.format("000000%06ld", row.get_long(first));
      }
      else
      {                                    
        const TBill b(row, first, 0x0);
        key.format("%03d%03d%06ld", 
                   b.gruppo(), b.conto(), b.sottoconto());
      }
      _assoc.add(key, NULL);
    }
  }
}

bool TSelection_mask::selected(const TBill& b) const
{
  bool ok = _all_selected;
  if (!ok)
  {
    TString16 key;
    key.format("%03d%03d%06ld", 
               b.gruppo(), b.conto(), b.sottoconto());
    ok = _assoc.is_key(key);           
  }
  return ok;
}

bool TSelection_mask::selected(int g, int c, long s) const
{
  bool ok = _all_selected;
  if (!ok)
  {
    TString16 key;
    key.format("%03d%03d%06ld", g, c, s);
    ok = _assoc.is_key(key);           
  }
  return ok;
}
