//
// 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 <WSDdev.h>
#include <WSCdevice.h>
#include <WSCbase.h>
#include <WSDdraw.h>
#include <WSDappDev.h>

WSMFclassInit(WSDdev,WSCroot);

WSCushort WSDdev::_w = 0;
WSCushort WSDdev::_h = 0;
WSDdraw* WSDdev::_draw = NULL;
WSDdraw* WSDdev::_native_draw = NULL;

void WSDdev::getGeom(short* ox,short* oy,WSCushort* ow,WSCushort* oh){
  *ox = _x;
  *oy = _y;
  *ow = _w;
  *oh = _h;
}

WSDdev::WSDdev(){
  _client = NULL;
  _addr_change_handler = 0;
  _handler_data = NULL;
  _scale_ptr = NULL;
  _x_offset_ptr = NULL;
  _y_offset_ptr = NULL;
  _absolute_draw = False;
  _no_child = False;
  _parent_dev = NULL;
  _event_parent_dev = NULL;
  _registered = False;
  _event_mask = 0;
  _x = 0;
  _y = 0;
  _deleted = 0;
  _visible = 0;
  setInitialized(0);
}

WSDdev::~WSDdev(){
  detachClient();
  setInitialized(False);
}

WSCbool WSDdev::getNoChildDev(){
  return _no_child;
}

void WSDdev::setEventMaskBit(long mask){
  _event_mask = mask;
}

long WSDdev::getEventMaskBit(){
  return _event_mask;
}

long WSDdev::setAbsoluteAddrChangeHandler(void(*hd)(WSDdev*,void*),void* data){
  _handler_data = data;
  _addr_change_handler = hd;
  return WS_NO_ERR;
}

WSCbool WSDdev::getEventRegistered(){
  return _registered;
}

void WSDdev::setEventRegistered(WSCbool fl){
  if (fl != False){
    fl = True;
  }else{
    setEventMaskBit(0);
  }
  _registered = fl;
}

WSCbool WSDdev::getReady(){
  return False;
}

void WSDdev::setScalePtr(double* ptr){
  _scale_ptr = ptr;
}

void WSDdev::setXOffsetPtr(short* ptr){
  _x_offset_ptr = ptr;
}

void WSDdev::setYOffsetPtr(short* ptr){
  _y_offset_ptr = ptr;
}

double WSDdev::getScale(){
  if (_scale_ptr == NULL){
    return (double)1;
  }
  return *_scale_ptr; 
}

short WSDdev::getXOffset(){
  if (_x_offset_ptr == NULL){
    return 0;
  }
  return *_x_offset_ptr; 
}

short WSDdev::getYOffset(){
  if (_y_offset_ptr == NULL){
    return 0;
  }
  return *_y_offset_ptr; 
}

long WSDdev::setValue(long kind ,void* data){
  switch(kind){
    case WSDEV_SCALE_OFFSET:
             setScalePtr((double*)data);
             break;
    case WSDEV_X_OFFSET:
             setXOffsetPtr((short*)data);
             break;
    case WSDEV_Y_OFFSET:
             setYOffsetPtr((short*)data);
             break;
  }
  return WS_NO_ERR;
}

long WSDdev::getValue(long /*kind*/,void* /*value*/){
  return WS_NO_ERR;
}

long WSDdev::getAvailableEventBit(){
  return 0;
}

WSCbool WSDdev::isAvailableEvent(long /*ev*/){
  return False;
}

long WSDdev::setDisableEvent(long /*ev*/){
  return WS_NO_ERR;
}

long WSDdev::setEventOrder(WSDdev*,char /*top_or_bottom*/){
  return WS_NO_ERR;
}

long WSDdev::setEvent(WSDdev*,WSCbool /*on_off*/){
  return WS_NO_ERR;
}

long WSDdev::execEvent(long /*ev*/,void* /*data*/){
  return WS_NO_ERR;
}

