#include <colmask.h>                   
#include <colors.h>                   
#include <config.h>                   

COLOR RGB2COLOR(unsigned char red, unsigned char green, unsigned char blue)
{
  COLOR def = MAKE_COLOR(red, green, blue);

  // Se nel colore non compare l'indice cerca di calcolarlo
  const unsigned char color_index = (unsigned char)(def >> 12);
  if (color_index <= 0x0 || color_index > 0xF)                                
  {
    const COLOR native_color[11] = { COLOR_RED,     COLOR_GREEN,  COLOR_BLUE,  COLOR_CYAN, 
                                     COLOR_MAGENTA, COLOR_YELLOW, COLOR_BLACK, COLOR_DKGRAY,
                                     COLOR_GRAY,    COLOR_LTGRAY, COLOR_WHITE };
    def &= 0x00FFFFFF;                                 
    for (int c = 0; c < 11; c++)
    {
      // Confronta solo la terna R,G,B
      if (def == (native_color[c] & 0x00FFFFFF))    
      {
        def = native_color[c];
        break;
      }  
    }
  }
  
  return def;
}

COLOR choose_color(COLOR col, WINDOW win)
{ 
  return xvt_dm_post_choose_color(win, col);
}

COLOR blend_colors(COLOR col1, COLOR col2, double perc)
{
  const unsigned int r1 = XVT_COLOR_GET_RED(col1);
  const unsigned int g1 = XVT_COLOR_GET_GREEN(col1);
  const unsigned int b1 = XVT_COLOR_GET_BLUE(col1);
  const unsigned int r2 = XVT_COLOR_GET_RED(col2);
  const unsigned int g2 = XVT_COLOR_GET_GREEN(col2);
  const unsigned int b2 = XVT_COLOR_GET_BLUE(col2);

	const byte r = byte(r1 * perc + r2*(1.0-perc));
	const byte g = byte(g1 * perc + g2*(1.0-perc));
	const byte b = byte(b1 * perc + b2*(1.0-perc));
	
	// return RGB2COLOR(r, g, b);
  return MAKE_COLOR(r, g, b);  // Faster
}

unsigned int color_distance(COLOR col1, COLOR col2)
{
  if ((col1 & 0x00FFFFFF) == (col2 & 0x00FFFFFF))
    return 0;

  const int r1 = XVT_COLOR_GET_RED(col1);
  const int g1 = XVT_COLOR_GET_GREEN(col1);
  const int b1 = XVT_COLOR_GET_BLUE(col1);
  const int r2 = XVT_COLOR_GET_RED(col2);
  const int g2 = XVT_COLOR_GET_GREEN(col2);
  const int b2 = XVT_COLOR_GET_BLUE(col2);
	const int r = abs(r1-r2);
	const int g = abs(g1-g2);
	const int b = abs(b1-b2);
  return (r > g && r > b) ? r : (g > b ? g : b);
}

class TColor_row_mask : public TMask
{ 
public:
  virtual void update();

  TColor_row_mask();
  virtual ~TColor_row_mask() { }
};

///////////////////////////////////////////////////////////
// TColor_row_mask
///////////////////////////////////////////////////////////

TColor_row_mask::TColor_row_mask()
               : TMask("bagn007", 1)
{
}

void TColor_row_mask::update()
{               
  TSheet_field* s = get_sheet();
  if (s == NULL)
  	return;
  TSelect_color_mask& m = (TSelect_color_mask&)s->mask();
  COLOR back, fore;
  m.get_cur_colors(back, fore);
  
  _pixmap = TRUE;
  set_pen(COLOR_BLACK);

  RCT rct; field(100).get_rect(rct);
  set_brush(back);
  frame(rct.left, 2*rct.top - rct.bottom - CHARY/2, rct.right, rct.top - CHARY/2, 0);
  
  field(99).get_rect(rct);
  set_brush(fore);
  frame(rct.left, 2*rct.top - rct.bottom - CHARY/2, rct.right, rct.top - CHARY/2, 0);

  _pixmap = FALSE;
}

///////////////////////////////////////////////////////////
// TColor_object_props
///////////////////////////////////////////////////////////

class TColor_object_props : public TObject
{         
  TString _key;
  TString _prompt;
  COLOR _back;
  COLOR _fore;
  COLOR _back_def;
  COLOR _fore_def;
  
protected:
public:   
  void set_key(const char * key) { _key = key; }
  void set_prompt(const char * prompt) { _prompt = prompt; }
  void set_back(COLOR back) { _back = back; }
  void set_fore(COLOR fore) { _fore = fore; }
  void set_back_def(COLOR back) { _back_def = back; }
  void set_fore_def(COLOR fore) { _fore_def = fore; }
  
  const TString & get_key() const { return _key; }
  const TString & get_prompt() const { return _prompt; }
  COLOR get_back() const { return _back; }
  COLOR get_fore() const { return _fore; }
  COLOR get_back_def() const { return _back_def; }
  COLOR get_fore_def() const { return _fore_def; }
  
  TColor_object_props(const char * key, const char * prompt, COLOR back, COLOR fore);
  virtual ~TColor_object_props() {}
};

TColor_object_props::TColor_object_props(const char * key, const char * prompt, COLOR back, COLOR fore) 
                   : _key(key), _prompt(prompt), _back(back), _fore(fore), _back_def(back), _fore_def(fore)
{              
}

///////////////////////////////////////////////////////////
// TSelect_color_mask
///////////////////////////////////////////////////////////


