//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WScom.h>
#include <WSCvlabel.h>
#include <WSCclassInformation.h>
#include <WSDdev.h>
#include <WSCgrid.h>
#include <WSCfontSet.h>
#include <WSCsform.h>
#include <WSCscrFrame.h>
#include <WSCvbtn.h>
#include <WSCbaseList.h>
#include <WSDmouse.h>
#include <WSDkeyboard.h>
#include <WSDappDev.h>
#include <WSCfontSet.h>
#include <WSCcolorSet.h>
#include <WSCvifield.h>

WSMFguiClassInitialize(WSCgrid,WSCform);
WSMFpropertyValueChange( WSCgrid, WSNbackColor , short,WS_DF_WORKBACKCOLOR);

WSCgrid::WSCgrid(WSCbase* base,char* objname):
                WSCform(base,objname){
//printf("WSCgrid::WSCgrid...\n");
  _hline_pos  = WSGFstrdup("25,50");
  _vline_pos  = WSGFstrdup("30,70");
  _vline_list = NULL;
  _hline_list = NULL;
  _values = NULL;
  _data = WSGFstrdup("");
  _data_source_name = WSGFstrdup("");
  _data_source_type = WS_DATA_SOURCE_NONE;
  _vnum = 3;
  _hnum = 3;
  _vselect_pos = 0;
  _hselect_pos = 0;
  _selected = False;
  _need_update = True;
  _enable_input = False;
  _font = 0;
  _data_changed = True;
  _alignment_v = WS_CENTER;
  _alignment_h = WS_CENTER;
  _fg_colors = NULL;
  _bg_colors = NULL;
  _line_width = 1;
  _line_type = 0;
  _if_status = 0;
  _ifield = NULL;
  _back_color = WS_DF_WORKBACKCOLOR;
  _need_ds_update = False; 

  WSMFpropertyCreateStart
    WSMFpropertyCreate(WSNlineX, char*, _hline_pos, WSSlineX );
    WSMFpropertyCreate(WSNlineY, char*, _vline_pos, WSSlineY );
    WSMFpropertyCreate(WSNvcolumns, WSCulong, _vnum, WSSvcolumns );
    WSMFpropertyCreate(WSNhcolumns, WSCulong, _hnum, WSShcolumns );

    WSMFpropertyCreate(WSNdata, char*, _data,WSSdata );
    WSMFpropertyCreate(WSNdataSource, WSCuchar, _data_source_type,WSSdataSource );
      WSMFpropertySetSelection(WSRdataSource,WSRdataSourceD);
    WSMFpropertyCreate(WSNdataSourceName, char*, _data_source_name,WSSdataSourceName );
    WSMFpropertyCreate(WSNenableInput,  WSCbool, _enable_input, WSSenableInput );
      WSMFpropertySetSelection(WSRbool3,WSRbool3D);

    WSMFpropertyCreate(WSNalignmentV,   WSCuchar,   _alignment_v,WSSalignmentV );
      WSMFpropertySetSelection(WSRalignmentV, WSRalignmentVD);
    WSMFpropertyCreate(WSNalignmentH,   WSCuchar,   _alignment_h,WSSalignmentH);
      WSMFpropertySetSelection( WSRalignmentH, WSRalignmentHD);
    WSMFpropertyCreate(WSNlineWidth, WSCuchar, _line_width,WSSlineWidth);
    WSMFpropertyCreate(WSNlineType,  WSCuchar, _line_type,WSSlineType);
      WSMFpropertySetSelection(WSRlineType, WSRlineTypeD);




//    WSMFpropertyDelete(WSNvirtualScroll);
    WSMFpropertyCreate(WSNfont,  WSCuchar, _font, WSSfont );
    WSMFpropertyVisibleOff(WSNscrollHeight);
    WSMFpropertyValueChangeDef( WSCgrid,WSNbackColor ,short);

    WSMFaddExtTrigger(WSEV_ITEM_SELECTED,"ITEM-SELECTED");
 
  WSMFpropertyCreateEnd

}

