//
// 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 <WSCconductor.h>
#include <WSDserialize.h>
#include <WSDsocketSerialize.h>
#include <WSCbase.h>
#include <WSDsocket.h>
#include <WSDappDev.h>
#include <WSCbaseList.h>
#include <WSDtimer.h>
#include <WSCRbaseList.h>

#define WS_RETRY_CNT 3

static WSCconductor* _the_app_conductor = NULL;
WSCconductor* WSGIconductor(){
  if (_the_app_conductor == NULL){
    _the_app_conductor = new WSCconductor();
  }
  return _the_app_conductor;
}
static WSCbinType* _the_app_bin_type = NULL;
WSCbinType* WSGIbinType(){
  if (_the_app_bin_type == NULL){
    _the_app_bin_type = new WSCbinType();
  }
  return _the_app_bin_type;
}

WSCconductor::WSCconductor(){
  _serialize_path.setString(".",WS_EN_ISO8859_1);
  _sock = NULL;
  _csock = NULL;
  _port = WS_DEFAULT_SERVER_PORT;
  _accepted = False;
  _timeout = 10;
  _timer_id = 0;
  _need_update = False;
}
WSCconductor::~WSCconductor(){
  if (_timer_id != 0){
    WSGIappTimer()->delTimerProc(_timer_id);
    _timer_id = 0;
  }
  if (_sock != NULL){
    _sock->stopAcceptEx();
    delete _sock;
    _sock = NULL;
  }
}

long WSCconductor::addSerialize(WSDserialize* serialize){
  _serialize_list.add(serialize);
  return WS_NO_ERR;
}
long WSCconductor::add(WSCtypeServer* item){
  _type_server_list.add(item);
  return WS_NO_ERR;
}
long WSCconductor::del(WSCtypeServer* item){
  _type_server_list.del(item);
  return WS_NO_ERR;
}
WSCtypeServer* WSCconductor::searchTypeServer(char* type){
  long i;
  long num = _type_server_list.getNum();
  for(i=0; i<num; i++){
    WSCtypeServer* drcl = (WSCtypeServer*)_type_server_list[i];
    if (drcl->isHit(type) != False){
      return drcl;
    }
  }
  return NULL;
}
WSDserialize* WSCconductor::getSerialize(char* serialize_type){
  long i;
  long num = _serialize_list.getNum();
  WSDserialize* same_serialize = NULL;
  for(i=0; i< num; i++){
    WSDserialize* serialize = (WSDserialize*)_serialize_list[i];
    if (serialize->type(serialize_type) != False ){
      same_serialize = serialize;
      if ( serialize->underTransaction() == False){
        return serialize;
      }
    }
  }
  if (same_serialize != NULL){
    WSDserialize* serialize = same_serialize->createSerialize();
    return serialize;
  }
WSMFtrace("WSCconductor::getSerialize()  ERROR. default type not found.\n");
  return NULL;
}
WSDserialize* WSCconductor::getNewSerialize(char* serialize_type){
  long i;
  long num = _serialize_list.getNum();
  for(i=0; i< num; i++){
    WSDserialize* serialize = (WSDserialize*)_serialize_list[i];
    if (serialize->type(serialize_type) != False ){
      return serialize->createSerialize();
    }
  }
WSMFtrace("WSCconductor::getSerialize()  ERROR. default type not found.\n");
  return NULL;
}

char* WSCconductor::getSerializePath(){
  return _serialize_path.getString();
}
void WSCconductor::setSerializePath(char* path){
  _serialize_path.setString(path);
}
WSDserialize* WSCconductor::beginTransaction(char* database,char* fname){
  WSDserialize* serialize = getSerialize(database);
  if (serialize == NULL){
WSMFtrace("WSCconductor::beginTransaction()  Data base does not exist.\n");
    return NULL;
  }
  serialize->setPath(getSerializePath());

  long ret = serialize->beginTransaction(fname);
  if (ret != WS_NO_ERR){
WSMFtrace("WSCconductor::beginTransaction()  Data base error.\n");
    return NULL;
  }
  return serialize;
}
WSDserialize* WSCconductor::beginTransaction(char* database,char* fname,WSDserialize* serialize){
  if (serialize == NULL){
WSMFtrace("WSCconductor::beginTransaction()  Data base does not exist.\n");
    return NULL;
  }
  serialize->setPath(getSerializePath());

  long ret = serialize->beginTransaction(fname);
  if (ret != WS_NO_ERR){
WSMFtrace("WSCconductor::beginTransaction()  Data base error.\n");
    return NULL;
  }
  return serialize;
}

