//
// 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 <win/WSDwinScrFrameDev.h>
#include <win/WSDwinappDev.h>
#include <WSCdevice.h>
#include <win/WSDwindraw.h>
#include <WSCcolorSet.h>
#include <windows.h>
#include <WSCbase.h>
#include <WSDmouse.h>


WSMFclassInit(WSDwinScrFrameDev,WSDwinformDev);
WSDdev* _wsdxscrdev_init_(){
  return new WSDwinScrFrameDev();
}

class _WSDwinScrFrameDev_init_ {
  public:_WSDwinScrFrameDev_init_(){
     WSGIappDevice()->setCreateHandler("scrFrameDev",_wsdxscrdev_init_);
  };
};
static _WSDwinScrFrameDev_init_ _init_to_run_WSDwinScrFrameDev_;

WSDwinScrFrameDev::WSDwinScrFrameDev(){
  _scr_wnd = 0;
  _work_width =0;
  _work_height =0;
  _title_height = 0;
}

WSDwinScrFrameDev::~WSDwinScrFrameDev(){
  destroyWindow();
}

long WSDwinScrFrameDev::setValue(long kind,void* data){
  char psbk = getPixmapStyle();
  setPixmapStyle( WS_DIRECT_WINDOW);
  setPixmapStyle(psbk);
//  short bx,by;
//  WSCushort bw,bh;
  if (kind == WSDEV_X && *(short*)data == _w_x){
    return WS_NO_ERR;
  }
  if (kind == WSDEV_Y && *(short*)data == _w_y){
    return WS_NO_ERR;
  }
  if (kind == WSDEV_WIDTH && *(WSCushort*)data == _w_w){
    return WS_NO_ERR;
  }
  if (kind == WSDEV_HEIGHT && *(WSCushort*)data == _w_h){
    return WS_NO_ERR;
  }
  WSDwindowDev::setValue(kind,data);

  long vl;
  WSDcolor* color;
  char fl;
  RECT p;
  long pos_bk;
  switch(kind){
    case WSDEV_X: 
             if (_scr_wnd == NULL){
               break;
             }
             _moved = True;
             GetClientRect(_scr_wnd,&p);
WSMFtrace("WSDwinScrFrameDev::setValue x p.left=%d ",p.left);
WSMFtrace(" -> %d  w=0x%d\n",p.left,p.right - p.left);
             _w_x = *(short*)data;
             MoveWindow(_scr_wnd,_w_x,_w_y,p.right,p.bottom, True);
             break;
    case WSDEV_Y:
             if (_scr_wnd == NULL){
               break;
             }
             _moved = True;
             GetClientRect(_scr_wnd,&p);
WSMFtrace("WSDwinScrFrameDev::setValue y p.top=%d ",p.top);
             _w_y = *(short*)data;
             MoveWindow(_scr_wnd,_w_x,_w_y,p.right,p.bottom, True);
WSMFtrace(" -> %d  w=0x%d\n",p.top,p.bottom - p.top);
             break;
    case WSDEV_WIDTH:
             if (_scr_wnd == NULL){
               break;
             }
//             _resized = True;
             if (_resize_sequence != False && *(short*)data == _w_now){
               break;
             }
             if (getPixmapStyle() != WS_DIRECT_WINDOW){
               destroyPixmap();
             }
             if (*(WSCushort*)data > 0){
               GetClientRect(_scr_wnd,&p);
               p.right = p.left + *(WSCushort*)data;
               MoveWindow(_scr_wnd,_w_x,_w_y,p.right,p.bottom, True);
             }
             break;
    case WSDEV_HEIGHT:
             if (_scr_wnd == NULL){
               break;
             }
//             _resized = True;
             if (_resize_sequence != False && *(short*)data == _h_now){
               break;
             }
             if (getPixmapStyle() != WS_DIRECT_WINDOW){
               destroyPixmap();
             }
             if (*(WSCushort*)data > 0){
               GetClientRect(_scr_wnd,&p);
               p.bottom = p.top + *(WSCushort*)data;
               MoveWindow(_scr_wnd,_w_x,_w_y,p.right,p.bottom, True);
             }
             break;
    case WSDEV_BACKCOLOR:
             color = WSGIappColorSet()->getColor(*(short*)data);
             _back_cno = *(short*)data;
             if (color != NULL){
               _bg_cref = (COLORREF)color->getValue1();
             }
             if (_wnd == NULL){
               break;
             }
             setExposed(False);
             invalidate(TRUE);
             break;
    case WSDEV_WORK_X:
             vl = *(WSCushort*)data;
             if (vl > _work_width - _w_w){
               vl = _work_width - _w_w;
               if (vl < 0){
                 vl = 0;
               }
             }
             if (_h_scr_pos != vl){
               pos_bk = _h_scr_pos;
               _h_scr_pos = vl;
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }

               if (_wnd != NULL){
                 GetClientRect(_wnd,&p);

                 MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, True);
//                 MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, False);
                 exposeArea(_h_scr_pos,_v_scr_pos,_w_w,_w_h,False);
                 _expose_children(_h_scr_pos,_v_scr_pos,_w_w,_w_h);
               }
             }
             break;
    case WSDEV_WORK_Y:
             vl = *(WSCushort*)data;
             if (vl > _work_height - _w_h){
               vl = _work_height - _w_h;
               if (vl < 0){
                 vl = 0;
               }
             }
             if (_v_scr_pos != vl){
               pos_bk = _v_scr_pos;
               _v_scr_pos = vl;
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }
               if (_wnd != NULL){
                 GetClientRect(_wnd,&p);
                 MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, True);
