//
// Copyright (C) 1999-2002 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 <nx/WSDnxAppDev.h>
#include <nx/WSDnxDraw.h>
#include <WSCbase.h>
#include <WSDfont.h>
#include <WSCfontSet.h>
#include <WSDcolor.h>
#include <WSCcolorSet.h>
#include <WSDimage.h>
#include <WSCimageSet.h>
#include <WSCstring.h>
#include <WSClocaleSet.h>

#define MEMGID
//#define F_MEMGID

//#define TDBG

WSMFclassInit(WSDnxDraw,WSCroot);
 

static WSCuchar _hatch_pattern1[] = {0x03, 0, 0x03, 0, 0x0c, 0, 0x0c, 0, 0x30, 0, 0x30, 0, 0xc0, 0, 0xc0};
static WSCuchar _hatch_pattern2[] = {0xc0, 0, 0xc0, 0, 0x30, 0, 0x30, 0, 0x0c, 0, 0x0c, 0, 0x03, 0, 0x03};
static WSCuchar _hatch_pattern3[] = {0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc, 0, 0xcc};
static WSCuchar _hatch_pattern4[] = {0xff, 0, 0xff, 0, 0x00, 0, 0x00, 0, 0xff, 0, 0xff, 0, 0x00, 0, 0x00};
static WSCuchar _hatch_pattern5[] = {0xcc, 0, 0xcc, 0, 0x33, 0, 0x33, 0, 0xcc, 0, 0xcc, 0, 0x33, 0, 0x33};
static WSCuchar _hatch_pattern6[] = {0xff, 0, 0xff, 0, 0xcc, 0, 0xcc, 0, 0xff, 0, 0xff, 0, 0xcc, 0, 0xcc};
static WSCuchar _hatch_pattern7[] = {0xcc, 0, 0xcc, 0, 0x00, 0, 0x00, 0, 0xcc, 0, 0xcc, 0, 0x00, 0, 0x00};
static WSCuchar _hatch_pattern8[] = {0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa, 0, 0xcc, 0, 0xaa};

WSDnxDraw::WSDnxDraw(){
  _fg_cno = -100;
  _bg_cno = -100;
  _fg_value = 0;
  _bg_value = 0;
  _fg_col = NULL;
  _bg_col = NULL;
  _line_type_val = 0; //TODO set default line type
  _line_width = -1;
  _line_type = -1;
  _clipping = False;
  _fill_mask = 0; // TODO set default fill mask type.
}
WSDnxDraw::~WSDnxDraw(){}

long WSDnxDraw::setForeColor(short cno){
  short ret = _fg_cno;
  if (_fg_cno != cno){
    _fg_col = WSGIappColorSet()->getColor(cno);
    if (_fg_col != NULL){
      _fg_cno = cno;
      _fg_value = (void*)_fg_col->getValue1();
    }
  }else{
    if (_fg_col != NULL){
      _fg_value = (void*)_fg_col->getValue1();
    }
  }
  return (long)ret;
}

long WSDnxDraw::setBackColor(short cno){
  short ret = _bg_cno;
  if (_bg_cno != cno){
    _bg_col = WSGIappColorSet()->getColor(cno);
    if (_bg_col != NULL){
      _bg_cno = cno;
      _bg_value = (void*)_bg_col->getValue1();
    }
  }else{
    if (_bg_col != NULL){
      _bg_value = (void*)_bg_col->getValue1();
    }
  }
  return (long)ret;
}
long WSDnxDraw::setForeColor(WSDcolor* color){
  short bk = _fg_cno;
  if (color == NULL){
    return bk;
  }
  short cno = color->getId();
  if (_fg_cno == cno){
    _fg_value = (void*)color->getValue1();
  }else{
    _fg_col = color;
    _fg_cno = _fg_col->getId();
    _fg_value = (void*)_fg_col->getValue1();
  }
  return bk;
}