WSCbool WSDdev::isExposed(short x,short y,WSCushort w,WSCushort h,WSCbool scaling){
  if (scaling != False){
    x = (short)((x + getXOffset()) * getScale());
    y = (short)((y + getYOffset()) * getScale());
    w = (WSCushort)(w * getScale());
    h = (WSCushort)(h * getScale());
  }

  short ex,ey;
  WSCushort ew,eh;
  getExposedArea(&ex,&ey,&ew,&eh,False);
  if (x + w < ex || y + h < ey || x > ex + ew || y > ey + eh ){
    return False;
  }
  return True;
}

long WSDdev::informEventToClient(long ev_kind,void* data){
  if (_client == NULL){
    return WS_ERR;
  }
  if (_client->getVisible() == False){
    return WS_ERR;
  }
  if (ev_kind == WSEV_EXPOSE){  
    return _client->execEventProc(ev_kind,data);
  }

  WSCbase* mcl = WSGIappDev()->getModalClient();
  if (mcl != NULL && mcl != _client && ev_kind != WSEV_RESIZE){
//WSMFtrace("WSDdev::informEventToClient modal\n");
    void(*proc)(WSDdev*,long,void*) = (void(*)(WSDdev*,long,void*))WSGIappDev()->getModalProc();
    WSCbase* cl = _client->getParent();
    if (cl == NULL){
      if (proc != NULL){
        proc(this,ev_kind,data);
        return WS_NO_ERR;
      }
      return WS_ERR;
    }
    long fl = False;
    while(1){
      if (cl == mcl){
        fl = True;
        break;
      }
      cl = cl->getParent();
      if (cl == NULL){
        break;
      }
    }
    if (fl == False){
      if (proc != NULL){
        proc(this,ev_kind,data);
        return WS_NO_ERR;
      }
      return WS_ERR;
    }
  }

  if (ev_kind == WSEV_MOUSE_IN || ev_kind == WSEV_MOUSE_MOVE ||
            ev_kind == WSEV_MOUSE_PRESS || ev_kind == WSEV_MOUSE_RELEASE){
     WSCpoint point;
     WSCpoint* src = (WSCpoint*)data;
     double scale = getScale();
     if (scale != 1){
       point.setPoint((short)(src->x / scale) - getXOffset(),(short)(src->y / scale) - getYOffset()); 
     }else{
       point.setPoint(src->x - getXOffset(),src->y - getYOffset()); 
     }
     if (_client->getSensitive() != False || _client->getPropertyEditMode() != False){
       _client->execEventProc(ev_kind,&point);
     }
     return WS_ERR;
  }
  return  _client->execEventProc(ev_kind,data);
}

void WSDdev::setInitialized(WSCbool fl){
   _initialized = fl;
}

WSCbool WSDdev::getInitialized(){
   return  _initialized;
}

long WSDdev::attachClient(WSCbase* client){
   if (_client != NULL){
     detachClient();
   }

   _x_offset_ptr = NULL;
   _y_offset_ptr = NULL;
   _scale_ptr = NULL;

   _client = client;

   if (getInitialized() == False){
     initialize();
     setInitialized(True);
   }
   return WS_NO_ERR;
}

long WSDdev::initialize(){
  setInitialized(True);
  return WS_NO_ERR;
}

long WSDdev::cancelEvent(WSDdev* dev){
  if (dev == this){
    setEventRegistered(False);
  }
  WSDdev* pdev = getEventParentDev();
  if ( pdev != NULL ){
    pdev->cancelEvent(this);
  }
  return WS_NO_ERR;
}

long WSDdev::detachClient(){
   if (_client == NULL){
     return WS_NO_ERR;
   }
   setVisible(False);
   cancelEvent(this);
   _addr_change_handler = NULL;
   _handler_data = NULL;

   _client = NULL;
   _parent_dev = NULL;
   _event_parent_dev = NULL;

   return WS_NO_ERR;
}