WSMFproperty( WSCgrid, WSNalignmentV,WSCuchar,_alignment_v, WS_CENTER     );
WSMFproperty( WSCgrid, WSNalignmentH,WSCuchar,_alignment_h, WS_CENTER     );
WSMFproperty( WSCgrid, WSNfont, WSCuchar, _font, (char)WSGIappFontSet()->getDefaultFontNo());
WSMFproperty( WSCgrid, WSNlineX, char*, _hline_pos, WSGFstrdup("25,50"));
WSMFproperty( WSCgrid, WSNlineY, char*, _vline_pos, WSGFstrdup("30,70"));
WSMFproperty( WSCgrid, WSNvcolumns, WSCulong,_vnum, 3);
WSMFproperty( WSCgrid, WSNhcolumns, WSCulong,_hnum, 3);

WSMFproperty( WSCgrid, WSNdata,  char*, _data,WSGFstrdup(""));
WSMFproperty( WSCgrid, WSNdataSource,  WSCuchar, _data_source_type,WS_DATA_SOURCE_NONE);
WSMFproperty( WSCgrid, WSNdataSourceName,  char*, _data_source_name,WSGFstrdup(""));
WSMFproperty( WSCgrid, WSNenableInput,  WSCbool, _enable_input,False);
WSMFproperty( WSCgrid, WSNlineWidth, WSCuchar, _line_width, 1);
WSMFproperty( WSCgrid, WSNlineType,  WSCuchar, _line_type, 0);

void WSCgrid::setWorkWSNlineType(WSCuchar){}
void WSCgrid::getWorkWSNlineType(WSCuchar*){}
void WSCgrid::setWorkWSNlineWidth(WSCuchar){}
void WSCgrid::getWorkWSNlineWidth(WSCuchar*){}
void WSCgrid::setWorkWSNalignmentV(WSCuchar){}
void WSCgrid::getWorkWSNalignmentV(WSCuchar*){}
void WSCgrid::setWorkWSNalignmentH(WSCuchar){}
void WSCgrid::getWorkWSNalignmentH(WSCuchar*){}

void WSCgrid::setWorkWSNfont(WSCuchar){}
void WSCgrid::getWorkWSNfont(WSCuchar*){}
void WSCgrid::setWorkWSNlineX(char*){
//printf("WSCgrid::setWorkWSNlineX...\n");
  _need_update = True;
}
void WSCgrid::getWorkWSNlineX(char**){}
void WSCgrid::setWorkWSNlineY(char*){
  _need_update = True;
}
void WSCgrid::getWorkWSNlineY(char**){}
void WSCgrid::setWorkWSNvcolumns(WSCulong){
  _need_update = True;
}
void WSCgrid::getWorkWSNvcolumns(WSCulong*){}
void WSCgrid::setWorkWSNhcolumns(WSCulong){
  _need_update = True;
}
void WSCgrid::getWorkWSNhcolumns(WSCulong*){}



void WSCgrid::setWorkWSNenableInput(WSCbool){}
void WSCgrid::getWorkWSNenableInput(WSCbool*){}

void WSCgrid::setData(WSCvariant* val,long code){
//printf("WSCgrid::setData %s\n",val->getCharPtr());
  if (code == WS_EN_DEFAULT){
    WSCstring str;
    str.setString(val->getCharPtr(),code);
    if (_data != NULL){
      delete _data;
    }
    _data = WSGFstrdup(str.getString());
  }else{
    if (_data != NULL){
      delete _data;
    }
    _data = WSGFstrdup((char*)val);
  }
  _data_changed = True;
  needUpdate();
}
long WSCgrid::getDataSourceType(){
  return _data_source_type;
}
char* WSCgrid::getDataSourcePropertyName(){
  return WSNdata;
}

void WSCgrid::setWorkWSNdata(char* data){
//  _clear_ds_instance();
//  if (_data_source_type == WS_DATA_SOURCE_NONE){
    WSCstring tmp;
    tmp.setString(_data);
    tmp.replaceString("\\n","\n",0);
    WSCvariant val;
    val = (char*)tmp;
    setData(&val,WS_EN_DEFAULT);
//    _set_data(tmp);
//  }
  _data_changed = True;
}
void WSCgrid::_set_ds_instance(){
  WSCbase* serv = WSGIappObjectList()->searchInstance("WSCbase", _data_source_name);
//printf("WSCgrid::_set_dsinstance here! %s %s\n",_data_source_name,serv);
  if (serv != NULL){
//printf("WSCgrid::_set_dsinstance %s\n",serv->getInstanceName());
    setDataSourceServer(serv);
    serv->addDataSourceClient(this);
    WSCstring val;
    val = serv->getProperty(serv->getDefaultProperty());
    val.replaceString("\n",",",0);
    WSCvariant tmp;
    tmp = (char*)val;
    setData(&tmp,WS_EN_DEFAULT);
  }else{
    WSCvariant tmp;
    tmp = "";
    setData(&tmp,WS_EN_DEFAULT);
    _need_ds_update = True;
  }
}