long WSDnxDraw::setBackColor(WSDcolor* color){
  short bk = _bg_cno;
  if (color == NULL){
    return bk;
  }
  short cno = color->getId();
  if (_bg_cno == cno){
    _bg_value = (void*)color->getValue1();
  }else{
    _bg_col = color;
    _bg_cno = _bg_col->getId();
    _bg_value = (void*)_bg_col->getValue1();
  }
  return bk;
}
long WSDnxDraw::setLineWidth(short width){
  if (width == 0){
    width = 1;
  }
  if (_line_width == width){
    return _line_width;
  }

  long bk = _line_width;
  _line_width = width;

  long linet = _line_type;
  _line_type = -1; 
  setLineDashType(linet);

  return bk;
}


long WSDnxDraw::setLineDashType(char type){
  if (_line_type == type){
    return type;
  }
  long bk = _line_type;
  _line_type = type;
  switch(type){
    case 0:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 1:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 2:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 3:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 4:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 5:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 6:
      // TODO set line type.
      _line_type_val = 0;
      break;
    case 7:
      // TODO set line type.
      _line_type_val = 0;
       break;
    case 8:
      // TODO set line type.
      _line_type_val = 0;
       break;
    default:
       break;
  }
  return bk;
}
long WSDnxDraw::setHatchPattern(char type){
  if (_fill_type == type){
    return type;
  }
  // TODO set default fill mask type.
  _fill_mask = 0;
  long bk = _fill_type;
  _fill_type = type;
  switch(type){
    case 1:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 2:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 3:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 4:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 5:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 6:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 7:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
    case 8:
      // TODO set fill mask type.
      _fill_mask = 0;
            break;
  }
  return bk;
}
long WSDnxDraw::beginDraw(WSDdev* dev,long val1,long val2,long val3){
  _dev = dev;
  _window = (void*)val2;
  _fdev = (WSDnxFormDev*)dev->cast("WSDnxFormDev");
  short dx=0,dy=0;
  WSCushort dw = 32767,dh = 32767;

  if (_fdev == NULL){
    WSDdev* pdev = dev->getParentDev();
    if (pdev != NULL){
      _fdev = (WSDnxFormDev*)pdev->cast("WSDnxFormDev");
    }
    if (_fdev != NULL){
      _fdev->getAbstSize(&dx,&dy,&dw,&dh);
      _x = -1;
      _y = -1;
      _w = -1;
      _h = -1;
    }
  }else{
    _fdev->getAbstSize(&dx,&dy,&dw,&dh);
    _x = dx;
    _y = dy;
    _w = dw;
    _h = dh;
  }

  if (_context != (void*)val3){
    _context =     (void*)val3;
    _fill_type = -1;
    _fg_cno = WSGFcolor("#000000");
    _fg_col = WSGIappColorSet()->getColor(_fg_cno);
    _fg_value = (void*)_fg_col->getValue1();

    _bg_cno = WSGFcolor("#ffffff");
    _bg_col = WSGIappColorSet()->getColor(_bg_cno);
    _bg_value = (void*)_bg_col->getValue1();
  }
  _line_width = 1;
  _line_type = 0;
  _line_type_val = 0; // TODO set default line type.
  _fill_mask = 0; // TODO set default fill mask type.

  if (_fill_type != 0){
    _fill_type = 0;
  }

  if (_fg_col == NULL){
    _fg_col = WSGIappColorSet()->getColor("#000000");
    if (_fg_col == NULL){
      return WS_ERR;
    }
    _fg_cno = _fg_col->getId();
    _fg_value = (void*)_fg_col->getValue1();
  }
  if (_bg_col == NULL){
    _bg_col = WSGIappColorSet()->getColor("#ffffff");
    if (_bg_col == NULL){
      return WS_ERR;
    }
    _bg_cno = _bg_col->getId();
    _bg_value = (void*)_bg_col->getValue1();
  }

  WSCrect r;
  r.x = 0+dx;
  r.y = 0+dy;
  r.width = dw+dx;
  r.height = dh+dy;
  _clip_x = dx;
  _clip_y = dy;
  _clip_w = dw;
  _clip_h = dw;

  // TODO set visible region to _context

  if (_fdev != NULL){
    _fdev->setDefaultRegion();
  }

  return WS_NO_ERR;
}