//                 MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, False);
//  invalidate(True);
                 exposeArea(_h_scr_pos,_v_scr_pos,_w_w,_w_h,False);
                 _expose_children(_h_scr_pos,_v_scr_pos,_w_w,_w_h);
               }
             }
             break;
    case WSDEV_WORK_WIDTH:
             if(_work_width < *(WSCushort*)data){
               destroyPixmap();
             }
             _work_width = *(WSCushort*)data;
             if (_h_scr_pos > _work_width - _w_w){
               _h_scr_pos = _work_width - _w_w;
               if (_h_scr_pos < 0){
                 _h_scr_pos = 0;
               }
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }
             }
             if (_wnd != NULL){
               GetClientRect(_wnd,&p);
               MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, True);
             }
             break;
    case WSDEV_WORK_HEIGHT:
             if(_work_height < *(WSCushort*)data){
               destroyPixmap();
             }
             _work_height = *(WSCushort*)data;
             if (_v_scr_pos > _work_height - _w_h){
               _v_scr_pos = _work_height - _w_h;
               if (_v_scr_pos < 0){
                 _v_scr_pos = 0;
               }
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }
             }
             if (_wnd != NULL){
               GetClientRect(_wnd,&p);
               MoveWindow(_wnd,-_h_scr_pos,-_v_scr_pos,_work_width,_work_height, True);
             }
             break;
    case WSDEV_PIXMAP_STYLE:
             fl = *(char*)data;
             setPixmapStyle(fl);
             destroyPixmap();
             break;
    case WSDEV_TITLE_HEIGHT:
             _title_height = *(WSCushort*)data;
             break;
    case WSDEV_GRAB_POINTER:
             if (_wnd == NULL){
               break;
             }
             _grabed = *(WSCbool*)data;
             if (_grabed != False){
               WSGIwinAppDev()->setGrabedWnd(_wnd);
             }else{
               WSGIwinAppDev()->setGrabedWnd(NULL);
             }
#if 0
               XGrabPointer(XtDisplay(_widget),XtWindow(_widget),False,
                  ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
                  GrabModeAsync,GrabModeAsync,None,None,CurrentTime);
             }else{
               XUngrabPointer(XtDisplay(_widget),CurrentTime);
             }
#endif
             break;
    case WSDEV_MOUSE_NO:
             _mouse_no = *(WSCushort*)data;
             _mouse_val = (HCURSOR)WSGIappMouse()->getMouseCursor(*(WSCushort*)data);
             break;
    default:
      return WS_ERR;
  }
  return WS_NO_ERR;
}

