//
// 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>
#ifdef TE
#include <btron/errcode.h>
#else
#include <errcode.h>
#endif
#include <WSCdevice.h>
#include <WSCimageSet.h>
#include <WSCcolorSet.h>
#include <WSDtimer.h>
#include <WSCbase.h>
#include <WSDmouse.h>
#include <WSClocaleSet.h>
#include <btron/WSDbtronWinDev.h>
#include <btron/WSDbtronAppDev.h>
#include <btron/WSDbtronMouse.h>

#define MEMGID

WSMFclassInit(WSDbtronWinDev,WSDbtronFormDev);
WSDdev* _wsdbtronWindev_init_(){
dbprintf("_wsdbtronWindev_init_() %s:%d started..\n",__FILE__,__LINE__);
  return new WSDbtronWinDev();
}

class _WSDbtronWinDev_init_ {
  public:_WSDbtronWinDev_init_(){
dbprintf("_WSDbtronWinDev_init_() %s:%d started..\n",__FILE__,__LINE__);
     WSGIappDevice()->setCreateHandler("windowDev",_wsdbtronWindev_init_);
  };
};
static _WSDbtronWinDev_init_ _init_to_run_WSDbtronWinDev_;
//static Atom wm_protocols = 0;
//static Atom wm_delete = 0;
extern TC* WSGFbtronStringToTc(char*,long*);
extern TC* WSGFbtronStringToTc2(char*,long*);

WSDbtronWinDev::WSDbtronWinDev(){
  _diff_x = 0;
  _diff_y = 0;
  _diff_w = 0;
  _diff_h = 0;
  _attr = WA_SIZE | WA_HHDL | WA_VHDL | WA_FMOVE | WA_THIN;

  _title_bar = 0;
  _title_bar_style = 0;
  _no_frame = 0;
  _no_frame_first_time = 0;
  _requested_top = 0;
  _transient = False;
  _top_float = 0;
  _modal = 0;
}

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

WSDdev* WSDbtronWinDev::getVisibleParentDev(){
  return this;
}