void WSCgrid::getWorkWSNdata(char** ptr){
  if (getPropertyEditMode() != False &&
      _data_source_type != WS_DATA_SOURCE_NONE){
    *ptr = "";
    return;
  }
};

void WSCgrid::setWorkWSNdataSource(WSCuchar){
//printf("WSCgrid::setWorkWSNdataSource here0 0x%x\n",_data_source_name);
  if (_data_source_name != NULL && _data_source_name[0] != 0){
    if (_data_source_type == WS_DATA_SOURCE_FILE){
      _data_from_file(_data_source_name);
    }else
    if (_data_source_type == WS_DATA_SOURCE_INSTANCE){
//printf("WSCgrid::setWorkWSNdataSource here1\n");
      _set_ds_instance();
    }
    if (_data_source_type != WS_DATA_SOURCE_INSTANCE){
      WSCbase* ds = getDataSourceServer();
      if (ds != NULL){
        ds->delDataSourceClient(this);
        setDataSourceServer(NULL);
      }
    }
  }
}
void WSCgrid::getWorkWSNdataSource(WSCuchar*){}

void WSCgrid::setWorkWSNdataSourceName(char*){
//printf("WSCgrid::setWorkWSNdataSourceName here1\n");
  if (_data_source_type == WS_DATA_SOURCE_INSTANCE){
//printf("WSCgrid::setWorkWSNdataSourceName here2\n");
    _set_ds_instance();
  }else
  if (_data_source_type == WS_DATA_SOURCE_FILE){
    _data_from_file(_data_source_name);
  }
}
void WSCgrid::getWorkWSNdataSourceName(char**){}

long WSCgrid::_device_initialize(){
  WSCform::_device_initialize();
  WSDdev* dev = getowndev();
  if (dev != NULL){
    dev->setEnableEventBit(WSEV_EXPOSE_BIT | WSEV_RESIZE_BIT |
                           WSEV_MOUSE_PRESS_BIT | WSEV_MOUSE_RELEASE_BIT);
    return WS_NO_ERR;
  }
  return WS_ERR;
}

WSCgrid::~WSCgrid(){
  if (_vline_pos != NULL){
    delete _vline_pos;
  }
  if (_hline_pos != NULL){
    delete _hline_pos;
  }
  if (_vline_list != NULL){
    delete _vline_list;
  }
  if (_hline_list != NULL){
    delete _hline_list;
  }
  if (_data != NULL){
    delete _data;
  }
  if (_data_source_name != NULL){
    delete _data_source_name;
  }
  if (_values != NULL){
    int i;
    int num = _vnum * _hnum;
    for(i=0; i<num; i++){
      WSCvariant* item = _values[i];
      delete item;
    }
    delete _values;
    _values = NULL;
  }
  if (_fg_colors != NULL){
    delete _fg_colors;
    _fg_colors = NULL;
  }
  if (_bg_colors != NULL){
    delete _bg_colors;
    _bg_colors = NULL;
  }
}
void WSCgrid::_adjust(){
}
long WSCgrid::getVColumns(){
  return _vnum;
}
long WSCgrid::getHColumns(){
  return _hnum;
}

void WSCgrid::update(){
//printf("WSCgrid::update %d\n",_need_update);
  if (_need_ds_update != False){
    _need_ds_update = False;
    _set_ds_instance();
  }
  if (_need_update != False){
    _adjust_line();
  }
  if (_data_changed != False){
    _adjust_value();
  }
  WSCform::update();
}

long WSCgrid::getItemAlignment(WSCulong hpos,WSCulong vpos){
  return getAlignment();
}
WSCvariant WSCgrid::getItem(WSCulong hpos,WSCulong vpos){
  WSCvariant tmp = "";
  if (_values != NULL){
    WSCulong i = vpos*_hnum + hpos;
    if (i<_values_num){
      WSCvariant* val = _values[i];
      return *val;
    }
  }
  return tmp;
}

