//
// 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 <WSCclassInformation.h>
#include <WSCbaseList.h>
#include <WSCbase.h>
#include <WSClistData.h>
#include <WSCRbaseList.h>
#include <WSDappDev.h>

class WSCbaseArray{
 public:
  WSCbaseArray(char*);
  ~WSCbaseArray();
  long        _hash_value;
  char*       _cname;
  WSClistData _base_list;
  long     getNum();
  void     addItem(WSCbase*);
  void     delItem(WSCbase* );
  WSCbase* getItem(char* );
};
static WSCbaseList* _the_app_base_list = NULL;
WSCbaseList::WSCbaseList(){
  _search_handler = NULL;
  _base_list = new WSClistData(128);
  _need_update = new WSClistData(1024);
  _need_init = new WSClistData(1024);
  _remote_data_list_updated = False;
}
WSCbaseList::~WSCbaseList(){
  long i;
  long num = _base_list->getNum();
  for(i=0; i < num; i++){
    WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
    delete base_array;
  }
  _base_list->clear();
  delete _base_list;
  delete _need_update;
  delete _need_init;
}
WSClistData* WSCbaseList::getInstanceList(char* cname){
  long i;
  long hvalue = WSGFgetHashValue(cname);
  long num = _base_list->getNum();
  for(i=0; i<num; i++){
    WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
    if (base_array->_hash_value == hvalue && !strcmp(base_array->_cname,cname)){
      return &base_array->_base_list;
    }
  }
  return NULL;
}
WSCbaseList* WSGIappObjectList(){
  if (_the_app_base_list == NULL){
    _the_app_base_list = new WSCbaseList();
  }
  return _the_app_base_list;
}
static WSCbase* _user_data_ = NULL;
void WSCbaseList::setUserData(char* name,void* data){
  if (_user_data_ == NULL){
    _user_data_ = new WSCbase(NULL,"_user_data_");
	_user_data_->initialize();
  }
  _user_data_->setUserData(name,data);
}
void* WSCbaseList::getUserData(char* name){
  if (_user_data_ != NULL){
    return _user_data_->getUserData(name);
  }
  return NULL;
}
WSClistData* WSCbaseList::getClassList(){
  return _base_list;
}
void WSCbaseList::addClient(WSCbase* client,void* base_array){
  //ok,it was initialized list in classinfo 
  if (base_array != NULL){
    WSCbaseArray* barray = (WSCbaseArray*)base_array;
    barray->addItem(client);
  }else{
    WSCclassInformation* inf = client->getClassInformation();
    WSCbaseArray* new_base_list = new WSCbaseArray(client->getClassName());
    new_base_list->addItem(client);
    _base_list->add( (void*) new_base_list );
    inf->setClassInstanceList((void*)new_base_list);
  }
}
void WSCbaseList::delClient(WSCbase* client,void* base_array){
  //delete from update list
  long i;
  long num = _need_update->getNum();
  for(i=0; i <num; i++){
    WSCbase* base = (WSCbase*)(*_need_update)[i];
    if (base == client){
      _need_update->delPos(i);
      num = _need_update->getNum();
      i--;
    }
  }
  //delete from initialize list
  num = _need_init->getNum();
  for(i=0; i <num; i++){
    WSCbase* base = (WSCbase*)(*_need_init)[i];
    if (base == client){
      _need_init->delPos(i);
      num = _need_init->getNum();
      i--;
    }
  }
  //delete from instance list
  WSCbaseArray* barray = (WSCbaseArray*)base_array;
  if (barray != NULL){
    barray->delItem(client);
  }else{
    WSCclassInformation* inf = client->getClassInformation();
    WSCbaseArray* barray2 = (WSCbaseArray*)inf->getClassInstanceList();
    if (barray2 != NULL){
      barray2->delItem(client);
    }
  }
}
WSCbase* WSCbaseList::searchInstance(char* cname,char* iname){
  if (_search_handler == NULL){
    return getInstance(cname,iname);
  }
  WSCbase* (*hd)(char*,char*) = (WSCbase* (*)(char*,char*))_search_handler;  
  return hd(cname,iname);
}
void WSCbaseList::setSearchInstanceHandler(void* hd){
  _search_handler = hd;
}

