//
// 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 <WSCvslider.h>
#include <WSCclassInformation.h>
#include <WSCdevice.h>
#include <WSDdev.h>
#include <WSDtimer.h>

#define WS_OVER   0
#define WS_BBTN1  1
#define WS_BBTN2  2
#define WS_BBTN3  3
#define WS_BBTN4  4
#define WS_BAR    5
#define WS_INTER1 6
#define WS_INTER2 7

WSMFguiClassInitialize(WSCvslider,WSCnwbase);
WSMFversion(WSCvslider,WSCnwbase);

WSCvslider::WSCvslider(WSCbase* base,char* objname):
                WSCnwbase(base,objname) {

  _bar_status = WS_OVER;
//  _out_side_mouse_move = True;
//  _out_side_mouse_release = True;
  _btn_x_bk =0;
  _btn_y_bk =0;
  _value_bk =0;
  _timer_id = 0;

  _shadow_thick = 2;
//  _bg_no = WSGFcolor("gray85");
//  _ts_no = WSGFcolor("gray95");
//  _bs_no = WSGFcolor("gray65");
  _bg_no = WS_DF_NWBACKCOLOR;
  _ts_no = WS_DF_NWTOPSHADOWCOLOR;
  _bs_no = WS_DF_NWBOTTOMSHADOWCOLOR;
  _slider_size = 30;
  _maximum = 1000;
  _minimum = 0;
  _dragInterval = 30;
  _value = 0;
  _orientation = WS_HORIZONTAL;

  WSMFpropertyCreateStart
    WSMFparentCheckVerSrc(WSCvslider);

    WSMFpropertyCreate(WSNshadowThickness,WSCuchar, _shadow_thick,WSSshadowThickness);
    WSMFpropertyCreate(WSNbackColor,short,_bg_no,WSSbackColor );
    WSMFpropertyCreate(WSNtopShadowColor,short,_ts_no,WSStopShadowColor);
    WSMFpropertyCreate(WSNbottomShadowColor,short,_bs_no,WSSbottomShadowColor);
    WSMFpropertyCreate(WSNsliderSize,WSCushort, _slider_size,WSSsliderSize);
    WSMFpropertyCreate(WSNmaximum,short,_maximum,WSSmaximum);
    WSMFpropertyCreate(WSNminimum,short,_minimum,WSSminimum);
    WSMFpropertyCreate(WSNdragInterval,WSCushort,_dragInterval,WSSdragInterval);
    WSMFpropertyCreate(WSNvalue,short,_value,WSSvalue);
    WSMFpropertyCreate(WSNorientation,WSCuchar,_orientation,WSSorientation);
     WSMFpropertySetSelection(WSRorientation, WSRorientationD);

    WSMFpropertyDelete(WSNblinkFlag);
    WSMFpropertyDelete(WSNblinkRate);
    WSMFpropertyDelete(WSNtwinBlink);
    WSMFpropertyDelete(WSNforeColor);
    WSMFpropertyDelete(WSNblinkColor);
    WSMFpropertyDelete(WSNblinkRefreshing);

    WSMFaddTrigger(WSEV_VALUE_CH     );
    WSMFaddTrigger(WSEV_ACTIVATE    );

    WSMFdelTrigger(WSEV_MOUSE_MOVE  );
    WSMFdelTrigger(WSEV_MOUSE_PRESS   );
    WSMFdelTrigger(WSEV_MOUSE_RELEASE );

  WSMFpropertyCreateEnd
}