long WSDbtronWinDev::setValue(long kind,void* data){
  if (kind == WSDEV_PIXMAP_STYLE){
    return WS_NO_ERR;
  }

  WSDwindowDev::setValue(kind,data);
  switch(kind){
    case WSDEV_X: 
    case WSDEV_Y: 
dbprintf("WSDbtronWinDev::setValue X/Y %d,%d w=0x%x vis=%d diff=%d,%d\n",_w_x,_w_y,_window,getVisible(),_diff_w,_diff_h);
            if (_window != 0){
               RECT rect;
               WSGFsetRect(&rect,_w_x,_w_y,_w_w+_diff_w,_w_h+_diff_h);
               W rv = wmov_wnd(_window,&rect);
               if (getVisible() != False){
                 if (rv == 1){
dbprintf("WSDbtronWinDev::setValue need execute expose..%s:%d\n",__FILE__,__LINE__);
                 }
               }
             }
             break;
    case WSDEV_WIDTH: 
    case WSDEV_HEIGHT: 
dbprintf("WSDbtronWinDev::setValue W/H %d,%d w=0x%x vis=%d\n",_w_w,_w_h,_window,getVisible());
             if (_mem_gid != 0){
               destroyPixmap();
             }
             if (_window != 0){
               RECT rect;
               WSGFsetRect(&rect,_w_x,_w_y,_w_w+_diff_w,_w_h+_diff_h);
               W rv = wrsz_wnd(_window,&rect);
               RECT rect2;
               wget_wrk(_window,&rect2);
               if (rect2.c.right > _w_w){
                 _w_w = rect2.c.right;
               }
               if (rect2.c.bottom > _w_h){
                 _w_h = rect2.c.bottom;
               }
               if (getVisible() != False){
                 if (rv == 1){
dbprintf("WSDbtronWinDev::setValue need execute expose..%s:%d\n",__FILE__,__LINE__);
#if 0
                   rect.c.top =0;
                   rect.c.left =0;
                   rect.c.right =_w_w;
                   rect.c.bottom =_w_h;
//                   WSGFsetRect(&rect,0,0,_w_w,_w_h);
                   gset_vis(_gid,rect);
#endif
                   createPixmap();
                   clearClipList();
                   W nr2 = gget_for(getParentGID(),getClipList());
                   setClipNum(nr2);
                   RECT r;
                   W nr  = wsta_dsp(_window, &r,NULL);
                   r.c.top =0;
                   r.c.left =0;
                   r.c.right =_w_w;
                   r.c.bottom =_w_h;
                   _evh_expose(&r);
                   wend_dsp(_window);
//TEST
//                   if (WSGIbtronAppDev()->getMouseGrabbed() != False){
//                     _copy_area(0,0,_w_w,_w_h,0,0,WS_PIXMAP_TO_WINDOW);
//                   }
                 }
               }
             }
             break;
    case WSDEV_BACKCOLOR:
             _bg = *(short*)data;
dbprintf("WSDbtronWinDev::setValue back color..%s:%d bg=%d\n",__FILE__,__LINE__,_bg);
             break;
    case WSDEV_BACK_PIXMAP:
             _bg_pix = *(short*)data;
             if (getVisible() != False){
               short x,y;
               getAbstPos(&x,&y);
               WSCrect r;
               r.setRect(x, y, _w_w, _w_h);
               _expose_ex(&r);
             }
             break;
    case WSDEV_TITLE_BAR:
             _title_bar = *(char*)data;
             switch(_title_bar){
               case WS_NO_TITLE:
                 _attr = WA_NOFRAME | WA_TITL;
                 break;
               case WS_FULL_TITLE:
                 _attr = WA_SIZE | WA_HHDL | WA_VHDL | WA_FMOVE | WA_THIN;
                 break;
               case WS_ONLY_TITLE:
                 _attr = WA_FMOVE;
                 break;
               case WS_MINI_BTN:
                 _attr = WA_SIZE | WA_HHDL | WA_VHDL | WA_FMOVE | WA_THIN;
                 break;
               case WS_MAX_BTN:
                 _attr = WA_SIZE | WA_HHDL | WA_VHDL | WA_FMOVE | WA_THIN;
                 break;
               case WS_FRAME:
                 _attr = WA_THIN;
                 break;
               default:
                 _attr = WA_SIZE | WA_HHDL | WA_VHDL | WA_FMOVE | WA_THIN;
                 break;
             };
             break;
    case WSDEV_TITLE_STRING:
             {
               char* vstr = (char*)data;
               long encode = WSGIappLocaleSet()->getDefaultEncoding();
               _title_str.setString(vstr,encode);
               if (_window != 0){
                 long tclen=0;
                 TC* tstr2 = WSGFbtronStringToTc2(
                                _title_str.getString(WS_EN_UTF8),
                                &tclen);
                 if (tstr2 != NULL){
                   wset_tit(_window,-1,tstr2,0);
                   delete tstr2;
                 }
               }
             }
             break;
    case WSDEV_FLOAT_ON_TOP:
             if (*(char*)data == False){
                _top_float = False;
             }else{
                _top_float = True;
             }
             break;
    case WSDEV_MOUSE_NO:
             {
               _mno = *(WSCushort*)data;
               _btron_mouse_value* val = (_btron_mouse_value*)WSGIappMouse()->getMouseCursor(_mno);
               if (val != NULL){
                 W style = val->_style;
                 COLOR fg = (COLOR)val->_fg;
                 COLOR bg = (COLOR)val->_bg;
                 gset_ptr(style,NULL,fg,bg);
               }
             }
             break;
    case WSDEV_NO_FRAME:  
//             _top_float = False;
             _no_frame = *(char*)data;
             break;
    case WSDEV_GRAB_POINTER:{
               WSCbool fl = *(WSCbool*)data;
               if (fl != False){
//printf("WSDbtronFormDev::setValue WSDEV_GRAB_POINTER.. grabed.\n");
                 WSGIbtronAppDev()->setGrabTarget(this);
               }else{
//printf("WSDbtronFormDev::setValue WSDEV_GRAB_POINTER.. cancel\n");
                 WSGIbtronAppDev()->setGrabTarget(NULL);
               }
               return WS_NO_ERR;
             }
    case WSDEV_MODAL:
             if (*(char*)data == False){
               _modal = False;
             }else{
               _modal = True;
             }
             break;
    case WSDEV_WINDOW_STATE:
             break;
    case WSDEV_POPUP_PARENT: 
             break;
    case WSDEV_MAP_STATUS: 
             break;
    case WSDEV_WIN_ACTIVE: 
             break;
    default:
      return WS_ERR;
  }

  return WS_NO_ERR;
}