long WSCconductor::endTransaction(WSDserialize* serialize){
  if (serialize->underTransaction() != False){
    serialize->endTransaction();
  }
  return WS_NO_ERR;
}
long WSCconductor::save(WSDserialize* serialize,char* type, char* name,void* ptr){
  return serialize->save(type,name,ptr);
}
long WSCconductor::load(WSDserialize* serialize, char* type, char* name,void* ptr){
  return serialize->load(type,name,ptr);
}
long WSCconductor::loadAlloc(WSDserialize* serialize, char* type, char* name,void** ptr,void* cdata){
  return serialize->loadAlloc(type,name,ptr,cdata);
}
long WSCconductor::saveGUI(WSDserialize* serialize, char* name,WSCbase* ptr){
  return serialize->save(ptr->getClassName(),name,(void*)ptr);
}
long WSCconductor::loadGUI(WSDserialize* serialize,WSCbase** ptr,WSCbase* cdata){
  return serialize->loadAlloc("WSCbase","*",(void**)ptr,(void*)cdata);
}
WSCbinType::WSCbinType(){
  long data = 0x11223344;
  char c[4];
  *(long*)c = data;
  if (c[0] == 0x44){
    _need_swap = True;
  }else{
    _need_swap = False;
  }
}
void WSCbinType::memcpy2b(char* ds,short sr){
  if (_need_swap == False){
    memcpy(ds,&sr,sizeof(short));
  }else{
    unsigned char* from;
    unsigned char to[2];
    from = (unsigned char*)&sr;
    ((unsigned char*)to)[1] = from[0];
    ((unsigned char*)to)[0] = from[1];
    memcpy(ds,to,sizeof(short));
  }
}
void WSCbinType::memscan2b(short* out,char* from){
  if (_need_swap == False){
    memcpy(out,from,sizeof(short));
  }else{
    char to[2];
    ((unsigned char*)to)[1] = from[0];
    ((unsigned char*)to)[0] = from[1];
    memcpy(out,to,sizeof(short));
  }
}
void WSCbinType::memscan4b(long* out,char* from){
  if (_need_swap == False){
    memcpy(out,from,sizeof(int));
  }else{
    unsigned char to[4];
    ((unsigned char*)to)[3] = from[0];
    ((unsigned char*)to)[2] = from[1];
    ((unsigned char*)to)[1] = from[2];
    ((unsigned char*)to)[0] = from[3];
    memcpy(out,to,sizeof(int));
  }
}
void WSCbinType::memscan8b(void* out,char* from){
  if (_need_swap == False){
    memcpy(out,from,sizeof(char)*8);
  }else{
    char to[8];
    long i;
    for(i=0; i<8; i++){
      ((unsigned char*)to)[7-i] = from[i];
    }
    memcpy(out,to,sizeof(char)*8);
  }
}
void WSCbinType::memscan16b(void* out,char* from){
  if (_need_swap == False){
    memcpy(out,from,sizeof(char)*16);
  }else{
    unsigned char to[16];
    long i;
    for(i=0; i<16; i++){
      ((unsigned char*)to)[15-i] = from[i];
    }
    memcpy(out,to,sizeof(char)*16);
  }
}
void WSCbinType::memscan32b(void* out,char* from){
  if (_need_swap == False){
    memcpy(out,from,sizeof(char)*32);
  }else{
    unsigned char  to[32];
    long i;
    for(i=0; i<32; i++){
      ((unsigned char*)to)[31-i] = from[i];
    }
    memcpy(out,to,sizeof(char)*32);
  }
}
void WSCbinType::memcpy4b(char* ds,long sr){
  if (_need_swap == False){
    memcpy(ds,&sr,sizeof(long));
  }else{
    unsigned char* from;
    unsigned char to[4];
    from = (unsigned char*)&sr;
    ((unsigned char*)to)[3] = from[0];
    ((unsigned char*)to)[2] = from[1];
    ((unsigned char*)to)[1] = from[2];
    ((unsigned char*)to)[0] = from[3];
    memcpy(ds,to,sizeof(long));
  }
}
void WSCbinType::memcpy8b(char* ds,void* sr){
  if (_need_swap == False){
    memcpy(ds,sr,sizeof(char)*8);
  }else{
    unsigned char *from,to[8];
    from = (unsigned char*)sr;
    ((unsigned char*)to)[7] = from[0];
    ((unsigned char*)to)[6] = from[1];
    ((unsigned char*)to)[5] = from[2];
    ((unsigned char*)to)[4] = from[3];
    ((unsigned char*)to)[3] = from[4];
    ((unsigned char*)to)[2] = from[5];
    ((unsigned char*)to)[1] = from[6];
    ((unsigned char*)to)[0] = from[7];
    memcpy(ds,to,sizeof(char)*8);
  }
}
void WSCbinType::memcpy16b(char* ds,void* sr){
  if (_need_swap == False){
    memcpy(ds,sr,sizeof(char)*16);
  }else{
    unsigned char *from,to[16];
    from = (unsigned char*)sr;
    long i;
    for(i=0; i<16; i++){
      ((unsigned char*)to)[15 -i] = from[i];
    }
    memcpy(ds,to,sizeof(char)*16);
  }
}
void WSCbinType::memcpy32b(char* ds,void* sr){
  if (_need_swap == False){
    memcpy(ds,sr,sizeof(char)*32);
  }else{
    unsigned char *from,to[32];
    from = (unsigned char*)sr;
    long i;
    for(i=0; i<32; i++){
      ((unsigned char*)to)[31 -i] = from[i];
    }
    memcpy(ds,to,sizeof(char)*32);
  }
}
void WSCconductor::setPort(WSCushort port){
  _port = port;
}
WSCushort WSCconductor::getPort(){
  return _port;
}
void WSCconductor::setAddr(char* addr){
  _addr = addr;
}
WSCstring WSCconductor::getAddr(){
  return _addr;
}

