//
// 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>

inline long WSIFstrcmpA(char* x,char* y){
  register WSCuchar* s1 = (WSCuchar*)x;
  register WSCuchar* s2 = (WSCuchar*)y;
  register WSCuchar p1 = 0;
  register WSCuchar p2 = 0;
  do{
    p1 = (WSCuchar)*s1++;
    p2 = (WSCuchar)*s2++;
    if (p1 == 0){
      return p1 -p2;
    }
  }while(p1 == p2);
  return p1 -p2;
}
WSCclassInformation::WSCclassInformation(char* class_name,WSCclassInformation* parent){
  cname = WSGFstrdup(class_name);
  cname_hash_value = WSGFgetHashValue(class_name);
  _bases = NULL;
  _pclass_info = parent;
  _inf_table = NULL;
  _all_prop_list = new WSClistData(64);
  _prop_list_for_init = new WSClistData(64);
  _trigger_mask = 0;
  _del_trigger_mask = 0;
};

WSCclassInformation::~WSCclassInformation(){
  delete cname;
  delete _prop_list_for_init;
  delete _all_prop_list;
}
WSCclassInformation* WSCclassInformation::getParentClassInformation(){
  return _pclass_info;
}
void* WSCclassInformation::getClassInstanceList(){
  return _bases;
}
void WSCclassInformation::setClassInstanceList(void* list){
  _bases = list;
}
WSClistData* WSCclassInformation::getPropertyList(){
  return &_prop_list;
}
WSClistData* WSCclassInformation::getHashTable(){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  return _inf_table;
}
WSCbool WSCclassInformation::getPropObj(char* prop_name,char** class_name){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  long val = WSGFgetHashValue(prop_name);
  if (val < 0 || val > WS_MAX_HASH_VALUE -1){
    return False;
  }
  long num = _inf_table[val].getNum();
  WSChashData* data;
  long i;
  for(i=0; i < num; i++){
    data = (WSChashData*)_inf_table[val][i];
    if (data->_property->property_name == prop_name){
      *class_name = data->_class_info->cname;
       return True;
    }
  }
  for(i=0; i < num; i++){
    data = (WSChashData*)_inf_table[val][i];
    if (data->_property->property_name[0] == prop_name[0] &&
        !WSIFstrcmpA( data->_property->property_name, prop_name)){
      *class_name = data->_class_info->cname;
      return True;
    }
  }
  return False;
}
WSCbool WSCclassInformation::getPropObj(char* prop_name,WSCproperty** prop){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  long val = WSGFgetHashValue(prop_name);
  long num = _inf_table[val].getNum();
  WSChashData* data;
  long i;
  for(i=0; i < num; i++){
    data = (WSChashData*)_inf_table[val][i];
    if (data->_property->property_name == prop_name){
      *prop = data->_property;
      return True;
    }
  }
  for(i=0; i < num ; i++){
    data = (WSChashData*)_inf_table[val][i];
    if (data->_property->property_name[0] == prop_name[0] &&
        !WSIFstrcmpA( data->_property->property_name, prop_name)){
      *prop = data->_property;
      return True;
    }
  }
  return False;
}
void WSCclassInformation::setExtTrigger(long trg,char* tname){
  _ext_trigger_list.setData(tname,(void*)trg);
}
WSCindexData* WSCclassInformation::getExtTriggerList(){
  return &_ext_trigger_list;
}
WSCindexData* WSCclassInformation::getAllExtTriggerList(){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  return &_all_ext_trigger_list;
}