long WSDwinScrFrameDev::createPixmap(){
  WSCushort wbk = _w_w;
  WSCushort hbk = _w_h;
  _w_w = _work_width;
  _w_h = _work_height;
  long ret = WSDwinformDev::createPixmap();
  _w_w = wbk;
  _w_h = hbk;
  return ret;
}
long WSDwinScrFrameDev::createWindow(){
#if 0
  if (_scr_wnd != 0){
    WSDwinformDev* xdev = getParentAreaDev();
    if (xdev != NULL && xdev->getWidget() != _pwidget){
      XtRemoveCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
    }else{
      return WS_NO_ERR;
    }
  }
#endif
  short x,y;    
  WSCushort w,h;    
  getWindowSize(&x,&y,&w,&h);
  if (w == 0){
    w = 1;
  }
  if (h == 0){
    h = 1;
  }
  _h_scr_pos = 0;
  _v_scr_pos = 0;

  WSDdev*      pdev = getParentDev();
  if (pdev == NULL){
    return WS_ERR;
  }
  WSDwinformDev* windev = (WSDwinformDev*)pdev->cast("WSDwinformDev");
  if (windev == NULL){
    return WS_ERR;
  }
extern char szAppName[];
  _pwnd = windev->getHWND();
WSMFtrace("CreateWindow  x,y,w,h=%d,%d,%d,%d\n",x,y,w,h);
  _scr_wnd = CreateWindow( szAppName,"",
                WS_CHILD | WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                x,y,w,h,_pwnd,
                NULL,WSGIwinAppDev()->getInstanceHandle(),NULL);
  WSDwinformDev* ptr = this;
#if 0
  SetWindowLong(_scr_wnd,GWL_USERDATA,(long)ptr);
#else
  SetProp(_scr_wnd,"frm",(HANDLE)ptr);
#endif

  _wnd = CreateWindow( szAppName,"",
                WS_CHILD | WS_OVERLAPPED | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
                -_h_scr_pos,-_v_scr_pos,_work_width,_work_height,_scr_wnd,
                NULL,WSGIwinAppDev()->getInstanceHandle(),NULL);
  if (WSGIwinAppDev()->getWndProc() != NULL){
    SetWindowLong(_scr_wnd,GWL_WNDPROC,(LONG)WSGIwinAppDev()->getWndProc());
    SetWindowLong(_wnd,GWL_WNDPROC,(LONG)WSGIwinAppDev()->getWndProc());
  }
WSMFtrace("x,y,w,h=%d,%d,%d,%d\n",x,y,w,h);
#if 0
  SetWindowLong(_wnd,GWL_USERDATA,(long)ptr);
#else
  SetProp(_wnd,"frm",(HANDLE)ptr);
#endif

WSMFtrace("WSDwinScrFrameDev this=0x%x wnd=0x%x pwnd=0x%x\n",this,_wnd,windev->getHWND());
#ifdef DEBUG
WSMFtrace("WSDwinformDev::createWindow() add callbacks is not implemented..\n");
#endif


#if 0
  Arg args[12];
  long anum =0;
  if (_back_cno != -1){
    WSDcolor* color = WSGIappColorSet()->getColor(_back_cno);
    if (color != NULL){
       XtSetArg(args[anum],XtNbackground,color->getValue1()); anum++;
    }
  }

  XtSetArg(args[anum],XtNbackgroundPixmap,UNSPECIFIED_PIXMAP); anum++;
  XtSetArg(args[anum],XtNx,x); anum++;
  XtSetArg(args[anum],XtNy,y); anum++;
  XtSetArg(args[anum],XtNwidth,w); anum++;
  XtSetArg(args[anum],XtNheight,h); anum++;
  XtSetArg(args[anum],XtNborderWidth,0); anum++;

  _pwidget = xdev->getWidget();
  _scr_wnd = XtCreateWidget("xscrarea",formWidgetClass,_pwidget,args,6);

  anum =0;
  if (_back_cno != -1){
    WSDcolor* color = WSGIappColorSet()->getColor(_back_cno);
    if (color != NULL){
       XtSetArg(args[anum],XtNbackground,color->getValue1()); anum++;
    }
  }
  XtSetArg(args[anum],XtNbackgroundPixmap,UNSPECIFIED_PIXMAP); anum++;
  XtSetArg(args[anum],XtNx,0); anum++;
  XtSetArg(args[anum],XtNy,0); anum++;
  XtSetArg(args[anum],XtNwidth,1000); anum++;
  XtSetArg(args[anum],XtNheight,1000); anum++;
  XtSetArg(args[anum],XtNborderWidth,0);anum++;

  _widget = XtCreateWidget("wsdxwa",formWidgetClass, _scr_wnd,args,anum);
  XtManageChild(_widget);

  XtAddEventHandler(_widget,ExposureMask,False,(XtEventHandler)_evh_expose,(WSDwinformDev*)this);
  XtAddEventHandler(_widget,ButtonPressMask,False,(XtEventHandler)_evh_btn_press,(WSDwinformDev*)this);
  XtAddEventHandler(_widget,ButtonReleaseMask,False,(XtEventHandler)_evh_btn_release,(WSDwinformDev*)this);
  XtAddEventHandler(_widget,ButtonMotionMask | PointerMotionMask,False,(XtEventHandler)_evh_mouse_move,(WSDwinformDev*)this);
  XtAddEventHandler(_scr_wnd,StructureNotifyMask,False,(XtEventHandler)_evh_resize,this);
  XtAddEventHandler(_widget,EnterWindowMask,False,(XtEventHandler)_evh_mouse_in,(WSDwinformDev*)this);
  XtAddEventHandler(_widget,LeaveWindowMask,False,(XtEventHandler)_evh_mouse_out,(WSDwinformDev*)this);
  XtAddEventHandler(_widget,KeyPressMask | KeyReleaseMask,False,(XtEventHandler)_evh_dummy,(WSDwinformDev*)this);
  XtAddCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
#endif
  return WS_NO_ERR;
}

