//
// 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 <basic.h>
#include <btron/hmi.h>
#include <WSCdevice.h>
#include <WSCcolorSet.h>
#include <WSCimageSet.h>
#include <WSCbase.h>
#include <WSDmouse.h>
#include <WSCbaseList.h>
#include <btron/WSDbtronmwinDev.h>
#include <btron/WSDbtronAppDev.h>
#include <btron/WSDbtronDraw.h>

WSMFclassInit(WSDbtronmwinDev,WSDmwindowDev);

WSDdev* _wsdbtronmwindev_init_(){
  return new WSDbtronmwinDev();
}

class _WSDbtronmwinDev_init_ {
  public:_WSDbtronmwinDev_init_(){
     WSGIappDevice()->setCreateHandler("mwindowDev",_wsdbtronmwindev_init_);
  };
};
static _WSDbtronmwinDev_init_ _init_to_run_WSDbtronmwinDev_;

//static WSDxdraw* draw_of_btronmwin = NULL;

//int red_mask, green_mask, blue_mask;
//int red_shift, green_shift, blue_shift;
//int start_shift;
//unsigned int start_mask;
//char mask_initialized = 0;
//long msb_flag = 0;

WSDbtronmwinDev::WSDbtronmwinDev(){
  _mem_gid = 0;
  _bit = 0; 
  _buf = NULL;
//  if (draw_of_btronmwin == NULL){
//      draw_of_btronmwin = new WSDxdraw();
//  }
//  setDraw(draw_of_btronmwin);
}

WSDbtronmwinDev::~WSDbtronmwinDev(){
  destroyContext();
  destroyPixmap();
}

long WSDbtronmwinDev::copyToWindow(WSDdev* dest,short x,short y,WSCushort w,WSCushort h,short dx,short dy){
  if (dest->cast("WSDnwDev") != NULL){
    int vx = 0;
    int vy = 0;
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    WSDdev* pdev = dest->getParentDev();
    WSDbtronFormDev* xdev = NULL;
    if (pdev != NULL){
      xdev = (WSDbtronFormDev*)dest->getParentDev()->cast("WSDbtronFormDev");
    }
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      RECT from;
      from.c.left = x;
      from.c.top = y;
      from.c.right = w +x;
      from.c.bottom = h +y;

      RECT to;
      to.c.left = dx + px + vx;
      to.c.top = dy + py + vy;
      to.c.right = w +dx + px + vx;
      to.c.bottom = h +dy + py + vy;
      gset_for(_mem_gid,NULL);
      gset_vis(_mem_gid,from);
      gset_for(xdev->getParentGID(),NULL);
      gset_vis(xdev->getParentGID(),to);
      xdev->setDefaultRegion();

      gcop_bmp(_mem_gid,&from,xdev->getParentGID(),&to,NULL,G_STORE);
      gcop_bmp(_mem_gid,&from,xdev->getParentMemGID(),&to,NULL,G_STORE);

    }
  }else{
    WSDbtronFormDev* xdev = (WSDbtronFormDev*)dest->cast("WSDbtronFormDev");
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      RECT from;
      from.c.left = x;
      from.c.top = y;
      from.c.right = w +x;
      from.c.bottom = h +y;

      RECT to;
      to.c.left = dx + px;
      to.c.top = dy + py;
      to.c.right = w +dx + px;
      to.c.bottom = h +dy + py;
      gset_for(_mem_gid,NULL);
      gset_vis(_mem_gid,from);
      gset_for(xdev->getParentGID(),NULL);
      gset_vis(xdev->getParentGID(),to);
      xdev->setDefaultRegion();

      gcop_bmp(_mem_gid,&from,xdev->getParentGID(),&to,NULL,G_STORE);
      gcop_bmp(_mem_gid,&from,xdev->getParentMemGID(),&to,NULL,G_STORE);

    }
  }
  return WS_NO_ERR;
}
long WSDbtronmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDimage* image){
  if (image == NULL){
    return WS_ERR;
  }

  W mask = (W)image->getValue1();
  return _copyToWindowWithMask(dest,x,y,w,h,dx,dy,mask);

}
long WSDbtronmwinDev::_copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       W mask){
#if 0
  W src_gid =  WSGIbtronAppDev()->getNewMemGid(w,h);
  RECT from;
  from.c.left = x;
  from.c.top = y;
  from.c.right = w +x;
  from.c.bottom = h +y;

  RECT to;
  to.c.left = 0;
  to.c.top = 0;
  to.c.right = w;
  to.c.bottom = h;

  gset_for(_mem_gid,NULL);
  gset_vis(_mem_gid,from);
  gset_for(xdev->getParentGID(),NULL);
  gset_vis(xdev->getParentGID(),to);
      xdev->setDefaultRegion();

      gcop_bmp(_mem_gid,&from,getParentGID(),&to,NULL,G_STORE);
      gcop_bmp(_mem_gid,&from,getParentMemGID(),&to,NULL,G_STORE);




  XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
           src,gc2, (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

//  Pixmap mask = (Pixmap)image->getValue1();

  WSDxnwDev* nwdev = (WSDxnwDev*)dest->cast("WSDxnwDev");
  int vx = 0;
  int vy = 0;
  WSDdev* pdev = dest->getParentDev();
  WSDbtronFormDev* xdev = NULL;
  if (nwdev != NULL){
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    if (pdev != NULL){
      xdev = (WSDbtronFormDev*)dest->getParentDev()->cast("WSDbtronFormDev");
    }
  }else{
    xdev = (WSDbtronFormDev*)dest->cast("WSDbtronFormDev");
  }

  Pixmap tdest = WSGFxGetPixmap(w,h);
  if (xdev != NULL){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);
//    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XCopyArea( WSGIxwinAppDev()->display(),
             xdev->getWindowResource(),
             tdest,gc2,
             vx+(int)dx, vy+(int)dy, (WSCuint)w, (WSCuint)h,0,0);
  }
  if (mask != (Pixmap)-1 && mask != 0){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXand);
    XCopyArea( WSGIxwinAppDev()->display(),mask,src,gc2,
           (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXandInverted);
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXandInverted);
    if (nwdev != NULL){
      if (nwdev->getUsePixmap() != False){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               nwdev->getWindowResource(),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
      }else
      if ( (Window)dest->getWindowResource() != (Window)-1){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//               (Window)dest->getWindowResource(),_gc,
               (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0,(int)0);
      }
#if 0
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
      }