long WSCgrid::getCellNo(long px,long py,WSCulong* cx,WSCulong* cy){
  long i;
  for(i=0; i<(long)_values_num; i++){
    long x = 0;
    long y = 0;
    long w = _w;
    long h = _h;
    long posx = i % _hnum;
    long posy = i / _hnum;
    if (posx){
      x = _hline_list[posx-1];
    }
    if (posx == (long)_hnum-1){
      w -= x;
    }else{
      w = _hline_list[posx] - x;
    }

    if (posy){
      y = _vline_list[posy-1];
    }
    if (posy == (long)_vnum-1){
      h -= y;
    }else{
      h = _vline_list[posy] - y;
    }
    if (x < px && px < x + w &&
        y < py && py < y + h){
      *cx = posx;
      *cy = posy;
      return WS_NO_ERR;
    }
  }
  return WS_ERR;
}

long WSCgrid::getCellGeometry(WSCulong cx,WSCulong cy,short* x,short* y,
                              WSCushort* w, WSCushort* h){
  long i = cx + cy*_hnum;
  if (!(i < (long)_values_num)){
    return WS_ERR;
  }

  if (_values != NULL){
    *x = 0;
    *y = 0;
    *w = _w;
    *h = _h;
    if (cx){
      *x = _hline_list[cx-1];
    }
    if (cx == (WSCulong)_hnum-1){
      *w -= *x;
    }else{
      *w = _hline_list[cx] - *x;
    }

    if (cy){
      *y = _vline_list[cy-1];
    }
    if (cy == (WSCulong)_vnum-1){
      *h -= *y;
    }else{
      *h = _vline_list[cy] - *y;
    }
    return WS_NO_ERR;
  }

  return WS_ERR;
}
long WSCgrid::draw(){

  if (_no_refresh != False){
    WSCbase::update();
    setAbsoluteDraw(False);
    return WS_NO_ERR;
  }
  if (getVisible() == False){
    return WS_NO_ERR;
  }
  WSDdev* dev = getowndev();
  if (dev == NULL){
    return WS_ERR;
  }
  if (_need_update != False){
    _adjust_line();
  }
  if (_data_changed != False){
    _adjust_value();
  }
  WSCbool absolute = getAbsoluteDraw();
  if (absolute == False  ){
    if ( dev->isExposed(0,0,_w,_h) == False ){
      return WS_NO_ERR;
    }
  }
  long err = dev->beginDraw(0,0,_w,_h,absolute);
  if (err != WS_NO_ERR){
    return WS_NO_ERR;
  }
  short ex = 0;
  short ey = 0;
  WSCushort ew = _w;
  WSCushort eh = _h;
  if (absolute == False){
    dev->getExposedArea(&ex,&ey,&ew,&eh);
  }
  WSCbase::update();
  setAbsoluteDraw(False);

  if (_bp_color == -1){
    if (_grad_no == 0){
      dev->setForeColor(_back_color);
      dev->drawFillRect(0,0,_w,_h);
      if ((WSGIappDev()->getGuiPolicy() & WS_POLICY_AQUA) != 0 &&
           _bp_color == -1){
        if (_a1_color == -1){
          WSGFgetShadowColor(_back_color,&_a1_color,&_a2_color,&_a3_color);
        }
        WSGFdrawStripes(dev,_w,_h,_a1_color,_a2_color,_a3_color);
      }
      dev->setForeColor(_back_color);

    }else{
      dev->drawGradation(_grad_no,_ts_color,_back_color,_bs_color,0,0,_w,_h,_grad_margin);
    }
  }

  if (getDotMode() == True){
    dev->setForeColor(_fore_color);
    long i,j;
    for(i=0; i<_w; i+=10){
      for(j=0; j<_h; j+=10){
        if (ex < i && i < ex+ ew &&
            ey < j && j < ey+ eh ){
          dev->drawFillRect(i,j,1,1);
        }
      }
    }
  }


  if (_values != NULL){
    long i;
    for(i=0; i<(long)_values_num; i++){
      WSCvariant* val = _values[i];
      WSCstring str((char*)(*val));
      long x = 0;
      long y = 0;
      long w = _w;
      long h = _h;
      long posx = i % _hnum;
      long posy = i / _hnum;
//printf("WSCgrid::draw pos %d %d\n",posx,posy);
      if (posx){
        x = _hline_list[posx-1];
//printf("WSCgrid::draw x=%d i=%d\n",x,posx-1);
      }
      if (posx == (long)_hnum-1){
//printf("WSCgrid::draw %d %d\n",w,x);
        w -= x;
      }else{
        w = _hline_list[posx] - x;
//printf("WSCgrid::draw1 %d %d\n",_hline_list[posx],x);
      }

      if (posy){
        y = _vline_list[posy-1];
      }
      if (posy == (long)_vnum-1){
//printf("WSCgrid::draw  h=%d y=%d\n",h,y);
        h -= y;
      }else{
        h = _vline_list[posy] - y;
      }
      short bgcol = _back_color;
      if (_bg_colors != NULL){
        bgcol = _bg_colors[i];
      }
      dev->setForeColor(bgcol);
      dev->drawFillRect(x,y,w,h);
      short fgcol = _fore_color;
      if (_fg_colors != NULL){
        fgcol = _fg_colors[i];
      }
      dev->setForeColor(fgcol);

      long align = getAlignment();
      dev->drawString(x,y,w,h,&str,_font,align,-1,False);
//printf("WSCgrid::draw  %d %d %d %d #%s#\n",x,y,w,h,(char*)str);
    }
  }
  dev->setForeColor(_fore_color);
  dev->setLineWidth(_line_width);
  dev->setLineDashType(_line_type);
  long i;
  if (_vline_list != NULL){
    long val = _vnum-1;
    if (val < 0){
      val = 0;
    }
    for(i=0; i<val; i++){
      dev->drawLine(0,_vline_list[i],_w,_vline_list[i]); 
    }
  }
  if (_hline_list != NULL){
    long val = _hnum-1;
    if (val < 0){
      val = 0;
    }
    for(i=0; i<val; i++){
      dev->drawLine(_hline_list[i],0,_hline_list[i],_h); 
//printf("WSCgrid::drawline x=%d i=%d\n",_hline_list[i],i);
    }
  }

  if (_shadow_type == WS_SHADOW_TRANS){
    long lt = _line_width /2;
    dev->drawRect(lt,lt,_w - lt*2,_h - lt*2);
  }else{
    WSGFdrawShadow(dev,_shadow_type,_shadow_thick,_fore_color,_ts_color,_bs_color,_back_color,0,0,_w,_h);
  }
  dev->endDraw();
  return WS_NO_ERR;
}
void WSCgrid::_value_update(){
  _adjust_line();
  _adjust_value();
}
void WSCgrid::_adjust_value(){
  long i;
  long num_back = _values_num;
  long num = _vnum * _hnum;
  if (num_back != num){
    if (_values != NULL){
      long num = _values_num;
      for(i=0; i<num; i++){
        WSCvariant* val = _values[i];
        delete val;
      }
      delete _values;
      _values = NULL;
      _values_num = 0;
    }
    _values = new WSCvariant*[num];
    _values_num = num;
    if (_fg_colors != NULL){
      delete _fg_colors;
      _fg_colors = NULL;
    }
    if (_bg_colors != NULL){
      delete _bg_colors;
      _bg_colors = NULL;
    }
  }

  WSCstring in(_data);
  for(i=0; i<num; i++){
    WSCvariant* val = new WSCvariant;
    WSCstring item = in.getWord(i,",");
    val->setValue((char*)item);
//printf("WSCgrip::_adjust_value %d #%s#\n",i,(char*)(*val));
    _values[i] = val;
  }
}