WSMFproperty( WSCvslider, WSNshadowThickness,WSCuchar, _shadow_thick, 2);
//WSMFproperty( WSCvslider, WSNbackColor,  short,   _bg_no, WSGFcolor("gray85") );
WSMFproperty( WSCvslider, WSNbackColor,  short, _bg_no,WS_DF_NWBACKCOLOR);
//WSMFproperty( WSCvslider, WSNtopShadowColor, short, _ts_no, WSGFcolor("gray95") );
WSMFproperty( WSCvslider, WSNtopShadowColor, short, _ts_no,WS_DF_NWTOPSHADOWCOLOR);
//WSMFproperty( WSCvslider, WSNbottomShadowColor, short,_bs_no, WSGFcolor("gray65") );
WSMFproperty( WSCvslider, WSNbottomShadowColor, short,_bs_no,WS_DF_NWBOTTOMSHADOWCOLOR);
WSMFproperty( WSCvslider, WSNsliderSize, WSCushort, _slider_size , 30);
WSMFproperty( WSCvslider, WSNmaximum, short,_maximum, 1000);
WSMFproperty( WSCvslider, WSNminimum, short,_minimum, 0);
WSMFproperty( WSCvslider, WSNdragInterval,WSCushort,_dragInterval, 30);
WSMFproperty( WSCvslider, WSNvalue,short,_value, 0);
WSMFproperty( WSCvslider, WSNorientation, WSCuchar, _orientation, WS_HORIZONTAL);

void WSCvslider::setWorkWSNshadowThickness(WSCuchar) { }
void WSCvslider::getWorkWSNshadowThickness(WSCuchar*) { }
void WSCvslider::setWorkWSNbackColor(short) { }
void WSCvslider::getWorkWSNbackColor(short*) { }
void WSCvslider::setWorkWSNtopShadowColor(short) { }
void WSCvslider::getWorkWSNtopShadowColor(short*) { }
void WSCvslider::setWorkWSNbottomShadowColor(short) { }
void WSCvslider::getWorkWSNbottomShadowColor(short*) { }
void WSCvslider::setWorkWSNsliderSize(WSCushort) { }
void WSCvslider::getWorkWSNsliderSize(WSCushort*) { }
void WSCvslider::setWorkWSNmaximum(short) { }
void WSCvslider::getWorkWSNmaximum(short*) { }
void WSCvslider::setWorkWSNminimum(short) { }
void WSCvslider::getWorkWSNminimum(short*) { }
void WSCvslider::setWorkWSNdragInterval(WSCushort) { }
void WSCvslider::getWorkWSNdragInterval(WSCushort*) { }

void WSCvslider::setWorkWSNvalue(short) {
  if (_value < _minimum ){
    _value = _minimum;
  }
  if (_maximum < _value){
    _value = _maximum;
  }
  if (getInitialized() != False){
    onValueChange();
  }
}

void WSCvslider::getWorkWSNvalue(short* val) {
  if (*val <_minimum){
    *val = _minimum;
    _value = _minimum;
  }
  if ( _maximum < *val){
    *val = _maximum;
    _value = _maximum;
  }
}

void WSCvslider::setWorkWSNorientation(WSCuchar) { }
void WSCvslider::getWorkWSNorientation(WSCuchar*) { }

long WSCvslider::_device_initialize() {
  WSDdev* dev = getowndev();
  if (dev == NULL) {
    return WS_ERR;
  }

  dev->setEnableEvent(WSEV_MOUSE_MOVE);
  dev->setEnableEvent(WSEV_MOUSE_OUT);
  dev->setEnableEvent(WSEV_MOUSE_PRESS);
  dev->setEnableEvent(WSEV_MOUSE_RELEASE);

  WSCnwbase::_device_initialize();

  char fl = True;
  dev->setValue(WSDEV_USE_PIXMAP, &fl);

  return WS_NO_ERR;
}

void WSCvslider::_timer_work(WSCuchar clock, void* data) {
  WSCvslider* obj = (WSCvslider*)data;

  if (obj->_timer_on == False) {
    obj->_timer_on = True;
    obj->_clock_bk = clock;
    return;
  }
  long val_bk = obj->_value;

  //moving after 0.5 second...
  if (clock - obj->_clock_bk > 2) {
    if (obj->_bar_status == WS_INTER1) {
      obj->_value -= obj->_dragInterval;
      if (obj->_value < obj->_minimum) {
        obj->_value = obj->_minimum;
      }
      obj->onDragInterval();
    } else
    if (obj->_bar_status == WS_INTER2) {
      obj->_value += obj->_dragInterval;
      if (obj->_value > obj->_maximum) {
        obj->_value = obj->_maximum;
      }
      obj->onDragInterval();
    }

    if (val_bk != obj->_value){
      obj->onValueChange();
      obj->setAbsoluteDraw(True);
      obj->draw();
    }
  }
}