long WSDnxDraw::endDraw(){
#ifdef MEMGID
#ifndef F_MEMGID
  if (_dev->cast("WSDnxFormDev") != NULL &&
    _w != -1 && _h != -1 &&
     _fdev != NULL && _fdev->getUseMemContext() != False){

    void* context = _fdev->getParentContext();

    WSCrect from;
    from.x = _x;
    from.y = _y;
    from.width = _w;
    from.height = _h;

    WSCrect to;
    to.x = _x;
    to.y = _y;
    to.width = _w;
    to.height = _h;
    // TODO set visible region to context..

    // TODO bit build from  _context to context..
    return WS_NO_ERR;
  }else{
    if (_dev->cast("WSDnxFormDev") == NULL){
      WSDdev* pdev = _dev->getParentDev();
      if ( pdev != NULL ){
        _dev = pdev; 
        _fdev = (WSDnxFormDev*)_dev->cast("WSDnxFormDev");
      }
    }
  }
#endif
#endif
  return WS_NO_ERR;
}
long WSDnxDraw::setRegion(short x,short y,WSCushort w,WSCushort h){
  WSCrect r;
  r.x = x;
  r.y = y;
  r.width = w;
  r.height = h;
  if (_fdev != NULL){
    short px,py;
    WSCushort pw,ph;
    _fdev->getAbstSize(&px,&py,&pw,&ph);
    short px2,py2;
    _fdev->getAbstPos(&px2,&py2);
    long dx,dy;
    WSCulong dw,dh;
    WSGFandArea(px2 +x, py2 +y,w,h, px,py,pw,ph,&dx,&dy,&dw,&dh);
    r.x = dx;
    r.y = dy;
    r.width = dw;
    r.height = dh;
    _clip_x = dx;
    _clip_y = dy;
    _clip_w = dw;
    _clip_h = dh;
  }else{
    r.x = x;
    r.y = y;
    r.width = w;
    r.height = h;
    _clip_x = x;
    _clip_y = y;
    _clip_w = w;
    _clip_h = h;
  }
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if ( _x == -1 && _y == -1 && _w == -1 && _h == -1){
    _x = _clip_x;
    _y = _clip_y;
    _w = _clip_w;
    _h = _clip_h;
  }
  // TODO set visible region to _context..
  return WS_NO_ERR;
}

long WSDnxDraw::drawArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw arc..

  return WS_NO_ERR;
}
long WSDnxDraw::drawFillArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2,char kind){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw fill arc.
  return WS_NO_ERR;
}
long WSDnxDraw::drawLine(short x1,short y1,short x2,short y2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw line
  return WS_NO_ERR;
}
long WSDnxDraw::drawLines(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw lines..
  return WS_NO_ERR;
}
long WSDnxDraw::drawRect(short x,short y,WSCushort w,WSCushort h){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw rect.

  return WS_NO_ERR;
}
long WSDnxDraw::drawFillRect(short x,short y,WSCushort w,WSCushort h){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw fill rect.
  return WS_NO_ERR;
}
long WSDnxDraw::drawRects(WSCrect* rects,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw rects.
  return WS_NO_ERR;
}

long WSDnxDraw::drawFillRects(WSCrect* rects,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw fill rects.
  return WS_NO_ERR;
}
long WSDnxDraw::drawPoly(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw poly
  return WS_NO_ERR;
}

long WSDnxDraw::drawFillPoly(WSCpoint* points,long num){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  // TODO draw fill poly.
  return WS_NO_ERR;
}