void WSCclassInformation::setTrigger(long trg){
  _trigger_mask |= WSGFeventToMaskBit(trg);
}
void WSCclassInformation::setDelTrigger(long trg){
  _del_trigger_mask |= WSGFeventToMaskBit(trg);
}
WSCbool WSCclassInformation::existTrigger(long trg){
  WSCbool ret = _existTrigger(trg);
  if (ret == False){
    return _existExtTrigger(trg);
  }
  return ret;
}
WSCbool WSCclassInformation::_existExtTrigger(long trg){
  long i;
  long num = _all_ext_trigger_list.getNum();
  for(i=0; i<num; i++){
    long val = (long)_all_ext_trigger_list.getData(i);
    if (val == trg){
      return True;
    }
  }
  return False;
}
WSCbool WSCclassInformation::_existTrigger(long trg){
  if (trg == WSEV_NONE || trg == WSEV_INITIALIZE ||
                          trg == WSEV_DELETE ){
    return True;
  }
  WSCulong mask = WSGFeventToMaskBit(trg);
  if (_del_trigger_mask & mask){
    return False;
  }
  if (_trigger_mask & mask){
    return True;
  }

  WSCclassInformation* parent = _pclass_info;
  if (parent == NULL){
    return False;
  }else{
    return parent->existTrigger(trg);
  }
}
WSClistData* WSCclassInformation::getAllPropertyList(){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  return _all_prop_list;
}
WSClistData* WSCclassInformation::getPropertyListForInit(){
  if (_inf_table == NULL){
    _create_inf_table();
  }
  return _prop_list_for_init;
}
void WSCclassInformation::setDelExtTrigger(long trg){
  _del_ext_trigger_list.add((void*)trg);
}
void WSCclassInformation::_create_inf_table(){
  if (_inf_table == NULL){
    _inf_table = new WSClistData[WS_MAX_HASH_VALUE];
  }
  WSClistData not_use_list;
  WSClistData defaultch_list;
  WSClistData not_vis_list;
  WSCclassInformation* inf = this;
  WSClistData* plist;
  WSCproperty* prop = NULL;
  WSCproperty* nprop = NULL;
  long num,num2,i,j;
  WSCbool reject;
  while(1){
    if (inf != NULL){
      WSClistData* dtlist = &inf->_del_ext_trigger_list;
      long dtnum = dtlist->getNum();
      for(i=0; i<dtnum; i++){
        long trg = (long)dtlist->getData(i);
        long j;
        long anum = _all_ext_trigger_list.getNum();
        for(j=0; j < anum;j++){
          long val = (long)_all_ext_trigger_list.getData(j);
          if (val == trg){
            _all_ext_trigger_list.delPos(j);
            anum--;
            j--;
          } 
        }
      }

      WSCindexData* tlist = inf->getExtTriggerList();
      long tnum = tlist->getNum();
      for(i=0; i<tnum; i++){
        _all_ext_trigger_list.setData(tlist->getIndex(i),tlist->getData(i));
      }


      plist = &inf->_prop_list;
      num = plist->getNum();
      for(i=0; i< num; i++){
        prop = (WSCproperty*)(*plist)[i];
        if (prop->_default_value_change != False){
          defaultch_list.add(prop);
          continue;
        }
        if (prop->_ignore != False && prop->_builder_visible == False){
          not_vis_list.add(prop);
          continue;
        }
        if (prop->_not_use != False){
          not_use_list.add(prop);
          continue;
        }
        num2 = not_use_list.getNum();
        reject = False;
        for(j=0; j < num2; j++){
          nprop = (WSCproperty*)not_use_list[j];
          if (nprop->property_name[0] == prop->property_name[0] &&
              !WSIFstrcmpA(nprop->property_name,prop->property_name)){
            reject = True;
            j = num2;
          }
        }
        if (reject != False){
          continue;
        }
        WSCproperty* default_ch = NULL;
        long dnum = defaultch_list.getNum();
        long j;
        for(j=0; j<dnum; j++){
          WSCproperty* dprop = (WSCproperty*)defaultch_list[j];
          if (dprop->property_name[0] == prop->property_name[0] &&
              !WSIFstrcmpA(dprop->property_name,prop->property_name)){
            default_ch = dprop;
            break;
          }
        }
        if (default_ch != NULL){
          WSCproperty* new_prop = new WSCproperty(*prop);
          new_prop->setGetDefaultValueHandler(
		           (void(*)(void*))default_ch->getGetDefaultValueHandler() );
          new_prop->_init_execute = default_ch->_init_execute;
          prop = new_prop;
        }
        WSCproperty* builder_vis_ch = NULL;
        dnum = not_vis_list.getNum();
        for(j=0; j<dnum; j++){
          WSCproperty* dprop = (WSCproperty*)not_vis_list[j];
          if (dprop->property_name[0] == prop->property_name[0] &&
              !WSIFstrcmpA(dprop->property_name,prop->property_name)){
            builder_vis_ch = dprop;
            break;
          }
        }
        if (builder_vis_ch != NULL){
//          WSCproperty* new_prop = new WSCproperty(*prop); //for VC++
          WSCproperty* new_prop = new WSCproperty("","");
          *new_prop = *prop;
          new_prop->_builder_visible =  builder_vis_ch->_builder_visible;
          prop = new_prop;
        }
        WSChashData* data = new WSChashData;
        data->_class_info = inf;
        data->_property = prop;
        char* name = prop->property_name;
        _inf_table[ WSGFgetHashValue(name) ].add(data);
        _all_prop_list->add(prop);
      }
      inf = inf->_pclass_info;
    }else{
      break;
    }
  }

  inf = this;
  WSCproperty* vis = NULL;
  WSClistData pl;
  while(1){
    if (inf != NULL){
      pl.add(inf);
    }else{
      break;
    }
    inf = inf->_pclass_info;
  }

  j = pl.getNum(); 
  j--;
  if (j < 0){ 
    return;
  }
  WSCclassInformation* pinf;
  WSCproperty* _prop;

  while(1){
    pinf = (WSCclassInformation*)pl[j];
    if (pinf != NULL ){
      plist = &pinf->_prop_list;
      num = plist->getNum();
      for(i=0; i< num; i++){
        _prop = (WSCproperty*)(*plist)[i];
        if (_prop->_default_value_change != False){
          continue;
        }
        if (_prop->_ignore != False && _prop->_builder_visible == False){
          continue;
        }
        if (_prop->_not_use != False){
          continue;
        }
        WSCproperty* default_ch = NULL;
        long dnum = defaultch_list.getNum();
        long j;
        for(j=0; j<dnum; j++){
          WSCproperty* dprop = (WSCproperty*)defaultch_list[j];
          if (dprop->property_name[0] == prop->property_name[0] &&
              !WSIFstrcmpA(dprop->property_name,_prop->property_name)){
            default_ch = dprop;
            break;
          }
        }
        if (default_ch != NULL){
          WSCproperty* new_prop = new WSCproperty(*_prop);
          new_prop->setGetDefaultValueHandler(
              (void(*)(void*))default_ch->getGetDefaultValueHandler() );
          new_prop->_init_execute = default_ch->_init_execute;
          new_prop->_set_proc_addr = _prop->_set_proc_addr;
          _prop = new_prop;
        }
        WSCproperty* builder_vis_ch = NULL;
        dnum = not_vis_list.getNum();
        for(j=0; j<dnum; j++){
          WSCproperty* dprop = (WSCproperty*)not_vis_list[j];
          if (dprop->property_name[0] == prop->property_name[0] &&
              !WSIFstrcmpA(dprop->property_name,_prop->property_name)){
            builder_vis_ch = dprop;
            break;
          }
        }
        if (builder_vis_ch != NULL){
          WSCproperty* new_prop = new WSCproperty(*_prop);
          new_prop->_builder_visible =  builder_vis_ch->_builder_visible;
          _prop = new_prop;
        }
        if ( WSIFstrcmpA(_prop->property_name,"vis")){
          if ( _prop->_init_execute != False){
            _prop_list_for_init->add((void*)_prop);       
          }
        }else{
          if ( _prop->_init_execute != False){
            vis = _prop;
          }
        }
      }
    }else{
      break;
    }
    j--;
    if (j < 0){ 
      break;
    }
  }
  if (vis != NULL){
    _prop_list_for_init->add((void*)vis);       
  }
}
void WSCclassInformation::addPropObj(WSCproperty* prop){
  _prop_list.add((void*)prop);
}
WSChashData::WSChashData(){
   _class_info = NULL;
   _property = NULL;
}
