//
// Copyright (C) 1999-2004 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 <WScom.h>
#include <WSCbase.h>
#include <nx/WSDnxDragDrop.h>
#include <nx/WSDnxAppDev.h>
#include <nx/WSDnxFormDev.h>
#include <nx/WSDnxMouse.h>

#define MAX_ARGS 10

WSMFclassInit(WSDnxDragDrop,WSDdragDrop);

WSDdragDrop* _nxDrag_drop_create_handler_(){
  return new WSDnxDragDrop;
}

class _wsd_nxDragdrop_init{
  public:
    _wsd_nxDragdrop_init(){
        WSDdragDrop::setCreateHandler(_nxDrag_drop_create_handler_);
    };
};
static _wsd_nxDragdrop_init  execute_init;

WSDnxDragDrop* WSGInxAppDragDrop(){
  WSDdragDrop* dd = WSGIappDragDrop();
  if (dd != NULL){
    WSDnxDragDrop* xdd = (WSDnxDragDrop*)dd->cast("WSDnxDragDrop");
	return xdd;
  }else{
    return NULL;
  }
}

WSCbase* WSDnxDragDrop::_drag_client = NULL;

WSDnxDragDrop::WSDnxDragDrop(){
  _under_dragging = 0;
}

WSDnxDragDrop::~WSDnxDragDrop(){
}

void WSDnxDragDrop::executeDrop(){
//printf("WSDnxDragDrop::executeDrop..\n");
  if (_under_dragging == 0){
    _drag_client = NULL;
    return;
  }
  _under_dragging = 0;
//printf("WSDnxDragDrop::executeDrop.. here1\n");

  WSCbase* drop_site = NULL;
  long num = _drop_site_list.getNum();
  long i;
  for(i=num -1; i>-1; i--){
     WSCbase* site = (WSCbase*)_drop_site_list.getData(i);
     WSDdev* dev = site->getdev();
     if (dev == NULL){
       continue;
     }



     WSDnxFormDev* bdev = (WSDnxFormDev*)dev->cast("WSDnxFormDev");
     if (bdev == NULL){
       continue;
     }
     short px,py;
	 WSGIappMouse()->getMousePosition(&px,&py);

     short dx,dy;
     bdev->getParentAbstPos(&dx,&dy);
     WSDnxFormDev* tdev = bdev->getChildWithPoint(px - dx,py - dy);
     while(1){
       if (tdev == NULL){
         break;
       }
       WSCbase* client = tdev->getAttachedClient();
       if (client != NULL){
         if (client->getUserData("DROP-PROC") != NULL){
           break;
         }
       }
       tdev = tdev->getParentAreaDev();
       if (tdev == bdev){
         break;
       }
     }

//printf("WSDnxDragDrop::executeDrop.. pt=%d,%d\n",px,py);
     if (tdev != NULL){
       drop_site = tdev->getAttachedClient();
       break;
     }
  }

  if (drop_site != NULL){
    void (*hd)(WSCbase*,WSCbase*) =
       (void(*)(WSCbase*,WSCbase*))drop_site->getUserData("DROP-PROC");
    if (hd != NULL){
      hd(drop_site,_drag_client);
    }
  }
}


WSCbool WSDnxDragDrop::getDragState(){
  return _under_dragging;
}

void WSDnxDragDrop::_btn_press_drag_start(WSCbase* client){
   WSDnxDragDrop* obj = (WSDnxDragDrop*)client->getUserData("WSDRAG-SERV");
   if (obj->_under_dragging == True){
     return;
   }
   obj->_under_dragging = True;
   _drag_client = client;
}

long WSDnxDragDrop::registerDragSite(WSCbase* client,char* msg){
  WSCprocedure* ac = new WSCprocedure("WSDRAG-START",WSEV_MOUSE_PRESS);
  ac->setFunction(_btn_press_drag_start,"_btn_press_drag_start");
  client->addProcedure(ac);
  client->setUserData("WSDRAG-AC",(void*)ac);
  client->setUserData("WSDRAG-MSG",(void*)WSGFstrdup(msg));
  client->setUserData("WSDRAG-SERV",(void*)this);
  return WS_NO_ERR;
}

long WSDnxDragDrop::unregisterDragSite(WSCbase* client){
  WSCprocedure* ac = (WSCprocedure*)client->getUserData("WSDRAG-AC");
  char* msg = (char*)client->getUserData("WSDRAG-MSG");
  if (msg != NULL){
    delete msg;
  }
  client->delProcedure(ac);
  delete ac;
  client->setUserData("WSDRAG-AC",(void*)NULL);
  client->setUserData("WSDRAG-MSG",(void*)NULL);
  return WS_NO_ERR;
}

long WSDnxDragDrop::registerDropSite(WSCbase* dropc,char* msg,void(*hd)(WSCbase*,WSCbase*)){
#ifdef PDBG
  printf("WSDnxDragDrop::registerDropSite #%s# num=%d 0x%x\n",
  dropc->getInstanceName(),_drop_site_list.getNum(),dropc);
#endif

  dropc->setUserData("WSDRAG-MSG",(void*)WSGFstrdup(msg));
  dropc->setUserData("DROP-PROC",(void*)hd);
  _drop_site_list.add((void*)dropc);

  return WS_NO_ERR;
}

long WSDnxDragDrop::unregisterDropSite(WSCbase* client){
#ifdef PDBG
  printf("WSDnxDragDrop::unregisterDropSite #%s# num=%d 0x%x\n",
  client->getInstanceName(),_drop_site_list.getNum(),client);
#endif
  char* msg = (char*)client->getUserData("WSDRAG-MSG");
  if (msg != NULL){
    delete msg;
  }
  client->setUserData("WSDRAG-MSG",(void*)NULL);
  _drop_site_list.del(client);
#ifdef PDBG
  printf("WSDnxDragDrop::unregisterDropSite done. num=%d\n",
  _drop_site_list.getNum());
#endif

  return WS_NO_ERR;
}