long WSCvslider::execEventProc(long ev,void* data) {
  short x = _x;
  short y = _y;

  if (ev == WSEV_MOUSE_PRESS) {
    WSCpoint* point = (WSCpoint*)data;
    _btn_x_bk = point->x - x;
    _btn_y_bk = point->y - y;
  }
  return WSCnwbase::execEventProc(ev,data);
}

void WSCvslider::onMousePress(WSCpoint* point) {
  _out_side_mouse_move = True;
  _out_side_mouse_release = True;
  short max = _maximum;
  short min = _minimum;

  WSCushort w = _w;
  WSCushort h = _h;

  _bar_status =  _bar_in(point->x, point->y, 0, 0, w ,h, _shadow_thick);

  long val_bk = _value;

  if (_bar_status == WS_BAR) {
    _value_bk = _value;
  } else
  if (_bar_status == WS_INTER1 || _bar_status == WS_INTER2) {
    if (_bar_status == WS_INTER1) {
      _value -= _dragInterval;
      if (_value < min) {
        _value = min;
      }
    } else
    if (_bar_status == WS_INTER2) {
      _value += _dragInterval;
      if (_value > max) {
        _value = max;
      }
    }
    onDragInterval();
    _timer_on = False;
    _timer_id = WSGIappTimer()->addTimerProc(_timer_work,WS250MS,this);
  }

  if (_bar_status  != 0 ) {
    WSDdev* dev = getowndev();
    if (dev == NULL) {
      return;
    }
    if (val_bk != _value){
      onValueChange();
      setAbsoluteDraw(True);
      draw();
    }
  }
  WSCnwbase::onMousePress(point);
}

void WSCvslider::onMouseRelease(WSCpoint*) {
  _out_side_mouse_move = False;
  _out_side_mouse_release = False;
  if (_timer_id != 0) {
    _timer_on = False;
    WSGIappTimer()->delTimerProc(_timer_id);
    _timer_id = 0;
  }
  if (_bar_status != WS_OVER){
    onActivate();
  }
  _bar_status = WS_OVER;
  setAbsoluteDraw(True);
  draw();
}

void WSCvslider::onMouseMove(WSCpoint* point) {
  long val_bk = _value;
  if (_bar_status == WS_BAR) {
    WSCushort w = _w;
    WSCushort h = _h;

    WSCushort sw;
    short pt;
    double dt;

    if (_orientation == WS_HORIZONTAL) {
      sw = w - _shadow_thick * 2 - _slider_size;
      pt = point->x - _btn_x_bk;
    } else {
      sw = h - _shadow_thick * 2 - _slider_size;
      pt = point->y - _btn_y_bk;
    }

    dt = (double)((_maximum - _minimum)) / (double)(sw);

    if ( _bar_status == WS_BAR ) {
      _value = (short)(_value_bk + (double)(pt * dt));
      if ( _value > _maximum) {
        _value = _maximum;
      } else
      if (_value < _minimum) {
        _value = _minimum;
      }
      if (val_bk != _value){
        onValueChange();
        setAbsoluteDraw(True);
        draw();
      }
    }
  }
}
void WSCvslider::onActivate() {
  execProcedure(WSEV_ACTIVATE);
}
void WSCvslider::onValueChange() {
  execProcedure(WSEV_VALUE_CH);
}

void WSCvslider::onDragInterval() {
/*  execProcedure(WSEV_VALUE_CH);*/
}