#endif

    }else{
      if ( (Window)dest->getWindowResource() != (Window)-1){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//               (Window)dest->getWindowResource(),_gc,
               (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
      }
#if 0
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
      }
#endif
    }
  } 
  XSetFunction( WSGIxwinAppDev()->display(),_gc,GXor);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXor);
  if (nwdev != NULL){
    if (nwdev->getUsePixmap() != False){
      XCopyArea( WSGIxwinAppDev()->display(),src,
             nwdev->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }else
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,gc2,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0,(int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
    if (nwdev->getUsePixmap() != False){
    }else
    if ( (Window)dest->getWindowResource() != (Window)-1){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             (Window)dest->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
//    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
  }else{
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,_gc,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);

    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }
  }
  WSGFxReleasePixmap(src);
  WSGFxReleasePixmap(tdest);
  XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,1);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);
#endif
  return WS_NO_ERR;
}
long WSDbtronmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDmwindowDev* image){
  if (image == NULL){
    return WS_ERR;
  }
  WSDbtronmwinDev* mimage = (WSDbtronmwinDev*)image->cast("WSDbtronmwinDev");
  if (mimage == NULL){
    return WS_ERR;
  }
  W mask = mimage->_mem_gid;
  return _copyToWindowWithMask(dest,x,y,w,h,dx,dy,mask);

}

long WSDbtronmwinDev::copyFromWindow(WSDdev* dest,short x,short y,WSCushort w,WSCushort h,short dx,short dy){
  if (_mem_gid == NULL){
    return WS_ERR;
  }
  if (dest->cast("WSDnwDev") != NULL){
    int vx = 0;
    int vy = 0;
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    WSDdev* pdev = dest->getParentDev();
    WSDbtronFormDev* xdev = NULL;
    if (pdev != NULL){
      xdev = (WSDbtronFormDev*)dest->getParentDev()->cast("WSDbtronFormDev");
    }
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      RECT to;
      to.c.left = x;
      to.c.top = y;
      to.c.right = w +x;
      to.c.bottom = h +y;

      RECT from;
      from.c.left = dx + px + vx;
      from.c.top = dy + py + vy;
      from.c.right = w +dx + px + vx;
      from.c.bottom = h +dy + py + vy;

      gset_for(_mem_gid,NULL);
      gset_vis(_mem_gid,to);
      gset_for(xdev->getParentGID(),NULL);
      gset_vis(xdev->getParentGID(),from);
      xdev->setDefaultRegion();

      gcop_bmp(xdev->getParentGID(),&from,_mem_gid,&to,NULL,G_STORE);
    }
  }else{
    WSDbtronFormDev* xdev = (WSDbtronFormDev*)dest->cast("WSDbtronFormDev");
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      RECT to;
      to.c.left = x;
      to.c.top = y;
      to.c.right = w +x;
      to.c.bottom = h +y;

      RECT from;
      from.c.left = dx + px;
      from.c.top = dy + py;
      from.c.right = w +dx + px;
      from.c.bottom = h +dy + py;
      gset_for(_mem_gid,NULL);
      gset_vis(_mem_gid,to);
      gset_for(xdev->getParentGID(),NULL);
      gset_vis(xdev->getParentGID(),from);
      xdev->setDefaultRegion();

      gcop_bmp(xdev->getParentGID(),&from,_mem_gid,&to,NULL,G_STORE);
    }
  }
  return WS_NO_ERR;
}

