//
// 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 <WScom.h>
#include <WStcpcom.h>
#include <x11/WSDunixThread.h>
#include <x11/WSDxappDev.h>
#include <stdio.h>
#include <fcntl.h>
#include <WSClocaleSet.h>
#include <pthread.h>

WSMFclassInit(WSDunixThread,WSDthread);

WSDthread* _unix_th_chandler(){
  return new WSDunixThread;
}

void WSGFinitializeUnixThread(){
    WSDthread::setCreateInstanceHandler((void*)_unix_th_chandler);
}

class _unix_th_init {
  public: _unix_th_init(){
    WSDthread::setCreateInstanceHandler((void*)_unix_th_chandler);
  };
};
_unix_th_init  _unix_th_init_execute;

WSDunixThread::WSDunixThread(){
  pthread_mutex_init(&_mutex,NULL);
  _id = 0;
}

WSDunixThread::~WSDunixThread(){
  if (_id != 0){
    terminateThread();
  }
}

long WSDunixThread::createThread(void* data){
  pthread_mutex_lock(&_mutex);
  if (_proc == 0){
    pthread_mutex_unlock(&_mutex);
    return WS_ERR;
  }
  if (_id != 0){
    pthread_mutex_unlock(&_mutex);
    return WS_ERR;
  }
  _ptr = data;
  int ret = pthread_create(&_id,NULL,_thread_start_handler,this);
  if (ret != 0){
    _id = 0;
  }
  pthread_mutex_unlock(&_mutex);
  return WS_NO_ERR;
}

void* WSDunixThread::_thread_start_handler(void* ptr){
  WSDunixThread* _this = (WSDunixThread*)ptr;
  void* ret = NULL;
  if (_this->_proc != NULL){
    ret = _this->_proc(_this,_this->_ptr);
  }
  pthread_mutex_lock(&_this->_mutex);
  _this->_id = 0;
  pthread_mutex_unlock(&_this->_mutex);
  pthread_exit(ret);
}

long WSDunixThread::detachThread(){
  if (_id != 0){
    int ret = pthread_detach(_id);
    if (ret == 0){
      return WS_NO_ERR;
    }
  }
  return WS_ERR;
}
long WSDunixThread::terminateThread(){
  if (_id == 0){
    return WS_ERR;  
  }
  pthread_mutex_lock(&_mutex);
  pthread_cancel(_id);
  pthread_mutex_unlock(&_mutex);
  return WS_ERR;  
}
long WSDunixThread::joinThread(void** retval){
  if (_id != 0){
    int ret = pthread_join(_id,retval);
    if (ret == 0){
      return WS_NO_ERR;
    }
    return WS_ERR;
  }
  return WS_ERR;
}
long WSDunixThread::getStatus(){
  if (_id == 0){
    return WS_THREAD_STOPPED;
  }
  return WS_THREAD_RUNNING;
}
long WSDunixThread::execCallback(void* data){
  _callback_data = data;
  Display* disp = XOpenDisplay((char*)NULL);
  if (disp == NULL){
    return WS_ERR;
  }

  Atom atom = XInternAtom(disp,"THREAD-MESSAGE",False);
  Window win = XtWindow(WSGIxwinAppDev()->appWidget());
  XClientMessageEvent  cm;
  cm.type = ClientMessage;
  cm.display = disp;
  cm.window = win;
  cm.message_type = atom;
  cm.format = 32;
  WSDunixThread* ptr = this;
  memcpy(cm.data.l,&ptr,sizeof(WSDunixThread*));
  XSendEvent(disp,win,False,NoEventMask,(_XEvent *)&cm);
//printf("send message... win=0x%x\n",win);
  Window  win2  = XCreateSimpleWindow(disp,DefaultRootWindow(disp),400,400,
                                 200,200,2, 0, 1);
  XEvent event;
  XSendEvent(disp,win2,False,NoEventMask,(_XEvent *)&cm);
  XNextEvent(disp, &event);
  XDestroyWindow(disp,win2);

  XCloseDisplay(disp);
  return WS_NO_ERR;
}