long WSDnxDraw::drawImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image,char align){
dbprintf(">> WSDnxDraw::drawImage start\n");
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  long mem_context1 = image->getValue1();
  long mem_context2 = image->getValue2();
  WSCushort pw = image->getImageWidth();
  WSCushort ph = image->getImageHeight();
  short xoff = 0;
  short yoff = 0;
  if (align == WS_CENTER){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT){
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT_TOP){
    xoff = 0;
    yoff = 0;
  }else
  if (align == WS_TOP){
    xoff = ((short)w - (short)pw)/2;
    yoff = 0;
  }else
  if (align == WS_RIGHT){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_BOTTOM){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_LEFT_BOTTOM){
    xoff = 0;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_RIGHT_TOP){
    xoff = ((short)w - (short)pw);
    yoff = 0;
  }else
  if (align == WS_RIGHT_BOTTOM){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph);
  }
  if ((long)mem_context1 == -1 || mem_context1 == 0){
    return WS_NO_ERR;
  }

  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }

  long dx1,dy1;
  long dw1,dh1;
  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x-px,_clip_y-py,_clip_w,_clip_h,&dx1,&dy1,(WSCulong*)&dw1,(WSCulong*)&dh1);
  WSGFandArea(dx1,dy1,dw1,dh1,x+xoff,y+yoff,pw,ph,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);

  WSCrect from;
  from.x = dx -x -xoff;
  from.y = dy -y -yoff;
  from.width = dw;
  from.height = dh;
  WSCrect to;
  to.x = dx+px;
  to.y = dy+py;
  to.width = dw;
  to.height = dh;

  if ((long)mem_context2 != -1 && mem_context2 != 0){
    // TODO bit build with AND operation from mem__context2 to _context;
    // TODO bit build with OR operation from mem__context to _context;
  }else{
    // TODO bit build  from mem__context to _context;
  }
  return WS_NO_ERR;
}
long WSDnxDraw::drawStretchedImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  long mem_context1 = image->getValue1();
  long mem_context2 = image->getValue2();

dbprintf(">> WSDnxDraw::drawStretchedImage mem_context=0x%x\n",mem_context1);
  if ((long)mem_context1 == -1 || mem_context1 == 0){
    return WS_NO_ERR;
  }

  WSCulong iw = image->getImageWidth();
  WSCulong ih = image->getImageHeight();

  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }

  WSCrect from;
  from.x = 0;
  from.y = 0;
  from.width = iw;
  from.height = ih;

  WSCrect to;
  to.x = x + px;
  to.y = y + py;
  to.width = w;
  to.height = h;

  if ((long)mem_context2 != -1 && mem_context2 != 0){
    // TODO bit build with AND operation from mem_context2 to _context;
    // TODO bit build with OR operation from mem_context to _context;
  }else{
    // TODO bit build  from mem_context to _context;
  }

  return WS_NO_ERR;
}