WSCbool WSCbaseList::existInstance(WSCbase* ptr){
  long num = _base_list->getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
    long num2 = base_array->getNum();
    long j;
    for(j=0; j < num2;j++){
      WSCbase* base = (WSCbase*)base_array->_base_list[j];
      if (base == ptr){
        return True;
      }
    }
  }
  return False;
}

WSCbase* WSCbaseList::getInstance(char* cname,char* iname){
  long hvalue = WSGFgetHashValue(cname);
  int i;
  int num = _base_list->getNum();
  if (!strcmp(cname,"WSCbase")){
    for(i = 0; i < num; i++){
      WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
      WSCbase* base =  base_array->getItem(iname);
      if (base != NULL){
        return base;
      }
    }
  }else{
    for(i = 0; i < num; i++){
      WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
      if (base_array->_hash_value == hvalue &&
          !strcmp(base_array->_cname,cname)){
        return base_array->getItem(iname);
      }
    }
  }
  return NULL;
}

void WSCbaseList::execUpdate(){
  long i;
  long num = _need_update->getNum();
  if (num > 0){
    WSCbase** baselist = new WSCbase*[num];
    memcpy(baselist,_need_update->getBuf(),sizeof(WSCbase*)*num);
    _need_update->clear();
    for(i=0; i <num; i++){
      if (baselist[i]->isNeedUpdate() != False){
        baselist[i]->update();
      }
    }
    delete baselist;
  }
}
void WSCbaseList::addNeedUpdate(WSCbase* client){
  _need_update->add( (void*)client );
}
void WSCbaseList::execInitialize(){
dbprintf("WSCbaseList::execInitialize %s:%d start.\n",__FILE__,__LINE__);
  WSCbool fl = WSGIappDev()->getUnderExecInitialize();
  if (fl != False){
    return;
  }
  fl = WSGIappDev()->getInitializeExecuted();
  if (fl == False){
    return;
  }
  long i;
  long num = _need_init->getNum();
  if (num > 0){
    WSCbase** baselist = new WSCbase*[num];
    memcpy(baselist,_need_init->getBuf(),sizeof(WSCbase*)*num);
    _need_init->clear();
    for(i=0; i <num; i++){
      baselist[i]->execProcedure(WSEV_INITIALIZE);
    }
    delete baselist;
  }
dbprintf("WSCbaseList::execInitialize %s:%d done.\n",__FILE__,__LINE__);
}
void WSCbaseList::addNeedInitialize(WSCbase* client){
  _need_init->add( (void*)client );
}
long WSCbaseList::countObject(char* cname){
  int i;
  long hvalue = WSGFgetHashValue(cname);
  int num = _base_list->getNum();
  if (!strcmp(cname,"WSCbase")){
    return num;
  }
  for(i = 0; i < num; i++){
    WSCbaseArray* base_array = (WSCbaseArray*)(*_base_list)[i];
    if (base_array->_hash_value == hvalue &&
        !strcmp(base_array->_cname,cname)){
      long ret = base_array->getNum();
      return ret;
    }
  }
  return 0;
}
WSCbaseArray::WSCbaseArray(char* cname){
  _cname = WSGFstrdup(cname);
  _hash_value = WSGFgetHashValue(cname);
}
WSCbaseArray::~WSCbaseArray(){
  _base_list.clear();
}
long WSCbaseArray::getNum(){
  return _base_list.getNum();
}
void WSCbaseArray::addItem(WSCbase* item){
  _base_list.add( (void*) item );
}
void WSCbaseArray::delItem(WSCbase* item){
  _base_list.del( (void*) item );
}
WSCbase* WSCbaseArray::getItem(char* item){
  long i;
  long hvalue = WSGFgetHashValue(item); 
  long num = _base_list.getNum();
  for(i=0; i < num; i++){
    WSCbase* base = (WSCbase*)_base_list[i];
    if ( hvalue == base->getInstanceNameHashValue() &&
      !strcmp(item,base->getInstanceName()) ){
      return base;
    }
  }
  return NULL;
}
void WSCbaseList::addEvent(WSCbase* client,long ev){
  _event_list.add((void*)ev);
  _event_client_list.add((void*)client);
}
void WSCbaseList::delEvent(WSCbase* client,long ev){
  long i;
  long num = _event_list.getNum(); 
  for(i=0; i<num; i++){
    WSCbase* cl = (WSCbase*)_event_client_list[i];
    if (cl == client){
      long e = (long)_event_list[i];
      if (e == ev){
        _event_list.delPos(i);
        _event_client_list.delPos(i);
        break;
      }
    }
  }
//  _event_client_list.add((void*)client);
//  _event_list.add((void*)ev);
}
void WSCbaseList::execEvent(long ev,void* data){
  long i;
  long num = _event_list.getNum(); 
  for(i=0; i<num; i++){
    long val = (long)_event_list[i];
    if (val == ev){
      WSCbase* client = (WSCbase*)_event_client_list[i];
      long tev = (long)_event_list[i];
      if (tev == ev){
        client->execEventProc(ev,data);
      }
    }
  }
}
void WSCbaseList::execEvent(long ev){
  long i;
  long num = _event_list.getNum(); 
  for(i=0; i<num; i++){
    long val = (long)_event_list[i];
    if (val == ev){
      WSCbase* client = (WSCbase*)_event_client_list[i];
      long tev = (long)_event_list[i];
      if (tev == ev){
        client->execProcedure(ev);
      }
    }
  }
}