WSCbool WSDdev::getVisible(){
   return _visible;
}
long WSDdev::setVisible(WSCbool fl){
  _visible = fl;
  if (fl != False && getInitialized() == False){
    initialize();
    setInitialized(True);
  }
  return WS_NO_ERR;
}


long  WSDdev::setDraw(WSDdraw*  draw){
  _draw = draw;
  if (_native_draw == NULL){
    _native_draw = draw;
  }
  return WS_NO_ERR;
}
WSDdraw* WSDdev::getDraw(){
  return _draw;
}
long  WSDdev::setNativeDraw(WSDdraw*  draw){
  _native_draw = draw;
  return WS_NO_ERR;
}
WSDdraw* WSDdev::getNativeDraw(){
  return _native_draw;
}

long WSDdev::beginDraw(short x,short y,WSCushort w,WSCushort h,WSCbool absolute,WSCbool scaling){
  _absolute_draw = absolute;
  if (scaling != False){
    x = (short)((x + getXOffset())*getScale());
    y = (short)((y + getYOffset())*getScale());
    w = (WSCushort)(w * getScale());
    h = (WSCushort)(h * getScale());
  }

  WSDdev* pdev = getParentDev();
  if ( pdev != NULL ){
      pdev->beginDraw( x, y, w, h,absolute,False);
  } 

  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }

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

  short ex,ey;
  WSCushort ew,eh;
  long ret = getExposedArea(&ex,&ey,&ew,&eh,False);
  if (ret != WS_NO_ERR){
    return WS_ERR;
  }

  if (getReady() == False){
    return WS_ERR;
  }
  draw->beginDraw(this,getDeviceResource(),getWindowResource(),getContextResource());

  short ex2 = ex + ew < x + w ? ex + ew : x + w; 
  short ey2 = ey + eh < y + h ? ey + eh : y + h; 
  ex = ex > x ? ex : x; 
  ey = ey > y ? ey : y; 
  ew = ex2 - ex;
  eh = ey2 - ey;

  if (absolute == False){
    draw->setRegion(ex,ey,ew,eh);
  }else{
    draw->setRegion(x,y,w,h);
  }

  return WS_NO_ERR;
}
long WSDdev::endDraw(){
  _absolute_draw = False;
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->endDraw();
  WSDdev* pdev = getParentDev();
  if ( pdev != NULL ){
    pdev->endDraw();
  } 
  return WS_NO_ERR;
}

long WSDdev::setLineWidth(short w){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setLineWidth(w);
  return WS_NO_ERR;
}

long WSDdev::setLineDashType(char type){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setLineDashType(type);
  return WS_NO_ERR;
}

long WSDdev::setHatchPattern(char type){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setHatchPattern(type);
  return WS_NO_ERR;
}

long WSDdev::setForeColor(short no){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setForeColor(no);
  return WS_NO_ERR;
}

long WSDdev::setBackColor(short no){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setBackColor(no);
  return WS_NO_ERR;
}
long WSDdev::setForeColor(WSDcolor* col){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setForeColor(col);
  return WS_NO_ERR;
}

long WSDdev::setBackColor(WSDcolor* col){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  draw->setBackColor(col);
  return WS_NO_ERR;
}

long WSDdev::drawArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawArc((short)(x * scale) +_x, 
                  (short)(y * scale) +_y,
                  (WSCushort)(w * scale), 
                  (WSCushort)(h * scale), a1, a2);
  }else{
    draw->drawArc(x +_x, y +_y, w , h , a1, a2);
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2,char kind){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }

  double scale = getScale();
  if (scale != 1){
    draw->drawFillArc((short)(x * scale) +_x, 
                      (short)(y * scale) +_y,
                      (WSCushort)(w * scale), 
                      (WSCushort)(h * scale), a1, a2,kind);
  }else{
    draw->drawFillArc(x +_x, y +_y, w , h , a1, a2,kind);
  }
  return WS_NO_ERR;
}

