//
// 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 <WSCimageSet.h>
#include <WSCcolorSet.h>
#include <WSDtimer.h>
#include <WSCbase.h>
#include <WSDmouse.h>
#include <WSClocaleSet.h>
#include <nx/WSDnxWinDev.h>
#include <nx/WSDnxAppDev.h>
#include <nx/WSDnxMouse.h>

#define MEMGID

WSMFclassInit(WSDnxWinDev,WSDnxFormDev);
WSDdev* _wsdnxWindev_init_(){
dbprintf("_wsdnxWindev_init_() %s:%d started..\n",__FILE__,__LINE__);
  return new WSDnxWinDev();
}

class _WSDnxWinDev_init_ {
  public:_WSDnxWinDev_init_(){
dbprintf("_WSDnxWinDev_init_() %s:%d started..\n",__FILE__,__LINE__);
     WSGIappDevice()->setCreateHandler("windowDev",_wsdnxWindev_init_);
  };
};
static _WSDnxWinDev_init_ _init_to_run_WSDnxWinDev_;
//static Atom wm_protocols = 0;
//static Atom wm_delete = 0;
//extern TC* WSGFnxStringToTc(char*,long*);
//extern TC* WSGFnxStringToTc2(char*,long*);

WSDnxWinDev::WSDnxWinDev(){
  _diff_x = 0;
  _diff_y = 0;
  _diff_w = 0;
  _diff_h = 0;
  _attr = 0;

  _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;
}

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

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

long WSDnxWinDev::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("WSDnxWinDev::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){
               // TODO move window..
               // move to _w_x,_w_y,_w_w+_diff_w,_w_h+_diff_h
               if (getVisible() != False){
                 // if need to expose by moving window..
dbprintf("WSDnxWinDev::setValue need execute expose..%s:%d\n",__FILE__,__LINE__);
               }
             }
             break;
    case WSDEV_WIDTH: 
    case WSDEV_HEIGHT: 
dbprintf("WSDnxWinDev::setValue W/H %d,%d w=0x%x vis=%d\n",_w_w,_w_h,_window,getVisible());
             if (_mem_context != 0){
               destroyPixmap();
             }
             if (_window != 0){
               // TODO resize window..
               // resize  _w_x,_w_y,_w_w+_diff_w,_w_h+_diff_h

               if (getVisible() != False){
                 if ( 0 ){ //if need to expose
dbprintf("WSDnxWinDev::setValue need execute expose..%s:%d\n",__FILE__,__LINE__);
                   createPixmap();
                   clearClipList();
                   //TODO set clip mask.
                   //example.  nr2 = gget_for(getParentGID(),getClipList());
                   //example.  setClipNum(nr2);
                   WSCrect r;
                   r.x =0;
                   r.y =0;
                   r.width =_w_w;
                   r.height =_w_h;
                   _evh_expose(&r);
                 }
               }
             }
             break;
    case WSDEV_BACKCOLOR:
             _bg = *(short*)data;