long WSDwinScrFrameDev::destroyWindow(){
  WSDwinformDev* mdev = WSGIwinAppDev()->getMouseFocusDev();
  if (mdev == this){
    WSGIwinAppDev()->setMouseFocusDev(NULL);
  }
  if (_wnd != 0){
#if 0
    SetWindowLong(_wnd,GWL_USERDATA,(long)0);
#else
    SetProp(_wnd,"frm",(HANDLE)0);
#endif
    MSG msg;
    while(PeekMessage(&msg,_wnd,0,0,PM_REMOVE)){
      if (msg.message == WM_PAINT){
          PAINTSTRUCT ps;
          BeginPaint(_wnd,&ps);
          EndPaint(_wnd,&ps);
      }
    }
    DestroyWindow(_wnd);
    _wnd = 0;
  }
  if (_scr_wnd != 0){
#if 0
    SetWindowLong(_scr_wnd,GWL_USERDATA,(long)0);
#else
    SetProp(_scr_wnd,"frm",(HANDLE)0);
#endif
    MSG msg;
    while(PeekMessage(&msg,_scr_wnd,0,0,PM_REMOVE)){
      if (msg.message == WM_PAINT){
          PAINTSTRUCT ps;
          BeginPaint(_scr_wnd,&ps);
          EndPaint(_scr_wnd,&ps);
      }
    }
    DestroyWindow(_scr_wnd);
    _scr_wnd = 0;
  }
  _pwnd = 0;
  setInitialized(False);
#if 0
  if (_widget != 0){
    XtRemoveEventHandler(_widget,ExposureMask,False,(XtEventHandler)_evh_expose,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,ButtonPressMask,False,(XtEventHandler)_evh_btn_press,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,ButtonReleaseMask,False,(XtEventHandler)_evh_btn_release,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,ButtonMotionMask | PointerMotionMask,False,(XtEventHandler)_evh_mouse_move,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,EnterWindowMask,False,(XtEventHandler)_evh_mouse_in,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,LeaveWindowMask,False,(XtEventHandler)_evh_mouse_out,(WSDwinformDev*)this);
    XtRemoveEventHandler(_widget,KeyPressMask | KeyReleaseMask,False,(XtEventHandler)_evh_dummy,(WSDwinformDev*)this);
    XtRemoveCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
    XtDestroyWidget(_widget);
  }
  if (_scr_wnd != 0){
    XtRemoveEventHandler(_scr_wnd,StructureNotifyMask,False,(XtEventHandler)_evh_resize,this);
    XtDestroyWidget(_scr_wnd);
  }
  _pwidget = 0;
  _widget = 0;
  _scr_wnd = 0;
//  setDependDev(NULL);
  setInitialized(False);
//  destroyAllDependChildren();
#endif
  return WS_NO_ERR;
}

long WSDwinScrFrameDev::setVisible(WSCbool fl){

  WSCbool bk = getVisible();
  WSDdev::setVisible(fl);
  if (fl == False){
    WSDwinformDev* windev = getParentAreaDev();
    if (windev != NULL && windev->getHWND() == 0){
      destroyWindow();
    }else{
      if (_scr_wnd != 0){
        ShowWindow(_scr_wnd,SW_HIDE);
        ShowWindow(_wnd,SW_HIDE);
      }
    }
  }else{

    if (_scr_wnd == 0){
      if ( createWindow() == WS_ERR){
	      return WS_ERR;
       }
    }

    if (getPixmapStyle() != WS_DIRECT_WINDOW){
      if (bk == False){
        destroyPixmap(); //expose handler 内で作成するため、消しておく
      }
    }
    ShowWindow(_scr_wnd,SW_SHOW);
    ShowWindow(_wnd,SW_SHOW);
    if (bk == False){
      setExposed(False);
      invalidate(False);
    }
  }
  return WS_NO_ERR;
}