long WSDdev::drawLines(WSCpoint* points,long num){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }

  WSCpoint  p1[16];
  WSCpoint* pt;
  if (num > 16){
    pt = new WSCpoint[num];
  }else{
    pt = p1;
  }

  long i;
  double scale = getScale();
  if (scale != 1){
    for(i = 0; i < num; i++){
      pt[i].x = (short)(points[i].x * scale) +_x;
      pt[i].y = (short)(points[i].y * scale) +_y;
    };
  }else{
    for(i = 0; i < num; i++){
      pt[i].x = points[i].x +_x;
      pt[i].y = points[i].y +_y;
    };
  }
  draw->drawLines(pt,num);
  if (num > 16){
    delete pt;
  }
  return WS_NO_ERR;
}

long WSDdev::drawLine(short x1,short y1,short x2,short y2){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }

  double scale = getScale();
  if (scale != 1){
    draw->drawLine((short)(x1 * scale) +_x, (short)(y1 * scale) +_y,
                   (WSCushort)(x2 * scale) +_x,
                   (WSCushort)(y2 * scale) +_y);
  }else{
    draw->drawLine(x1 +_x, y1 +_y, x2 +_x, y2 +_y);
  }
  return WS_NO_ERR;
}

long WSDdev::drawRect(short x,short y,WSCushort w,WSCushort h){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawRect((short)(x * scale) +_x, (short)(y * scale) +_y,
                   (WSCushort)(w * scale),
                   (WSCushort)(h * scale));
  }else{
    draw->drawRect(x +_x, y +_y,w,h);
  }
  return WS_NO_ERR;
}
long WSDdev::drawFillRect(short x,short y,WSCushort w,WSCushort h){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawFillRect((short)(x * scale) +_x, (short)(y * scale) +_y,
                       (WSCushort)(w * scale),
                       (WSCushort)(h * scale));
  }else{
    draw->drawFillRect(x+_x,y+_y,w,h);
  }
  return WS_NO_ERR;
}
long WSDdev::drawGradation(long type,short col1,short col2,short col3,
                   short x,short y,WSCushort w,WSCushort h,WSCuchar gradm){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawGradation(type,col1,col2,col3,
                       (short)(x * scale) +_x, (short)(y * scale) +_y,
                       (WSCushort)(w * scale),
                       (WSCushort)(h * scale),gradm);
  }else{
    draw->drawGradation(type,col1,col2,col3,x+_x,y+_y,w,h,gradm);
  }
  return WS_NO_ERR;
}



long WSDdev::exposeArea(long x,long y,WSCulong w,WSCulong h,WSCbool scaling){
  return WS_NO_ERR;
}
long WSDdev::clearArea(long x,long y,WSCulong w,WSCulong h,WSCbool create_event,WSCbool scaling){
  return WS_NO_ERR;
}
long WSDdev::copyArea(long x,long y,WSCulong w,WSCulong h,long dx,long dy){
#if 0
  WSDdev* pdev = getEventParentDev();
  if ( pdev != NULL ){

    double scale = getScale();
    if (scaling != False && scale != 1){
        pdev->clearArea((short)(x * scale) +_x,(short)(y * scale) +_y,
                      (WSCushort)(w * scale), (WSCushort)(h * scale),
                      (short)(dx * scale) +_x,(short)(dy * scale) +_y);
    }else{
      pdev->clearArea(x + _x,y + _y, w, h, dx + _x, dy + _y);
    }
  }
#endif
  return WS_NO_ERR;
}

void WSDdev::setExposedArea(short,short,WSCushort,WSCushort){
}

long WSDdev::setEnableEventBit(long /*ev_bit*/){
  setEventRegistered(True);
  return WS_NO_ERR;
}

long WSDdev::setEnableEvent(long /*ev_kind*/){
  setEventRegistered(True);
  return WS_NO_ERR;
}