long WSDbtronmwinDev::createPixmap(WSCushort w,WSCushort h){
  _w = w;
  _h = h;
  if (_w == 0 || _h == 0){
    return WS_ERR;
  }

  if (_buf != 0){
    destroyPixmap();
  }
  _buf = new WSCushort [ w * h * 3];
  createContext();
  return WS_NO_ERR;
}
long WSDbtronmwinDev::destroyPixmap(){
  if ( _buf == NULL){
    delete _buf;
    _buf = NULL;
  }
  destroyContext();
  return WS_NO_ERR;
}

long WSDbtronmwinDev::getDeviceResource(){
  return (long)0;
}


long WSDbtronmwinDev::getContextResource(){
  if (_mem_gid == 0){
    return -1;
  }
  return (long)_mem_gid;
}

long WSDbtronmwinDev::getSpecialResource(){
   return (long)0;
}

long WSDbtronmwinDev::createContext(){
  if (_mem_gid != NULL){
    destroyContext();
  }
  if (_w == 0 || _h == 0){
    return WS_ERR;
  } 
  _mem_gid =  WSGIbtronAppDev()->getNewMemGid(_w,_h);
  return WS_NO_ERR;
}

long WSDbtronmwinDev::getWindowResource(){
  return (long)0;
}

long WSDbtronmwinDev::destroyContext(){
  if (_mem_gid != 0){
    gcls_env(_mem_gid);
    _mem_gid = 0;
  }
  return WS_NO_ERR;
}

long WSDbtronmwinDev::initBuffer(){
  if (_buf == NULL){
    return WS_ERR;
  }
  long x,y;
  PIXVAL val;
  PNT pnt;
  long pt = 0;
  for(x=0; x<_w; x++){
    for(y=0; y<_h; y++){
      pnt.x = x;
      pnt.y = y;
      gtst_pnt(_mem_gid,pnt,&val);
      _buf[pt++] = (WSCushort)((0xff0000 & val) >> 16);
      _buf[pt++] = (WSCushort)((0xff00 & val) >> 8);
      _buf[pt++] = (WSCushort)(0xff & val);
    }
  }
  return WS_ERR;
}
long WSDbtronmwinDev::setBufferRGB(WSCushort x,WSCushort y,WSCuchar r,WSCuchar g,WSCuchar b){
  if (x < _w && y < _h){
    long pnt = (x + y * _h)*3;
    _buf[pnt] = r;
    _buf[pnt+1] = g;
    _buf[pnt+2] = b;
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSDbtronmwinDev::getBufferRGB(WSCushort x,WSCushort y, WSCuchar* r, WSCuchar* g,WSCuchar* b){
  if (x < _w && y < _h){
    long pnt = (x + y * _h)*3;
    *r = _buf[pnt];
    *g = _buf[pnt+1];
    *b = _buf[pnt+2];
    return WS_NO_ERR;
  }

  return WS_ERR;
}
long WSDbtronmwinDev::putBufferToPixmap(){
  if (_mem_gid == NULL){
    return WS_ERR;
  }
  if (_w > 0 && _h > 0){
    long pt = 0;
    long x,y;
    long val = 0x10000000;
    for(x=0; x<_w; x++){
      for(y=0; y<_h; y++){
        val = 0x10000000;
        val |= _buf[pt++]<<16;
        val |= _buf[pt++]<<8;
        val |= _buf[pt++];
        PNT pnt;
        pnt.x = x;
        pnt.y = y;
        gdra_pnt(_mem_gid,pnt,val,G_STORE);
      }
    }
  }
  return WS_NO_ERR;
}