void WSDwinScrFrameDev::_evh_delete(WinEvent* ptr){
  _pwnd = 0;
  _scr_wnd = 0;
  _wnd = 0;
  setInitialized(False);
}
void WSDwinScrFrameDev::_evh_resize(WinEvent* ev){
//  if (_resized == 1){
//    _resized = 0;
//    return;
//  }
  RECT r;
  GetClientRect(_scr_wnd,&r);
  WSCrect area;
  area.setRect(_w_x, _w_y, r.right - r.left, r.bottom - r.top);
  _w_now = area.width;
  _h_now = area.height;
  _resize_sequence = True;
  onResize(&area);
  _resize_sequence = False;
}
void WSDwinScrFrameDev::getDispAddr(short* ox,short* oy){

  short gx,gy;
  WSDwindowDev::getDispAddr(&gx,&gy);

  gx -=_h_scr_pos;
  gy -=_v_scr_pos;

  *ox = gx;
  *oy = gy;
}
void WSDwinScrFrameDev::_evh_expose(WinEvent* ev){
  if (_wnd == WSGIwinAppDev()->getEventWnd()){
WSMFtrace("WSDwinScrFrameDev::_evh_expose...\n");
    WSDwinformDev::_evh_expose(ev);
  }else 
  if (_scr_wnd == WSGIwinAppDev()->getEventWnd()){
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(_scr_wnd,&ps);
    HPALETTE pl = WSGIwinAppDev()->getPalette();
    HPALETTE plbk = 0;
    if (pl != 0){
      plbk = SelectPalette(hdc,pl,False);
      RealizePalette(hdc);
    }
    HBRUSH brush = CreateSolidBrush(_bg_cref);
    FillRect(hdc,&ps.rcPaint,brush);
    DeleteObject(brush);
    if (pl != 0){
      SelectPalette(hdc,plbk,False);
    }
    EndPaint(_scr_wnd,&ps);
  }
#if 0
  if (_w_w > _work_width || _w_h > _work_height){
    setValue(WSDEV_WORK_WIDTH,&_w_w);
    setValue(WSDEV_WORK_HEIGHT,&_w_h);
  }
#endif
}
void WSDwinScrFrameDev::_clear_and_expose(){
  WSCrect r;
  if (getPixmapStyle() == WS_DIRECT_WINDOW){
    r.setRect(_h_scr_pos,_v_scr_pos,_w_w,_w_h);
    _clear_area(_h_scr_pos,_v_scr_pos,_w_w,_w_h);
  }else{
    r.setRect(0,0,_work_width,_work_height);
    _clear_area(0,0,_work_width,_work_height);
  }
  onExpose(&r);
}
void WSDwinScrFrameDev::_expose_children(int x,int y,unsigned long w,unsigned long h){
  WSCbase* client = getAttachedClient();
  if (client == NULL){
    return;
  }
  WSCbase* pclient = client->getParent();
  if (pclient != NULL && pclient->getdev() == this){
    client = pclient;
  }
  WSClistData list = client->getChildren();
  long i;
  long num = list.getNum();
  for(i=0; i<num; i++){
    WSCbase* child = (WSCbase*)list[i];
    if (child->getVisible() == False){
      continue;
    }
    WSDdev* dev = child->getdev();
    if (dev == NULL){
      continue;
    }
    WSDwinformDev* wdev =(WSDwinformDev*)dev->cast("WSDwinformDev");
    if (wdev == NULL){
      continue;
    }
    long ex,ey;
    unsigned long ew,eh;
    short dx,dy;
    unsigned short dw,dh;
    wdev->getWindowSize(&dx,&dy,&dw,&dh);
    WSGFandArea(_h_scr_pos,_v_scr_pos,w,h,dx,dy,dw,dh,
                &ex,&ey,&ew,&eh);
    if (ew != 0 && eh != 0){
      wdev->exposeArea(ex-dx,ey-dy,ew,eh);
    }
  }
}