bool TSelect_color_mask::color_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE)
  {                                               
    TMask& m = f.mask();
    TSelect_color_mask& cm = (TSelect_color_mask&)m.get_sheet()->mask();
    TSheet_field& s = cm.sfield(101);
    const int cur = s.selected();
    
    TColor_object_props & p =  *cm.row(cur);
    const bool use_back = f.dlg() == 100;
    COLOR col = use_back ? p.get_back() : p.get_fore();     
    
    col = choose_color(col, m.win());
    if (col != COLOR_INVALID)
    {                   
      if (use_back)
        p.set_back(col);
      else
        p.set_fore(col);  
      cm._sheet_mask->update();
      m.set_focus();
      s.set_back_and_fore_color(p.get_back(), p.get_fore(), cur);
      s.force_update();
    }  
  }
  
  return TRUE;
}

bool TSelect_color_mask::reset_handler(TMask_field& f, KEY k)
{
  if (k == K_SPACE && f.yesno_box("Si desidera azzerare tutti i colori?"))
  {           
    TSelect_color_mask& cm = (TSelect_color_mask&)f.mask();
    TSheet_field& s = cm.sfield(101);
    const int items = cm.items();
    
    for (int i = 0; i < items; i++)
    {                    
      TColor_object_props & p = *cm.row(i);
                                                   
      const COLOR back = p.get_back_def();
      const COLOR fore = p.get_fore_def();
      p.set_back(back);
      p.set_fore(fore);
      s.set_back_and_fore_color(back, fore, i);
    }
    s.force_update();
  }
  if (k == K_ENTER)
  {
    TSelect_color_mask& cm = (TSelect_color_mask&)f.mask();
    
    cm.save();
  }
  return TRUE;
}

int TSelect_color_mask::add_color_def(const char * key, const char * prompt, COLOR back, COLOR fore)

{
  TColor_object_props * p = new TColor_object_props(key, prompt, back, fore);
  TSheet_field& s = sfield(101);

  const int row = _color_defs.add(p);
  
  TToken_string& riga = s.row(-1);
  riga << p->get_prompt();

  TString tmp(_mask_name) ; tmp << "_" << _paragraph;
  TConfig conf(CONFIG_GUI, tmp);
  
  tmp = p->get_key(); 
  if (conf.exist(tmp))
    p->set_fore(conf.get_color(tmp));
    
  tmp << "_Bg";
  if (conf.exist(tmp))
    p->set_back(conf.get_color(tmp));

  s.set_back_and_fore_color(p->get_back(), p->get_fore(), row);
  return row;
}   

void TSelect_color_mask::get_color_def(const char * key, COLOR & back, COLOR & fore) const 
{          
  const int pos = key2pos(key);
    
  if (pos >= 0)
  {
    back = get_back_color(pos);
    fore = get_fore_color(pos);
  }
  else
  {
    back = NORMAL_BACK_COLOR;
    fore = NORMAL_COLOR;
  }
} 

int TSelect_color_mask::key2pos(const char * key) const 
{
  const int items = _color_defs.items();
   
  for (int i = 0; i < items; i++)
    if (((TColor_object_props &) _color_defs[i]).get_key() == key)
      return i;
  return -1;
}        

COLOR TSelect_color_mask::get_back_color(int pos) const 
{
  return ((TColor_object_props &) _color_defs[pos]).get_back();
} 

COLOR TSelect_color_mask::get_fore_color(int pos) const 
{
  return ((TColor_object_props &) _color_defs[pos]).get_fore();
} 

TMask * TSelect_color_mask::get_mask(int, TMask& m)
{
  return ((TSelect_color_mask &) m.get_sheet()->mask())._sheet_mask;
}

void TSelect_color_mask::get_cur_colors(COLOR & back, COLOR & fore) const 
{
  TSheet_field& s = sfield(101);
  int cur = s.selected();
  TColor_object_props & p = *row(cur);

  back = p.get_back();
  fore = p.get_fore();     
} 

void TSelect_color_mask::init(const char * mask_name, const char * para) 
{              
  set_handler(102, reset_handler);

  _sheet_mask = new TColor_row_mask;
  _sheet_mask->set_handler(99, color_handler);
  _sheet_mask->set_handler(100, color_handler);

  TVariable_sheet_field& s = (TVariable_sheet_field&) sfield(101);
  s.set_getmask(get_mask);
  _mask_name = mask_name;
  _mask_name.ext("");
  _paragraph = para;
}

TSelect_color_mask::TSelect_color_mask(const TSheet_field & field) 
           : TVariable_mask("bagn007")
{
  const TMask& m = field.mask();
  TString16 para("Colors");
  const int num = field.sheet_mask().number() - 1;
  if (num > 0)
    para << num;
  init(m.source_file(), para);
}           
       
void TSelect_color_mask::save() const
{              
  TString tmp(_mask_name) ; tmp << "_" << _paragraph;
  TConfig conf(CONFIG_GUI, tmp);
  const int items = _color_defs.items();
   
  for (int i = 0; i < items; i++)
  {
    TColor_object_props & p = *row(i);
    
    tmp = p.get_key(); 
    if (p.get_fore() == p.get_fore_def())
      conf.remove(tmp);
    else
      conf.set_color(tmp, p.get_fore());

    tmp << "_Bg";
    if (p.get_back() == p.get_back_def())
      conf.remove(tmp);
    else
      conf.set_color(tmp, p.get_back());
  }
}              

TSelect_color_mask::TSelect_color_mask(const char * mask_name, const char * para) 
           : TVariable_mask("bagn007")
{              
  init(mask_name, para);
}

TSelect_color_mask::~TSelect_color_mask() 
{
  delete _sheet_mask;
}