void WSCgrid::_adjust_line(){
  long i;
  if (_vline_list != NULL){
    delete _vline_list;
    _vline_list = NULL;
  }
  if (_vnum <1){
    _vnum = 1;
  }

  _vline_list = new long[_vnum];
  long num = _vnum -1;
  if (num < 0){
    num = 0;
  }
//printf("WWSCgrid::_adjust_line  num=%d\n",num);
  WSCstring str(_vline_pos);
  long vn = str.getWords(",");
  for(i=0; i<num; i++){
    WSCstring tmp = str.getWord(i,",");
    if (i < vn ){
      _vline_list[i] = atoi((char*)tmp);
    }else{
      _vline_list[i] = ((_w - _vline_list[vn-1])*(i-vn+1)/(num -vn));
    }
//printf("WWSCgrid::_adjust_line  %d vval=%d\n",i,_vline_list[i]);
  }
  _vline_list[_vnum-1] =0;
  if (_hline_list != NULL){
    delete _hline_list;
  }
  if (_hnum <1){
    _hnum = 1;
  }
  _hline_list = new long[_hnum];
  num = _hnum -1;
  if (num < 0){
    num = 0;
  }
  str = _hline_pos;
  long hn = str.getWords(",");
  for(i=0; i<num; i++){
    WSCstring tmp = str.getWord(i,",");
    if (i < hn ){
      _hline_list[i] = atoi((char*)tmp);
    }else{
      _hline_list[i] = ((_h - _hline_list[hn-1])*(i-hn+1)/(num -hn));
    }
  }
  _hline_list[_hnum-1] =0;
}
char WSCgrid::getAlignment() {
static char fl = 0;
static long table[3][3];
  if (fl == 0){
    fl = 1;
    table[WS_LEFT][WS_CENTER - WS_CENTER] = WS_LEFT;
    table[WS_LEFT][WS_TOP - WS_CENTER] = WS_LEFT_TOP;
    table[WS_LEFT][WS_BOTTOM - WS_CENTER] = WS_LEFT_BOTTOM;
    table[WS_RIGHT][WS_CENTER - WS_CENTER] = WS_RIGHT;
    table[WS_RIGHT][WS_TOP - WS_CENTER] = WS_RIGHT_TOP;
    table[WS_RIGHT][WS_BOTTOM - WS_CENTER] = WS_RIGHT_BOTTOM;
    table[WS_CENTER][WS_CENTER - WS_CENTER] = WS_CENTER;
    table[WS_CENTER][WS_TOP - WS_CENTER] = WS_TOP;
    table[WS_CENTER][WS_BOTTOM - WS_CENTER] = WS_BOTTOM;
  }
  return table[_alignment_h][_alignment_v - WS_CENTER];
}