void WSCbaseList::execEvent(char* pname){
  long i;
  long num = _event_list.getNum(); 
  for(i=0; i<num; i++){
//    long val = (long)_event_list[i];
    WSCbase* client = (WSCbase*)_event_client_list[i];
    client->execProcedure(pname);
  }
}

WSClistData* WSCbaseList::getRemoteInstanceList(){
  return &_remote_instance_list;
}


WSCremoteInstanceData::WSCremoteInstanceData(){
  _port = 0;
}
WSCremoteInstanceData::~WSCremoteInstanceData(){
}

void WSCremoteInstanceData::setAddr(char* addr){
  _addr = addr;
}
void WSCremoteInstanceData::setPublicInstanceName(char* iname){
  _public_instance_name = iname;
}
void WSCremoteInstanceData::setInstanceName(char* iname){
  _instance_name = iname;
}
void WSCremoteInstanceData::setClassName(char* cname){
  _class_name = cname;
}
void WSCremoteInstanceData::setPort(WSCushort port){
  _port = port;
}

WSCstring WSCremoteInstanceData::getAddr(){
  return _addr;
}
WSCstring WSCremoteInstanceData::getPublicInstanceName(){
  return _public_instance_name;
}
WSCstring WSCremoteInstanceData::getInstanceName(){
  return _instance_name;
}
WSCstring WSCremoteInstanceData::getClassName(){
  return _class_name;
}

WSCushort WSCremoteInstanceData::getPort(){
  return _port;
}

WSCbool WSCbaseList::getRemoteInstanceListUpdated(){
  return _remote_data_list_updated;
}
void WSCbaseList::setRemoteInstanceListUpdated(WSCbool fl){
  _remote_data_list_updated = fl;
}

long WSCbaseList::addRemoteInstanceData(WSCremoteInstanceData* idata){
  long i;
  long num = _remote_instance_list.getNum();
  for(i=0; i<num; i++){
    WSCremoteInstanceData* item =
                   (WSCremoteInstanceData*)_remote_instance_list[i];
    char* pname = item->_public_instance_name;
    char* pname2 = idata->_public_instance_name;
    if (pname[0] == pname2[0] && !strcmp(pname,pname2)){
    }else{
      continue;
    }
    char* iname = item->_instance_name;
    char* iname2 = idata->_instance_name;
    if (iname[0] == iname2[0] && !strcmp(iname,iname2)){
    }else{
      continue;
    }
    char* cname = item->_class_name;
    char* cname2 = idata->_class_name;
    if (cname[0] == cname2[0] && !strcmp(cname,cname2)){
    }else{
      continue;
    }
    char* addr = item->_addr;
    char* addr2 = idata->_addr;
    if (addr[0] == addr2[0] && !strcmp(addr,addr2)){
    }else{
      continue;
    }
    if (item->_port != idata->_port){
      continue;
    }else{
//printf("WSCbaseList::addRemoteInstanceData same one exists..\n");
      return WS_NO_ERR;
    }
  }
  WSCremoteInstanceData* inst = new WSCremoteInstanceData();
  inst->_public_instance_name = idata->_public_instance_name;
  inst->_instance_name = idata->_instance_name;
  inst->_class_name = idata->_class_name;
  inst->_addr = idata->_addr;
  inst->_port = idata->_port;
  _remote_instance_list.add(inst);
//printf("WSCbaseList::addRemoteInstanceData added. %s %s %s %d\n", (char*)inst->_instance_name,(char*)inst->_class_name,(char*)inst->_addr,inst->_port);
  _remote_data_list_updated = True;
  return WS_NO_ERR;
}