long WSDbtronWinDev::createWindow(){
  _diff_x = 0;
  _diff_y = 0;
  _diff_w = 0;
  _diff_h = 0;
dbprintf("### WSDbtronWinDev::createWindow %s vis=%d attr=0x%x\n",getAttachedClient()->getInstanceName(),getVisible(),_attr);
  if (getVisible() == False){
    return WS_ERR;
  }
  if (_window != 0){
    return WS_NO_ERR;
  }
  _no_frame_first_time = 0;
//  _top_float = False;

  short x,y;    
  WSCushort w,h;    
  getWindowSize(&x,&y,&w,&h);
  if (w == 0){
    w = 1;
  }
  if (h == 0){
    h = 1;
  }
  _transient = False;

  RECT rect;
  rect.c.left = x;
  rect.c.top = y;
//  if (_attr != 0){
//    rect.c.right = x+w+100;
//    rect.c.bottom = y+h+100;
//  }else{
  rect.c.right = x+w;
  rect.c.bottom = y+h;
//  }
  UW attr = _attr | WA_WORK | WA_FMOVE | WA_BGDSP;
  if ( _top_float != False){
//    attr |= WA_POPUP;
  }

  TC* tstr2 = NULL;
  if (strcmp(_title_str.getString(),"")){
    long tclen=0;
    tstr2 = WSGFbtronStringToTc2( _title_str.getString(WS_EN_UTF8),&tclen);
dbprintf("WSDbtronWinDev::createWindow title=#%s# tclen=%d\n",_title_str.getString(),tclen);
  }

  if (_top_float != False && _no_frame != False){
//    UW attr = WA_SUBW | WA_NOFRAME | WA_TITL | WA_WORK | WA_FMOVE | WA_BGDSP;
//    UW attr = WA_NOFRAME | WA_TITL | WA_WORK | WA_FMOVE | WA_BGDSP;
    W pid;
    W parent = wget_act(&pid);
    WSCbase* client = getAttachedClient();
    if (client != NULL){
      if (client->cast("WSCpulldownMenuPopup") == NULL &&
          client->cast("WSCballoonHelp") == NULL ){
        pid = 1;
      }
    }
    if (pid == 0){
//dbprintf("WSDbtronWinDev::createWindow begin wopn_wnd\n");
      UW attr = WA_NOFRAME | WA_SUBW | WA_TITL | WA_WORK | WA_FMOVE | WA_BGDSP;
      _window = wopn_wnd(attr,parent,&rect,NULL,2,NULL,NULL,NULL);
    }else{
//dbprintf("WSDbtronWinDev::createWindow begin wopn_wnd2\n");
      UW attr = WA_NOFRAME | WA_TITL | WA_WORK | WA_FMOVE | WA_BGDSP;
      _window = wopn_wnd(attr,0,&rect,NULL,2,NULL,NULL,NULL);
    }
//    _window = wopn_pwd(&rect);
//printf("wopn_pwd!!! _window=0x%x parent=0x%x\n",_window,parent);
  }else{
    if (tstr2 != NULL){
//dbprintf("WSDbtronWinDev::createWindow begin wopn_wnd3\n");
      _window = wopn_wnd(attr,0,&rect,NULL,2,tstr2,NULL,NULL);
      delete tstr2;
    }else{
//dbprintf("WSDbtronWinDev::createWindow begin wopn_wnd4\n");
      _window = wopn_wnd(attr,0,&rect,NULL,2,NULL,NULL,NULL);
    }
//printf("wopn_wnd!!! _window=0x%x\n",_window);
  }
dbprintf("WSDbtronWinDev::createWindow _window=0x%x\n",_window);
//printf("WSDbtronWinDev::createWindow %d,%d,%d,%d w=0x%x\n",_w_x,_w_y,_w_w,_w_h,_window);
//dbprintf("WSDbtronWinDev::createWindow %d,%d,%d,%d\n",_w_x,_w_y,_w_w,_w_h);
  if (_window > 0){
//    WSGIbtronAppDev()->addWindow(_window);
    RECT rect;
    W rv = wget_wrk(_window,&rect);
    if (rv == E_OK){
      if (rect.c.right > _w_w){
        _w_w = rect.c.right;
      }
      if (rect.c.bottom > _w_h){
        _w_h = rect.c.bottom;
      }
    }

    wset_dat(_window,(long)((WSDbtronFormDev*)this));
    createContext();
    if (WSGIbtronAppDev()->getGidInitialized() == False){
      WSGIbtronAppDev()->setGid(_gid);
    }

    setPixmapStyle(WS_DYNAMIC_PIXMAP);
    createPixmap();

    _expose_list.add((void*)_window);
  }
  return WS_NO_ERR;
}