long WSDdev::drawRects(WSCrect* rects,long num){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  WSCrect  r1[16];
  WSCrect* rt;
  if (num > 16){
    rt = new WSCrect[num];
  }else{
    rt = r1;
  }

  long i;
  double scale = getScale();
  if (scale != 1){
    for(i = 0; i < num; i++){
      rt[i].x = (short)(rects[i].x * scale) +_x;
      rt[i].y = (short)(rects[i].y * scale) +_y;
      rt[i].width = (WSCushort)(rects[i].width * scale);
      rt[i].height = (WSCushort)(rects[i].height * scale);
    };
  }else{
    for(i = 0; i < num; i++){
      rt[i].x = rects[i].x +_x;
      rt[i].y = rects[i].y +_y;
      rt[i].width = rects[i].width;
      rt[i].height = rects[i].height;
    };
  }
  draw->drawRects(rt,num);
  if (num > 16){
    delete rt;
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillRects(WSCrect* rects,long num){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  WSCrect  r1[16];
  WSCrect* rt;
  if (num > 16){
    rt = new WSCrect[num];
  }else{
    rt = r1;
  }
  long i;
  double scale = getScale();
  if (scale != 1){
    for(i = 0; i < num; i++){
      rt[i].x = (short)(rects[i].x * scale) +_x;
      rt[i].y = (short)(rects[i].y * scale) +_y;
      rt[i].width = (WSCushort)(rects[i].width * scale);
      rt[i].height = (WSCushort)(rects[i].height * scale);
    };
  }else{
    for(i = 0; i < num; i++){
      rt[i].x = rects[i].x +_x;
      rt[i].y = rects[i].y +_y;
      rt[i].width = rects[i].width;
      rt[i].height = rects[i].height;
    };
  }
  draw->drawFillRects(rt,num);
  if (num > 16){
    delete rt;
  }
  return WS_NO_ERR;
}

long WSDdev::drawPoly(WSCpoint* points,long num){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  WSCpoint  p1[16];
  WSCpoint* pt;
  if (num > 16){
    pt = new WSCpoint[num];
  }else{
    pt = p1;
  }
  long i;
  double scale = getScale();
  if (scale != 1){
    for(i = 0; i < num; i++){
      pt[i].x = (short)(points[i].x * scale) +_x;
      pt[i].y = (short)(points[i].y * scale) +_y;
    };
  }else{
    for(i = 0; i < num; i++){
      pt[i].x = points[i].x +_x;
      pt[i].y = points[i].y +_y;
    };
  }
  draw->drawPoly(pt,num);
  if (num > 16){
    delete pt;
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillPoly(WSCpoint* points,long num){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  WSCpoint  p1[16];
  WSCpoint* pt;
  if (num > 16){
    pt = new WSCpoint[num];
  }else{
    pt = p1;
  }

  long i;
  double scale = getScale();
  if (scale != 1){
    for(i = 0; i < num; i++){
      pt[i].x = (short)(points[i].x * scale) +_x;
      pt[i].y = (short)(points[i].y * scale) +_y;
    }
  }else{
    for(i = 0; i < num; i++){
      pt[i].x = points[i].x +_x;
      pt[i].y = points[i].y +_y;
    }
  }
  draw->drawFillPoly(pt,num);
  if (num > 16){
    delete pt;
  }
  return WS_NO_ERR;
}

long WSDdev::drawImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image,char align){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawImage( (short)(x * scale) +_x,
                     (short)(y * scale) +_y,
                     (WSCushort)(w * scale),
                     (WSCushort)(h * scale),image,align);
  }else{
    draw->drawImage(x+_x,y+_y,w,h,image,align);
  }
  return WS_NO_ERR;
}
long WSDdev::drawImage(short x,short y,short sx,short sy,WSCushort w,WSCushort h,WSDimage* image){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawImage( (short)(x * scale) +_x,
                     (short)(y * scale) +_y,
                     sx,sy,
                     (WSCushort)(w * scale),
                     (WSCushort)(h * scale),image);
  }else{
    draw->drawImage(x+_x,y+_y,sx,sy,w,h,image);
  }
  return WS_NO_ERR;
}
long WSDdev::drawStretchedImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawStretchedImage( (short)(x * scale) +_x,
                     (short)(y * scale) +_y,
                     (WSCushort)(w * scale),
                     (WSCushort)(h * scale),image);
  }else{
    draw->drawStretchedImage(x+_x,y+_y,w,h,image);
  }
  return WS_NO_ERR;
}

