//
// 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 <X11/Xlib.h>
#include <X11/Xatom.h>
#include <x11/WSDxmessage.h>
#include <x11/WSDxappDev.h>
#include <WScom.h>
#include <WSClistData.h>

WSMFclassInit(WSDxmessage,WSDmessage);

WSDmessage* _xclient_msg_create(){
  return new WSDxmessage;
}

class _xclient_msg_init {
  public: _xclient_msg_init(){
    WSDmessage::setCreateHandler(_xclient_msg_create);
  };
};
_xclient_msg_init  _xclient_msg_init_execute;

WSDxmessage::WSDxmessage(){
 _ext_send_msg1 = extSendMessage;
 _ext_send_msg2 = extSendNewMessage;
}

WSDxmessage::~WSDxmessage(){}

long WSDxmessage::initialize(){
  WSCstring mstr;
  
  _display = WSGIxwinAppDev()->display();
  _tmpw = XtWindow(WSGIxwinAppDev()->appWidget());

  mstr << WS_TRANS_MESSAGE << _id.getString();
//printf("WSDxmessage::initialize #%s#\n",(char*)mstr);
  Atom cwin = XInternAtom( _display, (char*)mstr, False);

  XChangeProperty( _display, DefaultRootWindow(_display), cwin,
                     XA_WINDOW, 32, PropModeReplace,
                    (WSCuchar *)&_tmpw, 1);
  _ext_message = XInternAtom(_display, _id.getString(), False);

  XtAddEventHandler(WSGIxwinAppDev()->appWidget(),NoEventMask,TRUE,
                      (XtEventHandler)&WSDxmessage::ext_callback_handler,
                      (XtPointer)this);
  return 0 ;
}

static WSCstring    mstr_bk;
int WSDxmessage::extSendNewMessage(char* disp,char *message,char *data){
  mstr_bk = "";
  return WSDxmessage::extSendMessage(disp,message,data);
}

struct _ws_disp_name {
  char*     name;
  Display* disp;
};

#define WS_SEND_LEN 15
int WSDxmessage::extSendMessage(char* dispname, char *message, char *data){
  if (data == NULL){
    data = "";
  }
  long ptr = 0;
  char buf[WS_SEND_LEN +1];
  long len = strlen(data);
  long ret;
  while(1){
    strncpy(buf,&data[ptr],WS_SEND_LEN);
    buf[WS_SEND_LEN] = 0;
    ret = _extSendMessage(dispname,message,buf);
    ptr+= WS_SEND_LEN;
    if (ptr+1 > len){
      break;
    }
  }
  return ret;
}
int WSDxmessage::_extSendMessage(char* dispname, char *message, char *data){
    WSCstring mstr;
    Display* disp = NULL;
    int      fmt;
    WSCulong nitems,left;
    Atom     a1,type,a2;
    XEvent   event;
    XClientMessageEvent  cm;
    Window* win2;
    if (dispname == NULL){
      dispname = "";
    }
static WSClistData list;
    for(int k=0; k < list.getNum(); k++){
      _ws_disp_name* fpd = (_ws_disp_name*)list.getData(k);
      if (!strcmp(fpd->name,dispname)){
         disp = fpd->disp;
         break;
      }
    }

    if (disp == NULL){    
      _ws_disp_name* newitem = new _ws_disp_name;


      mstr_bk = message;
      mstr << WS_TRANS_MESSAGE << message;
//printf("WSDxmessage::extSendMessage #%s#\n",(char*)mstr);

      disp = XOpenDisplay(dispname);
      a1 = XInternAtom(disp,(char*)mstr, False);

      if (XGetWindowProperty(disp,DefaultRootWindow(disp),a1,0,4,False,
                           XA_WINDOW, &type, &fmt, &nitems,&left, 
                           (WSCuchar **)&win2)
           != Success || type != XA_WINDOW){
        XCloseDisplay(disp);
        disp = NULL;
        return -1;
      }

      newitem->name = WSGFstrdup(dispname);
      newitem->disp = disp;
      list.add((void *)newitem);

      a2 = XInternAtom(disp,message,False);

    }else{
      mstr << WS_TRANS_MESSAGE << message;
//printf("WSDxmessage::extSendMessage2  #%s#\n",(char*)mstr);
      a1 = XInternAtom(disp,(char*)mstr, False);

      if (XGetWindowProperty(disp,DefaultRootWindow(disp),a1,0,4,False,
                           XA_WINDOW, &type, &fmt, &nitems,&left, 
                           (WSCuchar **)&win2)
        != Success || type != XA_WINDOW){
        return -1;
      }
      a2 = XInternAtom(disp,message,False);
      mstr_bk = message;
    }

    cm.type = ClientMessage;
    cm.display = disp;
    cm.window = *win2;
    cm.message_type = a2;
    cm.format = 32;
    memcpy(cm.data.l,data,sizeof(char)*16);
    XSendEvent(disp,*win2,False,NoEventMask,(_XEvent *)&cm);

    Window  win  = XCreateSimpleWindow(disp,DefaultRootWindow(disp),400,400,
                               200,200,2, 0, 1);
    XSendEvent(disp,win,False,NoEventMask,(_XEvent *)&cm);

    XNextEvent(disp, &event);   
    XDestroyWindow(disp,win);

    return 0;
}

void WSDxmessage::sendMessage(char *data){
  if (_exec_action != NULL){
    _exec_action(data);
  }else{
    _exec_action2(data,_data);
  }
}

void WSDxmessage::ext_callback_handler(Widget,XtPointer clientData,
                                     XEvent *e,WSCbool*){
//printf("WSDxmessage::ext_callback_handler...\n");
  WSDxmessage *obj = (WSDxmessage *)clientData;
  obj->selector(e);

};
void WSDxmessage::selector(XEvent *e){
//printf("WSDxmessage::selector...\n");
  if (e->type == ClientMessage &&
      e->xclient.message_type == _ext_message){
    if (_exec_action != NULL){
//printf("selector1...\n");
      _exec_action(e->xclient.data.b);
    }else{
//printf("selector2...\n");
      _exec_action2(e->xclient.data.b,_data);
    }

  }
}