long WSCbaseList::delRemoteInstanceData(WSCremoteInstanceData* idata){
  long i;
  long num = _remote_instance_list.getNum();
  for(i=0; i<num; i++){
    WSCremoteInstanceData* item =
                   (WSCremoteInstanceData*)_remote_instance_list[i];
    char* pname = item->_public_instance_name;
    char* pname2 = idata->_public_instance_name;
    if (pname[0] == pname2[0] && !strcmp(pname,pname2)){
    }else{
      continue;
    }
    char* iname = item->_instance_name;
    char* iname2 = idata->_instance_name;
    if (iname[0] == iname2[0] && !strcmp(iname,iname2)){
    }else{
      continue;
    }
    char* cname = item->_class_name;
    char* cname2 = idata->_class_name;
    if (cname[0] == cname2[0] && !strcmp(cname,cname2)){
    }else{
      continue;
    }
    char* addr = item->_addr;
    char* addr2 = idata->_addr;
    if (addr[0] == addr2[0] && !strcmp(addr,addr2)){
    }else{
      continue;
    }
    if (item->_port == idata->_port){
      continue;
    }else{
      _remote_instance_list.delPos(i);
      delete item;
      _remote_data_list_updated = True;
      return WS_NO_ERR;
    }
  }
  return WS_ERR;
}

WSCremoteInstanceData* WSCbaseList::getRemoteInstanceData(char* pn){
  long i;
  long num = _remote_instance_list.getNum();
  for(i=0; i<num; i++){
    WSCremoteInstanceData* item =
                   (WSCremoteInstanceData*)_remote_instance_list[i];
    char* pname = item->_public_instance_name;
//printf("search WSCremoteInstanceData %d %s\n",i,pname);
    if (pname[0] == pn[0] && !strcmp(pname,pn)){
      return item;
    }else{
      continue;
    }
  }
  return NULL;
}

WSCRbase* WSCbaseList::getRemoteInstance(char* iname){
  WSCRbaseList* orb = new WSCRbaseList();
  orb->setAddr(WSGIconductor()->getAddr());
  orb->setPort(WS_DEFAULT_AGENT_PORT);
  WSCremoteInstanceData* rinst = orb->getRemoteInstanceData(iname);
  if (rinst == NULL){
    return NULL;
  }
//printf("WSCbaseList::getRemoteInstance cname=%s\n",(char*)rinst->getClassName());
//printf("WSCbaseList::getRemoteInstance pname=%s\n",(char*)rinst->getPublicInstanceName());
  if (!strcmp(rinst->getInstanceName(),"")){
    return NULL;
  }
  WSCRbase* inst = WSCRbase::getNewInstance(rinst->_class_name);
  if (inst == NULL){
    return NULL;
  }
  inst->setAddr(rinst->getAddr());
  inst->setPort(rinst->getPort());
//  inst->setClassName(rinst->getClassName());
  inst->setInstanceName(rinst->getInstanceName());
  delete rinst;
  return inst;
}

long WSCbaseList::addExportInstanceList(WSCbase* inst){
  long num = _export_instance_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_list[i];
    if (item == inst){
      return WS_ERR;
    }
  }
  _export_instance_list.add((void*)inst);
  return WS_NO_ERR;
}

long WSCbaseList::delExportInstanceList(WSCbase* inst){
  long num = _export_instance_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_list[i];
    if (item == inst){
      _export_instance_list.delPos(i);
      return WS_NO_ERR;
    }
  }
  
  return WS_NO_ERR;
}