void WSCconductor::setTimeout(WSCulong t){
  _timeout = t;
}
long WSCconductor::startDispatch(){
  if (_sock == NULL){
    _sock = WSDsocket::getNewInstance();
  }
  if (_accepted != False){
    _sock->stopAcceptEx();
  }
  if (strcmp((char*)_addr,"")){
//printf("WSCconductor::startDispatch own ip=%s\n",(char*)_addr);
    _sock->setAddr((char*)_addr);
  }
  _sock->setPort(_port);
  _sock->setClTimeout(_timeout);
  _sock->setUserData(this);
  long err = _sock->acceptEx(_accepted_work);
  if (err == WS_NO_ERR){
    _accepted = True;
  }
  if (_timer_id == 0){
    _timer_cnt = 0;
    _timer_id = WSGIappTimer()->addTimerProc(_timer_work,WS10000MS,this);
  }
  _need_update = True;
  return WS_NO_ERR;
}
long WSCconductor::stopDispatch(){
  if (_timer_id != 0){
    WSGIappTimer()->delTimerProc(_timer_id);
    _timer_id = 0;
    WSClistData* list = WSGIappObjectList()->getExportInstanceList();
    long num = list->getNum();
    long i;
    WSCremoteInstanceData rinst;
    WSCRbaseList* orb = new WSCRbaseList();
    if (orb == NULL){
      return WS_ERR;
    }
    orb->setPort(WS_DEFAULT_AGENT_PORT);
    orb->setAddr(WSGIconductor()->getAddr());
    for(i=0; i<num; i++){
      WSCbase* inst = (WSCbase*)(*list)[i];
      if (inst != NULL){
        if (!strcmp(inst->getExportName(),"")){
          rinst.setPublicInstanceName(inst->getInstanceName());
        }else{
          rinst.setPublicInstanceName(inst->getExportName());
        }
        rinst.setInstanceName(inst->getInstanceName());
        rinst.setClassName(inst->getClassName());
        rinst.setPort(WSGIconductor()->getPort());
        rinst.setAddr(WSGIconductor()->getAddr());
        long ret = orb->addRemoteInstanceData(&rinst);
        if (ret != WS_NO_ERR){
          return WS_ERR;
        }
      }
    }
  }
  if (_sock == NULL){
    return WS_ERR;
  }
  if (_accepted != False){
    _sock->stopAcceptEx();
    _accepted = False;
    return WS_NO_ERR;
  }else{
    return WS_ERR;
  }
}