long WSDnxDraw::drawImage(short x,short y,short sx,short sy,WSCushort w,WSCushort h,WSDimage* image){
dbprintf(">> WSDnxDraw::drawImage start\n");
  if (_clip_w == 0 || _clip_h == 0){
    return WS_ERR;
  }
  if (_context == 0){
    return WS_ERR;
  }
  long mem_context1 = image->getValue1();
  long mem_context2 = image->getValue2();
dbprintf(">> WSDnxDraw::drawImage mem_context=0x%x\n",mem_context1);

  if ((long)mem_context1 == -1 || mem_context1 == 0){
    return WS_NO_ERR;
  }

  short px,py;
  if (_fdev != NULL){
    _fdev->getAbstPos(&px,&py);
  }else{
    px = 0;
    py = 0;
  }

  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x-px,_clip_y-py,_clip_w,_clip_h,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);
 
  WSCrect from;
  from.x = dx -x +sx;
  from.y = dy -y +sy;
  from.width = dw;
  from.height = dh;

  WSCrect to;
  to.x = dx + px;
  to.y = dy + py;
  to.width = dw;
  to.height = dh;

  if ((long)mem_context2 != -1 && mem_context2 != 0){
    // TODO bit build with AND operation from mem_context2 to _context;
    // TODO bit build with OR operation from mem_context to _context;
  }else{
    // TODO bit build  from mem_context to _context;
  }

  return WS_NO_ERR;
}
long WSDnxDraw::drawUString(long x,long y,WSCulong w,WSCulong h,
         WSCushort* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawString(x,y,w,h,&str2,font,align,cur,inter_cur,scur1,scur2);
  delete str1;
  return ret;
}
long WSDnxDraw::drawFillUString(long x,long y,WSCulong w,WSCulong h,
           WSCushort* str,char font,char align,short cur,WSCbool inter_cur){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawFillString(x,y,w,h,&str2,font,align,cur,inter_cur);
  delete str1;
  return ret;
}
long WSDnxDraw::drawString(long x,long y,WSCulong w,WSCulong h,
         WSCstring* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
dbprintf("ST WSDnxDraw::drawString start %d %s fg=%s xy=%d,%d\n",WSGFclocktime(),str->getString(WS_EN_EUCJP),WSGIappColorSet()->getColor(_fg_cno)->getColorName(),x,y);
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }

  if (scur1 == scur2){
    scur1 = scur2 = 0;
  }
  if (scur1 > scur2){
    long bk = scur1;
    scur1 = scur2;
    scur2 = bk;
  }
  short dx=0,dy=0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
    x = x+dx;
    y = y+dy;
  }

  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;
  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&clx,&cly,&clw,&clh);

  WSCrect r;
  r.x = clx;
  r.y = cly;
  r.width = clw;
  r.height = clh;
  // TODO set visible region to _context

  WSDfont* fn = WSGIappFontSet()->getFont(font);
  if (fn == NULL){
    fn = WSGIappFontSet()->getDefaultFont();
    if (fn == NULL){
      return WS_ERR;
    }
  }
  // TODO set font value to _context..

  long fheight = fn->getFontHeight();
  long fheight2 = fn->getFontHeight();

  if (str->isExist("\n") == -1){
    WSCrect   area;
    area.setRect(x,y,w,h);
    WSCpoint  point;
    WSGFcalcOneLineStringAddr(str,&area,align,fn,&point);
    char* tstr;
    tstr = str->getString(WS_EN_UTF8);

    // TODO draw string.

    r.x = clx_bk;
    r.y = cly_bk;
    r.width = clw_bk;
    r.height = clh_bk;
    // TODO set visible region to _context

    return WS_NO_ERR;
  }

  long num;
  WSCrect area;
  area.setRect(x,y,w,h);
  WSCpoint* points;

  WSGFcalcStringAddr(str,&area,align,fn,&points,&num);
  long i;
  str->seek(0);
  long lpos =0;
  long prelpos =0;
  for(i=0; i < num; i++){

    if (points[i].y + fheight < cly){
      lpos += prelpos;
      prelpos = str->_seek_next_line() +1;
      continue;
    }
    WSCstring lstr;
    lstr = str->gets();

    lpos += prelpos;
    prelpos = lstr.getChars() +1;
    if ((long)(cly + clh) < points[i].y){
      break;
    }
    char* tstr;
    tstr = lstr.getString(WS_EN_UTF8);
    if (cur == -1){
      // TODO draw string with no cursor..
    }else{
      // TODO draw string.
    }
  }
  str->seek(0);
  if (num != 0){
    delete points;
  }

  r.x = clx_bk;
  r.y = cly_bk;
  r.width = clw_bk;
  r.height = clh_bk;
  // TODO set visible region to _context

  return WS_NO_ERR;
}

long WSDnxDraw::drawFillString(long x,long y,WSCulong w,WSCulong h,
           WSCstring* str,char font,char align,short cur,WSCbool inter_cur){

  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
  void* bk = _fg_value;
  _fg_value = _bg_value;
  drawFillRect(x,y,w,h);
  _fg_value = bk;
  drawString(x,y,w,h,str,font,align,cur,inter_cur);

  return WS_NO_ERR;
}

extern WSCulong WSGFxcolorval(WSDcolor*,WSCuchar,WSCuchar,WSCuchar);