WSClistData* WSCbaseList::getExportInstanceList(){
  return &_export_instance_list;
}
long WSCbaseList::addExportInstanceUpdateList(WSCbase* inst){
  long num = _export_instance_update_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_update_list[i];
    if (item == inst){
      return WS_ERR;
    }
  }
  _export_instance_update_list.add((void*)inst);
  return WS_NO_ERR;
}

long WSCbaseList::delExportInstanceUpdateList(WSCbase* inst){
  long num = _export_instance_update_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_update_list[i];
    if (item == inst){
      _export_instance_update_list.delPos(i);
      return WS_NO_ERR;
    }
  }
  return WS_NO_ERR;
}

WSClistData* WSCbaseList::getExportInstanceUpdateList(){
  return &_export_instance_update_list;
}
long WSCbaseList::addExportInstanceDeleteList(WSCbase* inst){
  long num = _export_instance_delete_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_delete_list[i];
    if (item == inst){
      return WS_ERR;
    }
  }
  _export_instance_delete_list.add((void*)inst);
  return WS_NO_ERR;
}

long WSCbaseList::delExportInstanceDeleteList(WSCbase* inst){
  long num = _export_instance_delete_list.getNum();
  long i;
  for(i=0; i<num; i++){
    WSCbase* item = (WSCbase*)_export_instance_delete_list[i];
    if (item == inst){
      _export_instance_delete_list.delPos(i);
      return WS_NO_ERR;
    }
  }
  return WS_NO_ERR;
}

WSClistData* WSCbaseList::getExportInstanceDeleteList(){
  return &_export_instance_delete_list;
}


void _WSCremoteInstanceData_save(WSDserialize* db,void* ptr){
//printf("WSCremoteInstanceData_save...\n");
  WSCremoteInstanceData* obj =(WSCremoteInstanceData*)ptr;
//printf("send #%s# #%s# #%s# #%s# %d\n",
//obj->_public_instance_name.getString(),
//obj->_instance_name.getString(),
//obj->_class_name.getString(),
//obj->_addr.getString(),
//obj->_port);

  db->saveData(WS_DcRString,">pn",obj->_public_instance_name.getString());
  db->saveData(WS_DcRString,">in",obj->_instance_name.getString());
  db->saveData(WS_DcRString,">cl",obj->_class_name.getString());
  db->saveData(WS_DcRString,">ad",obj->_addr.getString());
  db->saveData(WS_DcRUShort,">pt",&obj->_port);
}
void _WSCremoteInstanceData_load(WSDserialize* db,void* ptr){
//printf("WSCremoteInstanceData_load...\n");
  WSCremoteInstanceData* obj =(WSCremoteInstanceData*)ptr;
  char* pn = NULL;
  char* in = NULL;
  char* cl = NULL;
  char* ad = NULL;
  db->loadAllocData(WS_DcRString,">pn",(void**)&pn,NULL);
  db->loadAllocData(WS_DcRString,">in",(void**)&in,NULL);
  db->loadAllocData(WS_DcRString,">cl",(void**)&cl,NULL);
  db->loadAllocData(WS_DcRString,">ad",(void**)&ad,NULL);
  db->loadData(WS_DcRUShort,">pt",(void**)&obj->_port);
  if (pn != NULL){
//printf("pn=%s\n",pn);
    obj->setPublicInstanceName(pn);
  }
  if (in != NULL){
//printf("in=%s\n",in);
    obj->setInstanceName(in);
  }
  if (cl != NULL){
//printf("cl=%s\n",cl);
    obj->setClassName(cl);
  }
  if (ad != NULL){
//printf("ad=%s\n",ad);
    obj->setAddr(ad);
  }
}

void* _WSCremoteInstanceData_create(void* ptr){
  return new WSCremoteInstanceData;
}
void _WSCremoteInstanceData_delete(void* ptr){
  WSCremoteInstanceData* obj =(WSCremoteInstanceData*)ptr;
  delete obj;
}
WSMFdefineDrClient(WSCremoteInstanceData,_WSCremoteInstanceData_save,
  _WSCremoteInstanceData_load, _WSCremoteInstanceData_create,
  _WSCremoteInstanceData_delete);