long WSDbtronWinDev::destroyWindow(){
  if (_window > 0){
    if (WSGIbtronAppDev()->getGrabTarget() != NULL &&
        WSGIbtronAppDev()->getGrabTarget()->getParentWindow() == _window){
      WSGIbtronAppDev()->setGrabTarget(NULL);
    }
    if (WSGIbtronAppDev()->getBtnPressGrabTarget() != NULL &&
        WSGIbtronAppDev()->getBtnPressGrabTarget()->getParentWindow() == _window){
      WSGIbtronAppDev()->setBtnPressGrabTarget(NULL);
    }
//    WSGIbtronAppDev()->delWindow(_window);
    wcls_wnd(_window,CLR);
    _window = 0;
  }
  if (getChildDevListFlag() != False){
    WSDbtronFormDev* pdev = getParentAreaDev();
    if (pdev != NULL){
      pdev->delChildDevList(this);
    }else{
      setChildDevListFlag(False);
    }
  }

  _diff_x = 0;
  _diff_y = 0;
  _diff_w = 0;
  _diff_h = 0;
dbprintf("WSDbtronWinDev::destroyWindow not implemented\n");

  return WS_NO_ERR;
}

long WSDbtronWinDev::setVisible(WSCbool fl){
//printf("WSDbtronWinDev::setVisible vis=%d\n",getVisible());
//dbprintf("WSDbtronWinDev::setVisible vis=%d\n",getVisible());
//WSMFtrace("WSCbtronWinDev::setVisible _w_h=%d\n",_w_h);
//  WSCbool bk = getVisible();
  WSDdev::setVisible(fl);
  if (fl == False){
    if (_window != 0){
      destroyWindow();
//      onUnmap();
    }
    if (WSGIbtronAppDev()->getGrabTarget() != NULL &&
        WSGIbtronAppDev()->getGrabTarget()->getParentWindow() == _window){
      WSGIbtronAppDev()->setGrabTarget(NULL);
    }
    if (WSGIbtronAppDev()->getBtnPressGrabTarget() != NULL &&
        WSGIbtronAppDev()->getBtnPressGrabTarget()->getParentWindow() == _window){
      WSGIbtronAppDev()->setBtnPressGrabTarget(NULL);
    }

  }else{
    if (_window == 0){
       createWindow();
    }
    if (WSGIbtronAppDev()->getMouseGrabbed() != False){
      _copy_area(0,0,_w_w,_w_h,0,0,WS_PIXMAP_TO_WINDOW);
    }
  }
  return WS_NO_ERR;
}