dbprintf("WSDnxWinDev::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:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               case WS_FULL_TITLE:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               case WS_ONLY_TITLE:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               case WS_MINI_BTN:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               case WS_MAX_BTN:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               case WS_FRAME:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
               default:
                 // TODO set window attribute.
                 _attr = 0;
                 break;
             };
             break;
    case WSDEV_TITLE_STRING:
             {
               char* vstr = (char*)data;
               long encode = WSGIappLocaleSet()->getDefaultEncoding();
               _title_str.setString(vstr,encode);
               if (_window != 0){
                 //TODO set _title_str to _window..
               }
             }
             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;
               _nx_mouse_value* val = (_nx_mouse_value*)WSGIappMouse()->getMouseCursor(_mno);
               if (val != NULL){
                 //TODO set value to mouse
               }
             }
             break;
    case WSDEV_NO_FRAME:  
             _no_frame = *(char*)data;
             break;
    case WSDEV_GRAB_POINTER:{
               WSCbool fl = *(WSCbool*)data;
               if (fl != False){
//printf("WSDnxFormDev::setValue WSDEV_GRAB_POINTER.. grabed.\n");
                 WSGInxAppDev()->setGrabTarget(this);
               }else{
//printf("WSDnxFormDev::setValue WSDEV_GRAB_POINTER.. cancel\n");
                 WSGInxAppDev()->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 WSDnxWinDev::createWindow(){
  _diff_x = 0;
  _diff_y = 0;
  _diff_w = 0;
  _diff_h = 0;
dbprintf("### WSDnxWinDev::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;

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

  WSCrect rect;
  rect.x = x;
  rect.y = y;
  rect.width = w;
  rect.height = h;

  if ( _top_float != False){
    // TODO set _attr POPUP style.
  }

  if (_top_float != False && _no_frame != False){
    // TODO create popup or noframe window..
    // _window = xxx
  }else{
    // TODO create window..
    // _window = xxx
  }
dbprintf("WSDnxWinDev::createWindow _window=0x%x\n",_window);
  if (strcmp(_title_str.getString(),"")){
    // set _title_str to _window
  }


  if (_window > 0){
    // TODO adjust window size..
    // TODO get real window size..
    // _w_w = real sise.
    // _w_h = real sise.

    //set window to "this" pointer.
    createContext();

    // TODO if need, set the sample of context to appdev.
    // example.   if (WSGInxAppDev()->getGidInitialized() == False){
    // example.     WSGInxAppDev()->setGid(_context);
    // example.   }

    setPixmapStyle(WS_DYNAMIC_PIXMAP);
    createPixmap();

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

long WSDnxWinDev::destroyWindow(){
  if (_window > 0){
    if (WSGInxAppDev()->getGrabTarget() != NULL &&
        WSGInxAppDev()->getGrabTarget()->getParentWindow() == _window){
      WSGInxAppDev()->setGrabTarget(NULL);
    }
    if (WSGInxAppDev()->getBtnPressGrabTarget() != NULL &&
        WSGInxAppDev()->getBtnPressGrabTarget()->getParentWindow() == _window){
      WSGInxAppDev()->setBtnPressGrabTarget(NULL);
    }
    // TODO destroy window here.

    _window = 0;
  }
  if (getChildDevListFlag() != False){
    WSDnxFormDev* pdev = getParentAreaDev();
    if (pdev != NULL){
      pdev->delChildDevList(this);
    }else{
      setChildDevListFlag(False);
    }
  }

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

  return WS_NO_ERR;
}

long WSDnxWinDev::setVisible(WSCbool fl){
  WSDdev::setVisible(fl);
  if (fl == False){
    if (_window != 0){
      destroyWindow();
    }
    if (WSGInxAppDev()->getGrabTarget() != NULL &&
        WSGInxAppDev()->getGrabTarget()->getParentWindow() == _window){
      WSGInxAppDev()->setGrabTarget(NULL);
    }
    if (WSGInxAppDev()->getBtnPressGrabTarget() != NULL &&
        WSGInxAppDev()->getBtnPressGrabTarget()->getParentWindow() == _window){
      WSGInxAppDev()->setBtnPressGrabTarget(NULL);
    }

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

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

long WSDnxWinDev::getValue(long kind,void* val){
  return WSDwindowDev::getValue(kind,val);
}
long WSDnxWinDev::getWindowResource(){
  return (long)getWindow();
}
long WSDnxWinDev::getContextResource(){
#ifdef MEMGID
  if (getPixmapStyle() != WS_DIRECT_WINDOW){
    long ret = (long)getMemContext();
    if (ret == 0){
      createPixmap();
      ret = (long)getMemContext();
      if (ret == 0){
        return -1;
      }
    }
    return ret;
  }
#endif
  long ret = (long)getContext();
  if (ret == 0){
    return -1;
  }
  return ret;
}
WSCbool WSDnxWinDev::haveWindow(){
  return True;
}
long WSDnxWinDev::createPixmap(){
  if (_mem_context != NULL){
    destroyPixmap();
  }
  short x,y;
  WSCushort w,h;
  getWindowSize(&x,&y,&w,&h);
  if (w <1){
    w = 1;
  }
  if (h <1){
    h = 1;
  }
                                                                                
  _mem_context = WSGInxAppDev()->getNewMemContext(w,h);
  if (_mem_context == 0){
    return WS_ERR;
  }

  WSDwindowDev::createPixmap();
  _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++){
    WSDnxFormDev* child =(WSDnxFormDev*)children[i];
    child->createPixmap();
  }
#endif
  return WS_NO_ERR;
}
long WSDnxWinDev::destroyPixmap(){
  if (_mem_context != NULL){
    WSGInxAppDev()->destroyMemContext(_mem_context);
    _mem_context = NULL;
  }

  WSDwindowDev::destroyPixmap();
  WSClistData children = getChildDevList();
  long num = children.getNum();
  long i;
  for(i=0; i<num; i++){
    WSDnxFormDev* child =(WSDnxFormDev*)children[i];
    child->destroyPixmap();
  } 
  return WS_NO_ERR;
}
long WSDnxWinDev::createContext(){
  destroyContext();
  // TODO set context related with window to _context 
  // example.__context = get_graphics_context(_window);
  return WS_NO_ERR;
}
long WSDnxWinDev::destroyContext(){
  if (_context > 0){
    // TODO destroy _context
    _context = 0;
  }
  return WS_NO_ERR;
}
WSCbool WSDnxWinDev::getParentVisible(){
  return getVisible();
}
