//
// 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 <WSCdevice.h>
#include <WSCcolorSet.h>
#include <WSCimageSet.h>
#include <WSCbase.h>
#include <WSDmouse.h>
#include <WSCbaseList.h>
#include <nx/WSDnxmwinDev.h>
#include <nx/WSDnxAppDev.h>
#include <nx/WSDnxDraw.h>

WSMFclassInit(WSDnxmwinDev,WSDmwindowDev);

WSDdev* _wsdnxmwindev_init_(){
  return new WSDnxmwinDev();
}

class _WSDnxmwinDev_init_ {
  public:_WSDnxmwinDev_init_(){
     WSGIappDevice()->setCreateHandler("mwindowDev",_wsdnxmwindev_init_);
  };
};
static _WSDnxmwinDev_init_ _init_to_run_WSDnxmwinDev_;


WSDnxmwinDev::WSDnxmwinDev(){
  _mem_context = 0;
  _bit = 0; 
  _buf = NULL;
}

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

long WSDnxmwinDev::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();
    WSDnxFormDev* xdev = NULL;
    if (pdev != NULL){
      xdev = (WSDnxFormDev*)dest->getParentDev()->cast("WSDnxFormDev");
    }
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      WSCrect from;
      from.x = x;
      from.y = y;
      from.width = w;
      from.height = h;

      WSCrect to;
      to.x = dx + px + vx;
      to.y = dy + py + vy;
      to.width = w;
      to.height = h;
      // TODO set clip mask NULL to _mem_context
      // TODO set visible region "from" to _mem_context

      // TODO set clip mask NULL to xdev->getParentContext()
      // TODO set visible region "to" to xdev->getParentContext()

      xdev->setDefaultRegion();

      // TODO bit build from _mem_context to xdev->getParentContext()
      // TODO bit build from _mem_context to xdev->getParentMemContext()

    }
  }else{
    WSDnxFormDev* xdev = (WSDnxFormDev*)dest->cast("WSDnxFormDev");
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      WSCrect from;
      from.x = x;
      from.y = y;
      from.width = w;
      from.height = h;

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

      // TODO set clip mask NULL to _mem_context
      // TODO set visible region "from" to _mem_context

      // TODO set clip mask NULL to xdev->getParentContext()
      // TODO set visible region "to" to xdev->getParentContext()

      xdev->setDefaultRegion();

      // TODO bit build from _mem_context to xdev->getParentContext()
      // TODO bit build from _mem_context to xdev->getParentMemContext()

    }
  }
  return WS_NO_ERR;
}
long WSDnxmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDimage* image){
  if (image == NULL){
    return WS_ERR;
  }
  // TODO bit build from context to window with mask

  return WS_ERR;

}

long WSDnxmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDmwindowDev* image){
  if (image == NULL){
    return WS_ERR;
  }
  WSDnxmwinDev* mimage = (WSDnxmwinDev*)image->cast("WSDnxmwinDev");
  if (mimage == NULL){
    return WS_ERR;
  }
  // TODO bit build from context to window with mask
  return WS_ERR;

}

long WSDnxmwinDev::copyFromWindow(WSDdev* dest,short x,short y,WSCushort w,WSCushort h,short dx,short dy){
  if (_mem_context == 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();
    WSDnxFormDev* xdev = NULL;
    if (pdev != NULL){
      xdev = (WSDnxFormDev*)dest->getParentDev()->cast("WSDnxFormDev");
    }
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      WSCrect to;
      to.x = x;
      to.y = y;
      to.width = w;
      to.height = h;

      WSCrect from;
      from.x = dx + px + vx;
      from.y = dy + py + vy;
      from.width = w;
      from.height = h;

      // TODO set clip mask NULL to _mem_context
      // TODO set visible region "to" to _mem_context

      // TODO set clip mask NULL to xdev->getParentContext()
      // TODO set visible region "from" to xdev->getParentContext()

      xdev->setDefaultRegion();

      // TODO bit build from getParentContext() to _mem_context

    }
  }else{
    WSDnxFormDev* xdev = (WSDnxFormDev*)dest->cast("WSDnxFormDev");
    if (xdev != NULL ){
      short px,py;
      xdev->getAbstPos(&px,&py);
      WSCrect to;
      to.x = x;
      to.y = y;
      to.width = w;
      to.height = h;

      WSCrect from;
      from.x = dx + px;
      from.y = dy + py;
      from.width = w;
      from.height = h;

      // TODO set clip mask NULL to _mem_context
      // TODO set visible region "to" to _mem_context

      // TODO set clip mask NULL to xdev->getParentContext()
      // TODO set visible region "from" to xdev->getParentContext()

      xdev->setDefaultRegion();

      // TODO bit build from getParentContext() to _mem_context
    }
  }
  return WS_NO_ERR;
}

long WSDnxmwinDev::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 WSDnxmwinDev::destroyPixmap(){
  if ( _buf == NULL){
    delete _buf;
    _buf = NULL;
  }
  destroyContext();
  return WS_NO_ERR;
}

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


long WSDnxmwinDev::getContextResource(){
  if (_mem_context == 0){
    return -1;
  }
  return (long)_mem_context;
}

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

long WSDnxmwinDev::createContext(){
  if (_mem_context != NULL){
    destroyContext();
  }
  if (_w == 0 || _h == 0){
    return WS_ERR;
  } 
  _mem_context =  WSGInxAppDev()->getNewMemContext(_w,_h);
  return WS_NO_ERR;
}

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

long WSDnxmwinDev::destroyContext(){
  if (_mem_context != 0){
    // TODO destroy _mem_context
    _mem_context = 0;
  }
  return WS_NO_ERR;
}

long WSDnxmwinDev::initBuffer(){
  if (_buf == NULL){
    return WS_ERR;
  }
  long x,y;
  long pt = 0;
  WSCulong val = 0;
  for(x=0; x<_w; x++){
    for(y=0; y<_h; y++){
      // TODO get pixel value from _mem_context.
      _buf[pt++] = (WSCushort)((0xff0000 & val) >> 16);
      _buf[pt++] = (WSCushort)((0xff00 & val) >> 8);
      _buf[pt++] = (WSCushort)(0xff & val);
    }
  }
  return WS_ERR;
}
long WSDnxmwinDev::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 WSDnxmwinDev::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 WSDnxmwinDev::putBufferToPixmap(){
  if (_mem_context == NULL){
    return WS_ERR;
  }
  if (_w > 0 && _h > 0){
    long pt = 0;
    long x,y;
    WSCulong val = 0x00000000;
    for(x=0; x<_w; x++){
      for(y=0; y<_h; y++){
        val = 0x00000000;
        val |= _buf[pt++]<<16;
        val |= _buf[pt++]<<8;
        val |= _buf[pt++];
        // TODO set pixel value to _mem_context.
      }
    }
  }
  return WS_NO_ERR;
}