long WSCgrid::setCellForeColor(WSCulong x,WSCulong y,short color){
  if (_need_update != False){
    _value_update();
  }
  if (_fg_colors == NULL){
    _fg_colors = new short[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _fg_colors[i] = _fore_color;
    }
  }
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    _fg_colors[pos] = color;
    needUpdate();
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSCgrid::setCellForeColor(WSCulong x,WSCulong y,char* color){
  if (_need_update != False){
    _value_update();
  }
  if (_fg_colors == NULL){
    _fg_colors = new short[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _fg_colors[i] = _fore_color;
    }
  }
  short cno = WSGIappColorSet()->getColorNo(color);
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    _fg_colors[pos] = cno;
    needUpdate();
    return WS_NO_ERR;
  }
  return WS_ERR;
}

long WSCgrid::setCellBackColor(WSCulong x,WSCulong y,short color){
  if (_need_update != False){
    _value_update();
  }
  if (_bg_colors == NULL){
    _bg_colors = new short[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _bg_colors[i] = _back_color;
    }
  }
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    _bg_colors[pos] = color;
    needUpdate();
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSCgrid::setCellBackColor(WSCulong x,WSCulong y,char* color){
  if (_need_update != False){
    _value_update();
  }
  if (_bg_colors == NULL){
    _bg_colors = new short[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _bg_colors[i] = _back_color;
    }
  }
  short cno = WSGIappColorSet()->getColorNo(color);
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    _bg_colors[pos] = cno;
    needUpdate();
    return WS_NO_ERR;
  }
  return WS_ERR;
}
void WSCgrid::onMousePress(WSCpoint* pt){
  if (_enable_input == False){
    WSCform::onMousePress(pt);
    return;
  }
//printf("WSCgrid::onMousePress\n");
  long clk = WSGFclocktime();
  long clkbk = (long)getUserData("ctime");
  if (clk - clkbk < 250){
    setUserData("ctime",(void*)0);
    setUserData("onfire",(void*)1);
  }else{
    setUserData("ctime",(void*)clk);
    setUserData("onfire",(void*)0);
  }
  WSCform::onMousePress(pt);
}