long WSDdev::drawString(long x,long y,WSCulong w,WSCulong h,WSCstring* str,char font,char align,long cur,WSCbool inter_cur,long spos1,long spos2){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawString( (long)(x * scale) +_x, 
                      (long)(y * scale) +_y,
                      (WSCulong)(w * scale), 
                      (WSCulong)(h * scale),
                      str,font,align,cur,inter_cur,
                      spos1,spos2);
  }else{
    draw->drawString(x+_x,y+_y,w,h,str,font,align,cur,inter_cur,spos1,spos2);
  }
  return WS_NO_ERR;
}

long WSDdev::drawString(long x,long y,WSCulong w,WSCulong h,char font,char align,char* str,long encoding){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  WSCstring tmp;
  tmp.setString(str,encoding);
  if (scale != 1){
    draw->drawString( (long)(x * scale) +_x, 
                      (long)(y * scale) +_y,
                      (WSCulong)(w * scale), 
                      (WSCulong)(h * scale),
                      &tmp,font,align,-1,False,0,0);
  }else{
    draw->drawString(x+_x,y+_y,w,h,&tmp,font,align,-1,False,0,0);
  }
  return WS_NO_ERR;
}

long WSDdev::drawUString(long x,long y,WSCulong w,WSCulong h,WSCushort* str,char font,char align,long cur,WSCbool inter_cur,long spos1,long spos2){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawUString( (long)(x * scale) +_x, 
                      (long)(y * scale) +_y,
                      (WSCulong)(w * scale), 
                      (WSCulong)(h * scale),
                      str,font,align,cur,inter_cur,
                      spos1,spos2);
  }else{
    draw->drawUString(x+_x,y+_y,w,h,str,font,align,cur,inter_cur,spos1,spos2);
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillString(long x,long y,WSCulong w,WSCulong h,WSCstring* str,char font,char align,long cur,WSCbool inter_cur){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawFillString( (long)(x * scale) +_x, 
                          (long)(y * scale) +_y,
                          (WSCulong)(w * scale), 
                          (WSCulong)(h * scale),
                          str,font,align,cur,inter_cur);
  }else{
    draw->drawFillString(x+_x,y+_y,w,h,str,font,align,cur,inter_cur);
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillString(long x,long y,WSCulong w,WSCulong h,char font,char align,char* str,long encoding){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  WSCstring tmp;
  tmp.setString(str,encoding);
  double scale = getScale();
  if (scale != 1){
    draw->drawFillString( (long)(x * scale) +_x, 
                          (long)(y * scale) +_y,
                          (WSCulong)(w * scale), 
                          (WSCulong)(h * scale),
                          &tmp,font,align,-1,False);
  }else{
    draw->drawFillString(x+_x,y+_y,w,h,&tmp,font,align,-1,False);
  }
  return WS_NO_ERR;
}

long WSDdev::drawFillUString(long x,long y,WSCulong w,WSCulong h,WSCushort* str,char font,char align,long cur,WSCbool inter_cur){
  WSDdraw* draw = getDraw();
  if (draw == NULL){
    return WS_ERR;
  }
  double scale = getScale();
  if (scale != 1){
    draw->drawFillUString( (long)(x * scale) +_x, 
                          (long)(y * scale) +_y,
                          (WSCulong)(w * scale), 
                          (WSCulong)(h * scale),
                          str,font,align,cur,inter_cur);
  }else{
    draw->drawFillUString(x+_x,y+_y,w,h,str,font,align,cur,inter_cur);
  }
  return WS_NO_ERR;
}

long WSDdev::setRegion(short x,short y,WSCushort w, WSCushort h){
  WSDdraw* draw = getDraw();
  double scale = getScale();

  short ex,ey;
  WSCushort ew,eh;
  long ret = getExposedArea(&ex,&ey,&ew,&eh,False);
  if (ret != WS_NO_ERR){
    return WS_ERR;
  }

  long ox,oy;
  WSCulong ow,oh;
  WSGFandArea(x,y,w,h,ex,ey,ew,eh,&ox,&oy,&ow,&oh);

  if (_absolute_draw == False){
    x = ox;
    y = oy;
    w = ow;
    h = oh;
  }

  if (scale != 1){
    draw->setRegion( (short)(x * scale) +_x,(short)(y * scale) +_y,
                     (WSCushort)(w * scale),
                     (WSCushort)(h * scale));
  }else{
    draw->setRegion(x+_x,y+_y,w,h);
  }
  return WS_NO_ERR;
}

long WSDdev::getExposedArea(short* x,short* y, WSCushort* w, WSCushort* h,WSCbool scaling){
  WSDdev* dev = getEventParentDev();
  if (dev != NULL){
      dev->getExposedArea(x,y,w,h,False);
      if (scaling != False){
        double scale = getScale();
        if (scale != 1){
          *x = (short)(*x / scale) - getXOffset();
          *y = (short)(*y / scale) - getYOffset();
          *w = (WSCushort)(*w / scale);
          *h = (WSCushort)(*h / scale);
        }else{
          *x = *x  - getXOffset();
          *y = *y  - getYOffset();
          *w = *w;
          *h = *h;
        }
      }
      return WS_NO_ERR;
  }else{
      return WS_ERR;
  }
}

void WSDdev::setParentDev(WSDdev* dev){
  _parent_dev = dev;
}
void WSDdev::setEventParentDev(WSDdev* dev){
  _event_parent_dev = dev;
}
WSDdev* WSDdev::getVisibleParentDev(){
  return _parent_dev;
}

WSDdev* WSDdev::getEventParentDev(){
  if (_event_parent_dev == NULL){
    _event_parent_dev = _parent_dev;
  }
  return _event_parent_dev;
}

WSDdev* WSDdev::getParentDev(){
  if (_parent_dev != NULL){
    return _parent_dev;
  }

  if (_client == NULL){
    return NULL;
  }
  _parent_dev = _client->getParentDev();
//  if (_parent_dev == this){
//    assert(0);
//  }
  return _parent_dev;
}

WSCbase* WSDdev::getAttachedClient(){
  return _client;
}

void WSDdev::getDispAddr(short* ox,short* oy){
   *ox = 0;
   *oy = 0;
   return;
}

void WSDdev::getAbsoluteAddr(short x,short y,short* ox,short* oy){
  *ox = (short)((x + getXOffset()) * getScale());
  *oy = (short)((y + getYOffset()) * getScale());
}

WSCbool WSDdev::getAttached(){
  if (getAttachedClient() == NULL){
    return False;
  }
  return True;
}

#if 0
void WSDdev::setDependDev(WSDdev*){
}

WSDdev* WSDdev::getDependDev(){
  return NULL;
}

WSCbool WSDdev::isIndependent(){
  return True;
}
#endif

void WSDdev::deleteInstance(){
  if (_deleted == 0){
    WSGIappDevice()->addDeleteInstance(this);
    detachClient();
    setInitialized(False);
  }
  _deleted = 1;
}
void WSDdev::getWH(WSCushort* w,WSCushort* h){
  *w = _w;
  *h = _h;
}