WSDdev* WSDbtronWinDev::getParentDev(){
  return NULL;
}

long WSDbtronWinDev::getValue(long kind,void* val){
  return WSDwindowDev::getValue(kind,val);
}
long WSDbtronWinDev::getWindowResource(){
  return (long)getWindow();
}
long WSDbtronWinDev::getContextResource(){
#ifdef MEMGID
  if (getPixmapStyle() != WS_DIRECT_WINDOW){
    long ret = (long)getMemGID();
    if (ret == 0){
      createPixmap();
      ret = (long)getMemGID();
      if (ret == 0){
        return -1;
      }
    }
    return ret;
  }
#endif
  long ret = (long)getGID();
  if (ret == 0){
    return -1;
  }
  return ret;
}
WSCbool WSDbtronWinDev::haveWindow(){
  return True;
}
long WSDbtronWinDev::createPixmap(){
//  if (getVisible() == False){
//    return False;
//  }
  if (_mem_gid != NULL){
    destroyPixmap();
#if 0
    ERR ret = gcls_env(_mem_gid);
dbprintf("WSDbtronFormDev::createPixmap() gcls_env=0x%x\n",ret);
    _mem_gid = NULL;
#endif
  }
  short x,y;
  WSCushort w,h;
  getWindowSize(&x,&y,&w,&h);
  if (w <1){
    w = 1;
  }
  if (h <1){
    h = 1;
  }
                                                                                
  _mem_gid = WSGIbtronAppDev()->getNewMemGid(w,h);
  WSDwindowDev::createPixmap();
//dbprintf("WSDbtronWinDev::createPixmap() wh=%d,%d %s\n",w,h,getAttachedClient()->getInstanceName());
  _setup_pixmap(0,0,w,h,_bg,_bg_pix);
  exposeExecute(0,0,w,h);

#ifdef F_MEMGID
  WSClistData children = getChildDevList();
  long num = children.getNum();
  long i;
  for(i=0; i<num; i++){
    WSDbtronFormDev* child =(WSDbtronFormDev*)children[i];
    child->createPixmap();
  }
#endif
//dbprintf("CC WSDbtronWinDev::createPixmap() done. %s\n",getAttachedClient()->getInstanceName());
  return WS_NO_ERR;
}
long WSDbtronWinDev::destroyPixmap(){
  if (_mem_gid != NULL){
    ERR ret = gcls_env(_mem_gid);
dbprintf("WSDbtronFormDev::destroyPixmap() gcls_env=0x%x\n",ret);
    _mem_gid = NULL;
  }
  WSDwindowDev::destroyPixmap();
  WSClistData children = getChildDevList();
  long num = children.getNum();
  long i;
  for(i=0; i<num; i++){
    WSDbtronFormDev* child =(WSDbtronFormDev*)children[i];
    child->destroyPixmap();
  } 
  return WS_NO_ERR;
}
long WSDbtronWinDev::createContext(){
  destroyContext();
  _gid = wget_gid(_window);
//printf("WSDbtronWinDev::createContext _gid=0x%x\n",_gid);
  return WS_NO_ERR;
}
long WSDbtronWinDev::destroyContext(){
  if (_gid > 0){
    gcls_env(_gid);
    _gid = 0;
  }
  return WS_NO_ERR;
}
WSCbool WSDbtronWinDev::getParentVisible(){
  return getVisible();
}