void WSCgrid::onMouseRelease(WSCpoint* pt){
  if (_enable_input == False){
    WSCform::onMouseRelease(pt);
    return;
  }
//printf("WSCgrid::onMouseRelease\n");
  long fired = (long)getUserData("onfire");
  if (fired != False){
    setUserData("ctime",(void*)0);
    WSCulong cx,cy;
    long ret = getCellNo(pt->x,pt->y,&cx,&cy);
    if (ret == WS_ERR){
      return;
    }
    _adjust_input(cx,cy,True);
    setUserData("ctime",(void*)0);
  }
  WSCform::onMouseRelease(pt);
}
long WSCgrid::setFocusedCell(WSCulong cx,WSCulong cy){
  short x,y;
  WSCushort w,h;
  
  long ret = getCellGeometry((WSCulong)cx,(WSCulong)cy,&x,&y,&w,&h); 
  if (ret == WS_ERR){
    return WS_ERR;
  }
  _adjust_input(cx,cy,True);
  return WS_NO_ERR;
}
long WSCgrid::getFocusedCell(WSCulong* cx,WSCulong* cy){
  short x,y;
  WSCushort w,h;
  *cx = 0; 
  *cy = 0; 
  long ret = getCellGeometry((WSCulong)cx,(WSCulong)cy,&x,&y,&w,&h); 
  if (ret == WS_ERR){
    return WS_ERR;
  }
  if (_ifield != NULL){
    *cx = (WSCulong)_ifield->getUserData("cx");
    *cy = (WSCulong)_ifield->getUserData("cy");
    return WS_NO_ERR;
  }
  return WS_ERR;
}



void WSCgrid::_input_focus_lose(WSCbase* ifield){
  if (ifield->getFocus() == False){
    WSCgrid* _this = (WSCgrid*)ifield->getUserData("pgrid");
    WSCvariant val = ifield->getProperty(WSNlabelString);
    long cx = (long)ifield->getUserData("cx");
    long cy = (long)ifield->getUserData("cy");
    _this->onInputFixed(&val,cx,cy);
  }
}
void WSCgrid::_input_fix_work(WSCbase* ifield){
  long key = WSGIappKeyboard()->getKey();
  if (key == WSK_Return){
    WSCgrid* _this = (WSCgrid*)ifield->getUserData("pgrid");
    WSCvariant val = ifield->getProperty(WSNlabelString);
    long cx = (long)ifield->getUserData("cx");
    long cy = (long)ifield->getUserData("cy");
    _this->onInputFixed(&val,cx,cy);
  }
}
void WSCgrid::onInputFixed(WSCvariant* val,long cx,long cy){
  WSCulong i = cx + cy*_hnum;
  if ( i < _values_num ){
    *(_values[i]) = *val;
    needUpdate();
    _ifield->setVisible(False);

    long num = _values_num;
    long i;
    WSCstring tmp;
    if (_values_num >0){
      tmp << *(_values[0]);
    }
    for(i=1; i<num; i++){
      tmp << "," << *(_values[i]);
    }
    if (_data != NULL){
      delete _data;
      _data = NULL;
    }
    _data = WSGFstrdup((char*)tmp);
  }
}
void WSCgrid::_create_input(){
  if (_ifield == NULL){
    _ifield = WSCbase::getNewInstance("WSCvifield",this,"grid-input");
    _ifield->initialize();
    _ifield->setInternalObject(True);

    WSCprocedure* op = new WSCprocedure("focus-lose",WSEV_FOCUS_CH);
    op->setInternal(True);
    op->setFunction(_input_focus_lose,"_input_focus_lose");
    _ifield->addProcedure(op);
    WSCprocedure* op2 = new WSCprocedure("focus-lose",WSEV_KEY_HOOK);
    op2->setInternal(True);
    op2->setFunction(_input_fix_work,"_input_fix_work");
    _ifield->addProcedure(op2);
    _ifield->setUserData("pgrid",(void*)this);
  }
}