void WSCconductor::_accepted_work(WSDsocket* sock,void* socket,WSCulong addr){
  WSCconductor* _this = (WSCconductor*)sock->getUserData();

  WSDserialize* db = _this->getNewSerialize("SOCKET");
//printf("WSCconductor::_accepted_work .. db=0x%x\n",db);
  _this->beginTransaction("SOCKET","",db);
  sock->_set_dest_addr_(addr);
  WSCstring daddr = sock->getDestAddr();
  if (db == NULL){
//printf("netop err1\n");
    return;
  }
  WSDsocketSerialize* ss = (WSDsocketSerialize*)db->cast("WSDsocketSerialize");
  if (ss != NULL){
//printf("WSCconductor::_accepted_work .. set sock=0x%x socket=0x%x\n",sock,socket);
    ss->setSocket(sock);
    ss->setSocket(socket);
  }

  WSCremoteCall* rc=NULL;
  db->loadAlloc("WSCremoteCall","*",(void**)&rc,NULL);
  if (rc != NULL){
    void(*hd)(WSDserialize*,WSCremoteCall*) =
      (void(*)(WSDserialize*,WSCremoteCall*))
         _this->_net_server_handler_list.getData(rc->_class);

    rc->_dest_addr = daddr;
    if (hd != NULL){
      hd(db,rc);
      WSGIappObjectList()->execUpdate();
    }
  }

  _this->endTransaction(db);
  if (rc != NULL){
//printf("rc->_instance=#%s#\n",rc->_instance);
//printf("rc->_op=#%s#\n",rc->_op);
    delete rc;
  }else{
//printf("loadAlloc WSCremoteCall = NULL\n");
  }

  sock->close(socket);
  delete db;
}

WSDserialize* WSCconductor::beginRemoteCall(WSCremoteCall* rc){
//printf("WSCconductor::remoteCall started.\n");
  if (_csock == NULL){
    _csock = WSDsocket::getNewInstance();
  }
  if (_csock == NULL){
//printf("WSCconductor::remoteCall err1");
    return NULL;
  }
  _csock->setDestPort(rc->_port);
  _csock->setDestAddr(rc->_addr);
  _csock->setTimeout(_timeout);
  long ret = _csock->connect();
  if (ret != WS_NO_ERR){
//printf("WSCconductor::remoteCall err2\n");
    return NULL;
  }
  WSDserialize* db = getNewSerialize("SOCKET");
  beginTransaction("SOCKET","",db);
  if (db == NULL){
//printf("btnop err3\n");
    return NULL;
  }
  WSDsocketSerialize* ss = (WSDsocketSerialize*)db->cast("WSDsocketSerialize");
  if (ss != NULL){
//printf("WSCconductor::beginRemoteCall db=0x%x _csock=0x%x\n",db,_csock);
    ss->setSocket(_csock);
  }
  db->save("WSCremoteCall","call1",(void*)rc);
//printf("WSCconductor::beginRemoteCall  done.\n");
  return db;
}

long WSCconductor::endRemoteCall(WSDserialize* db){
  endTransaction(db);
  delete db;
  return WS_NO_ERR;
}

void WSCconductor::addNetServerHandler(char* cname,void* handler){
  _net_server_handler_list.setData(cname,handler);
}