long WSDnxDraw::drawGradation(long type,short c1,short c2,short c3,
                  short x,short y,WSCushort w,WSCushort h,WSCuchar gradm){
  if (_clip_w == 0 || _clip_h == 0){
    return WS_NO_ERR;
  }
static WSDcolor* color = NULL;
  if (_context == 0 || _window == 0){
    return WS_ERR;
  }
  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;

  short dx = 0,dy = 0;
  if (_fdev != NULL){
    _fdev->getAbstPos(&dx,&dy);
    clx_bk = _clip_x - dx;
    cly_bk = _clip_y - dy;
  }

  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,clx_bk,cly_bk,clw_bk,clh_bk,&clx,&cly,&clw,&clh);

  WSCrect r;
  r.x = clx + dx;
  r.y = cly + dy;
  r.width = clw;
  r.height = clh;
  // TODO set visible region to _context

  setForeColor(c2);
  drawFillRect(x,y,w,h);

  WSDcolor* col1 = WSGIappColorSet()->getColor(c1);
  WSDcolor* col2 = WSGIappColorSet()->getColor(c2);
  WSDcolor* col3 = WSGIappColorSet()->getColor(c3);
  long r1,g1,b1;
  long r2,g2,b2;
  long r3,g3,b3;

  if (col1 == NULL || col2 == NULL || col3 == NULL){
    r.x = _clip_x;
    r.y = _clip_y;
    r.width = _clip_w;
    r.height = _clip_h;
    // TODO set visible region to _context
    return WS_ERR;
  }



  col1->getRGB(&r1,&g1,&b1);
  col2->getRGB(&r2,&g2,&b2);
  col3->getRGB(&r3,&g3,&b3);
  color = WSGIappColorSet()->getColor((short)0);
  if (color == NULL){
    color = WSGIappColorSet()->getNewColor();
    color->setId(0);
    color->setUsePrivateCell(True);
    WSGIappColorSet()->addColor(color);
  }
  if (gradm != 0){
    setForeColor(c2);
    drawFillRect(x,y,w,h);
  }
  long i;
  if (type == WS_GR_LT_RB || type == WS_GR_RB_LT){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +i;
      if (i > max/2){ 
        x1 = x + (w+h)*gradm/100 + i;
        y1 = y + (w+h)*gradm/100 + i;
      }
      long val1,val2,val3;
      if (type == WS_GR_LT_RB){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;

      // TODO draw line x1+dx, y+dy  <-> x+dx, y1+dy 
    }
  }else
  if (type == WS_GR_LB_RT || type == WS_GR_RT_LB){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +h -i;
      if (i >= max/2){
        x1 = x +i + (w+h) * gradm/100;
        y1 = y +h -i - (w+h) * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_LB_RT){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xfff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;
      // TODO draw line x+dx, y1+dy  <->  x1+dx, y+h+dy
    }
  }else
  if (type == WS_GR_T_B || type == WS_GR_B_T){
    long max = h* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max;i+=wval){
      long h1 = i;
      if (h1 >= max/2){
        h1 = i+ h * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_T_B){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;
      // TODO draw line x+dx, y+h1+dy  <->  x+w+dx, y+h1+dy
    }
  }else{
    long max = w* (100 -gradm)/100;
    long wval = max/64+1;
    for(i=0; i<max; i+=wval){
      long w1 = i;
      if (w1 >= max/2){
        w1 = i+ w * gradm/100;
      }
      long val1,val2,val3;
      if (type == WS_GR_L_R){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      long cval = 0x10000000;
      cval |= val1 << 16;
      cval |= val2 << 8;
      cval |= val3;
      // TODO draw line x+w1+dx, y+dy  <->  x+w1+dx, y+h+dy
    }
  }
  long linet = _line_type;
  _line_type = -1;
  setLineDashType(linet);
  r.x = clx_bk + dx;
  r.y = cly_bk + dy;
  r.width = clw_bk;
  r.height = clh_bk;
  // TODO set visible region to _context

  return WS_NO_ERR;
}