void WSCgrid::_adjust_input(long cx,long cy,WSCbool fl){
  if (fl != False){
    if (_ifield == NULL){
#if 0
      _ifield = WSCbase::getNewInstance("WSCvifield",this,"grid-input");
      _ifield->initialize();
      _ifield->setInternalObject(True);

      WSCprocedure* op = new WSCprocedure("focus-lose",WSEV_FOCUS_CH);
      op->setInternal(True);
      op->setFunction(_input_focus_lose,"_input_focus_lose");
      _ifield->addProcedure(op);
      WSCprocedure* op2 = new WSCprocedure("focus-lose",WSEV_KEY_HOOK);
      op2->setInternal(True);
      op2->setFunction(_input_fix_work,"_input_fix_work");
      _ifield->addProcedure(op2);
      _ifield->setUserData("pgrid",(void*)this);
#endif
      _create_input();
    }
    short x,y;
    WSCushort w,h;
  
    long ret = getCellGeometry((WSCulong)cx,(WSCulong)cy,&x,&y,&w,&h); 
    if (ret == WS_ERR){
      return;
    }
    if ( _ifield->getVisible() != False){
      _ifield->setFocus(False);
      _ifield->setVisible(False);
    }
    _ifield->redraw();

    _ifield->setProperty(WSNx,x+_line_width);
    _ifield->setProperty(WSNy,y+_line_width);
    _ifield->setProperty(WSNwidth,w - _line_width*2);
    _ifield->setProperty(WSNheight,h - _line_width*2);
    WSCvariant val = getItem(cx,cy);
    _ifield->setProperty(WSNbackColor,_back_color);
    _ifield->setProperty(WSNlabelString,(char*)val);
    _ifield->setProperty(WSNshadowThickness,1);
    _ifield->setProperty(WSNshadowType,WS_SHADOW_IN);
    _ifield->setUserData("cx",(void*)cx);
    _ifield->setUserData("cy",(void*)cy);

    WSCulong i = cx + cy *_hnum;
    short fg = _fore_color;
    short bg = _back_color;

    if (i <_values_num && _fg_colors != NULL ){ 
      fg = _fg_colors[i];
    }
    if (i <_values_num && _bg_colors != NULL ){ 
      bg = _bg_colors[i];
    }
    _ifield->setProperty(WSNforeColor,fg);
    _ifield->setProperty(WSNbackColor,bg);

    _ifield->setVisible(True);
    _ifield->setFocus(True);
    _ifield->setSpecialFocus(True);

  }else{
    if (_ifield != NULL){
      _ifield->setVisible(False);
    }
  }
}

long WSCgrid::setCellInputStatus(WSCulong x,WSCulong y,WSCbool fl){
  if (_need_update != False){
    _value_update();
  }
  if (_if_status == NULL){
    _if_status = new WSCbool[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _if_status[i] = True;
    }
  }
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    _if_status[pos] = fl;
    needUpdate();
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSCgrid::getCellInputStatus(WSCulong x,WSCulong y,WSCbool* fl){
  if (_need_update != False){
    _value_update();
  }
  if (_if_status == NULL){
    _if_status = new WSCbool[_values_num];
    long i;
    for(i=0; (WSCulong)i<_values_num; i++){
      _if_status[i] = True;
    }
  }
  long pos = y*_hnum + x;
  if ( pos < (long)_values_num){
    *fl = _if_status[pos];
    return WS_NO_ERR;
  }
  return WS_ERR;
}

void WSCgrid::_data_from_file(char* fname){
  WSCstring* str = WSGFreadTextFile(fname);
  if (str != NULL){
    WSCvariant tmp;
    str->replaceString("\n",",",0);
    tmp = str->getString();
    setData(&tmp,WS_EN_DEFAULT);
    delete str;
    update();
  }
}
long WSCgrid::setItem(WSCulong hpos,WSCulong vpos,WSCvariant val){
  long pos = vpos * _hnum + hpos;
  if (pos < (long)_values_num && _values[pos] != NULL){
    *(_values[pos]) =  val;

    WSCstring tmp;
    long i;
    for(i=0; i<(long)_values_num -1; i++){
      tmp << *(_values[i]) << ",";
    }
    tmp << *(_values[_values_num -1]);
    if (strcmp((char*)tmp,_data)){
      delete _data;
      _data = strdup((char*)tmp);
    }
  }
  return WS_ERR;
}
char* WSCgrid::getDefaultProperty(){
  return WSNdata;
}