long WSCvslider::draw() {
  if (getVisible() == False) {
    return WS_NO_ERR;
  }

  WSDdev* dev = getowndev();
  if (dev == NULL) {
    return WS_ERR;
  }

  short x = _x;
  short y = _y;
  WSCushort w = _w;
  WSCushort h = _h;

  WSCbool absolute = getAbsoluteDraw();
  if (absolute == True) {

  }else
  if (dev->isExposed(x, y, w, h) == False) {
    return WS_NO_ERR;
  }
  long err = dev->beginDraw(x, y, w, h, absolute);
  if (err != WS_NO_ERR) {
    return WS_NO_ERR;
  }

  WSCbase::update();
  setAbsoluteDraw(False);

  WSCushort st = _shadow_thick;
  x =0;
  y =0;
  short xx, yy;
  WSCushort ww, hh;
  short bg = _bg_no;
  short ts = _ts_no;
  short bs =  _bs_no;
  WSCushort sz = _slider_size;
  double max = (double)_maximum;
  double min = (double)_minimum;
  double val = (double)_value;

  double dt = 0;
  if(max - min > 0){
    dt = (val - min) / (max - min);
  }

  WSGFdrawShadow(dev, WS_SHADOW_IN, st, bg, ts, bs, bg,x, y, w, h);
  xx = x + st;
  yy = y + st;
  ww = w - st * 2;
  hh = h - st * 2;
  dev->setForeColor(bg);
  dev->drawFillRect(xx, yy, ww, hh);


  if (_orientation == WS_HORIZONTAL) {
    if (w > 2 + st * 2) {
      dt *= (double)(w - st * 2 - sz);
      dev->setForeColor(bg);
      xx = x + st + (short)(dt);
      yy = y + st;
      ww = sz;
      hh = h - st * 2;
      dev->drawFillRect(xx, yy, ww, hh);
      ww /= 2;
      WSGFdrawShadow(dev, WS_SHADOW_OUT, st, bg, ts, bs, bg,xx, yy, ww, hh);
      xx += ww;
      WSGFdrawShadow(dev, WS_SHADOW_OUT, st, bg, ts, bs, bg,xx, yy, ww, hh);
    }
  } else {
    if (h > 2  + st*2) {
      dt *= (double)(h - st * 2 - sz);
      dev->setForeColor(bg);
      xx = x + st;
      yy = y + st + (short)(dt);
      ww = w - st * 2,
      hh = sz;
      dev->drawFillRect(xx, yy, ww, hh);
      hh /= 2;
      WSGFdrawShadow(dev, WS_SHADOW_OUT, st, bg, ts, bs, bg,xx, yy, ww, hh);
      yy += hh;
      WSGFdrawShadow(dev, WS_SHADOW_OUT, st, bg, ts, bs, bg,xx, yy, ww, hh);
    }
  }
  dev->endDraw();
  return WS_NO_ERR;
}
long WSCvslider::_bar_in(short px,short py, short x,short y, 
                         WSCushort w,WSCushort h, WSCushort st) {

  short value = _value;
  if (value < _minimum){
    value = _minimum;
  }
  if (_maximum < _value){
    value = _maximum;
  }
  double val = (double)value;
  WSCushort sz = _slider_size;
  double max = (double)_maximum;
  double min = (double)_minimum;
  double dt = (val - min) / (max - min);

  short x1, x2, x3, x4;
  short y1, y2, y3, y4;

  if (_orientation == WS_HORIZONTAL) {
    if (w > 2 + st * 2) {
      dt *= (w - st * 2 - sz);
      x1 = x + st;
      x2 = x1 + (short)(dt);
      x3 = x2 + sz;
      x4 = x + w;
      y1 = y + st;
      y2 = y + h - st;
      if (x1 < px && px < x2 && y1 < py && y2 > py) {
        return WS_INTER1;
      }
      if (x2 < px && x3 > px && y1 < py && y2 > py) {
        return WS_BAR;
      }
      if (x3 < px && x4 > px && y1 < py && y2 > py) {
        return WS_INTER2;
      } 
    }
  } else {
    if (h > 2 + st * 2) {
      dt *= (h - st * 2 - sz);
      y1 = y + st;
      y2 = y1 + (short)(dt);
      y3 = y2 + sz;
      y4 = y + h;
      x1 = x + st;
      x2 = x + w - st;
      if (y1 < py && py < y2 && x1 < px && x2 > px) {
        return WS_INTER1;
      }
      if (y2 < py && y3 > py && x1 < px && x2 > px) {
        return WS_BAR;
      }
      if (y3 < py && py < y4 && x1 < px && x2 > px) {
        return WS_INTER2;
      }
    }
  }
  return WS_OVER;
}
char* WSCvslider::getDefaultProperty(){
  return WSNvalue;
}