void WSCconductor::_timer_work(WSCuchar,void* ptr){
//printf("WSCconductor::_timer_work.. \n");
  WSCconductor* _this = (WSCconductor*)ptr;
  if (_this->_accepted == False){
//XXZZ DEVELOP...
//XXZZ recv new port form agent..
    long err = _this->_sock->acceptEx(_accepted_work);
    if (err == WS_NO_ERR){
      _this->_accepted = True;
    }
  }
  _this->_timer_cnt++;
  if (_this->_timer_cnt > WS_RETRY_CNT){
    _this->_need_update = True;
    _this->_timer_cnt = 0; 
  }
//printf("WSCconductor::_timer_work _this->_timer_cnt=%d\n",_this->_timer_cnt);
  WSClistData* list = WSGIappObjectList()->getExportInstanceList();
  long num = list->getNum();
  long i;
  WSCremoteInstanceData rinst;
  WSCRbaseList* orb = new WSCRbaseList();
  if (orb == NULL){
    return;
  }
  orb->setPort(WS_DEFAULT_AGENT_PORT);
  orb->setAddr(WSGIconductor()->getAddr());
  if (_this->_need_update != False){
    for(i=0; i<num; i++){
      WSCbase* inst = (WSCbase*)(*list)[i];
      if (inst != NULL){
        if (!strcmp(inst->getExportName(),"")){
          rinst.setPublicInstanceName(inst->getInstanceName());
        }else{
          rinst.setPublicInstanceName(inst->getExportName());
        }
        rinst.setInstanceName(inst->getInstanceName());
        rinst.setClassName(inst->getClassName());
        rinst.setPort(WSGIconductor()->getPort());
        rinst.setAddr(WSGIconductor()->getAddr());
        long ret = orb->addRemoteInstanceData(&rinst);
        if (ret != WS_NO_ERR){
          delete orb;
          return;
        }
      }
    }
    _this->_need_update = False;
  }

  list = WSGIappObjectList()->getExportInstanceUpdateList();
  num = list->getNum();
  for(i=0; i<num; i++){
    WSCbase* inst = (WSCbase*)(*list)[i];
    if (inst != NULL){
      if (!strcmp(inst->getExportName(),"")){
        rinst.setPublicInstanceName(inst->getInstanceName());
      }else{
        rinst.setPublicInstanceName(inst->getExportName());
      }
      rinst.setInstanceName(inst->getInstanceName());
      rinst.setClassName(inst->getClassName());
      rinst.setPort(WSGIconductor()->getPort());
      rinst.setAddr(WSGIconductor()->getAddr());
      long ret = orb->addRemoteInstanceData(&rinst);
      if (ret != WS_NO_ERR){
        return;
      }
      WSGIappObjectList()->addExportInstanceList(inst);
      list->delPos(i);
      i--;
      num--;
    }
  }
  list->clear();

  list = WSGIappObjectList()->getExportInstanceDeleteList();
  num = list->getNum();
  for(i=0; i<num; i++){
    WSCbase* inst = (WSCbase*)(*list)[i];
    if (inst != NULL){
      if (!strcmp(inst->getExportName(),"")){
        rinst.setPublicInstanceName(inst->getInstanceName());
      }else{
        rinst.setPublicInstanceName(inst->getExportName());
      }
      rinst.setInstanceName(inst->getInstanceName());
      rinst.setClassName(inst->getClassName());
      rinst.setPort(WSGIconductor()->getPort());
      rinst.setAddr(WSGIconductor()->getAddr());
      long ret = orb->delRemoteInstanceData(&rinst);
      if (ret != WS_NO_ERR){
        delete orb;
        return;
      }
      WSGIappObjectList()->addExportInstanceList(inst);
      list->delPos(i);
      i--;
      num--;
    }
  }
  list->clear();
  if (orb != NULL){
    delete orb;
  }

}

void WSCconductor::clearUpdateCounter(){
  _timer_cnt = 0;
}



WSCremoteCall::WSCremoteCall(){
  _op = NULL;
  _class = NULL;
  _instance = NULL;
}
WSCremoteCall::~WSCremoteCall(){
  if (_op != NULL){
    delete _op;
  }
  if (_class != NULL){
    _class = NULL;
  }
  if (_instance != NULL){
    _instance = NULL;
  }
}

void WSCremoteCall::setOperationName(char* opname){
  if (_op != NULL){
    delete _op;
    _op = NULL;
  }
  _op = WSGFstrdup(opname);
}

void WSCremoteCall::setInstanceName(char* iname){
  if (_instance != NULL){
    delete _instance;
    _instance = NULL;
  }
  _instance = WSGFstrdup(iname);
}

void WSCremoteCall::setClassName(char* cname){
  if (_class != NULL){
    delete _class;
    _class = NULL;
  }
  _class = WSGFstrdup(cname);
}

void _WSCremoteCall_save(WSDserialize* db,void* ptr){
//printf("WSCremoteCall_save...\n");
  WSCremoteCall* obj =(WSCremoteCall*)ptr;
  db->saveData(WS_DcRString,">cl",obj->_class);
  db->saveData(WS_DcRString,">in",obj->_instance);
  db->saveData(WS_DcRString,">op",obj->_op);
}
void _WSCremoteCall_load(WSDserialize* db,void* ptr){
//printf("WSCremoteCall_load...\n");
  WSCremoteCall* obj =(WSCremoteCall*)ptr;
  db->loadAllocData(WS_DcRString,">cl",(void**)&obj->_class,NULL);
  db->loadAllocData(WS_DcRString,">in",(void**)&obj->_instance,NULL);
  db->loadAllocData(WS_DcRString,">op",(void**)&obj->_op,NULL);
}

void* _WSCremoteCall_create(void* ptr){
  return new WSCremoteCall;
}
void _WSCremoteCall_delete(void* ptr){
  WSCremoteCall* obj =(WSCremoteCall*)ptr;
  delete obj;
}
WSMFdefineDrClient(WSCremoteCall,_WSCremoteCall_save,
  _WSCremoteCall_load, _WSCremoteCall_create, _WSCremoteCall_delete);


