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

#ifndef WSCTYPESERVER_H
#define WSCTYPESERVER_H

#include <WSdrDef.h>
#include <WSClistData.h>
#include <WSCstring.h>
class WSDserialize;

class WSCtypeServer{

 protected:
  WSClistData _parent_name_list;
  WSClistData _parent_type_server_list;
  void* (*_create_handler)(void *);
  void  (*_delete_handler)(void *);
  void  (*_save_handler)(WSDserialize*,void *);
  void  (*_load_handler)(WSDserialize*,void *);
  WSCstring _type_name;

 public:
  WSCtypeServer();
  virtual ~WSCtypeServer();

  void  setType(char* type);
  void  setSaveHandler(void (*)(WSDserialize*,void*) );
  void  setLoadHandler(void (*)(WSDserialize*,void*) );
  void  setCreateHandler(void*(*)(void*));
  void  setDeleteHandler(void(*)(void*));

  void* getSaveHandler();
  void* getLoadHandler();
  long  getParentClassNum();
  char* getParentClassName(long i);
  WSCtypeServer* getParentClassServer(long,char** cname);
  virtual void*  getParentClassPtr(char*,void*) = 0;

  void* createInstance(void*);
  void  deleteInstance(void*);
  WSCbool isParentClass(char*);
  WSCbool isHit(char*);
};


#define WSMFdefineDrClient(ETYPE,save_hd,load_hd,create_hd,delete_hd) \
class ETYPE ## _dr_client: public WSCtypeServer { \
public: \
  ETYPE ## _dr_client(char* type,WSdr_handler savehd,WSdr_handler loadhd,WSdr_chandler createhd,WSdr_dhandler deletehd):\
      WSCtypeServer(){ setType(type); setSaveHandler(savehd); setLoadHandler(loadhd); setCreateHandler(createhd);setDeleteHandler(deletehd);}; \
  void* getParentClassPtr(char* pclass,void* ptr){ \
    ETYPE* inst = (ETYPE*)ptr; \
    if (pclass[0] == #ETYPE [0] && !strcmp(pclass,#ETYPE)){ \
      inst = NULL; \
    }; \
    return (inst); \
  };\
};\
ETYPE ## _dr_client ETYPE ## _ins_dc(#ETYPE,save_hd,load_hd,create_hd,delete_hd);

#define WSMFdefineDrInheritClient(ETYPE,PTYPE,save_hd,load_hd,create_hd,delete_hd) \
class ETYPE ## _dr_client: public WSCtypeServer { \
public: \
  ETYPE ## _dr_client(char* type,char* ptype,WSdr_handler savehd,WSdr_handler loadhd,WSdr_chandler createhd,WSdr_dhandler deletehd):\
    WSCtypeServer(){ \
      setType(type); \
      setSaveHandler(savehd); \
      setLoadHandler(loadhd); \
      setCreateHandler(createhd); \
      setDeleteHandler(deletehd); \
      _parent_name_list.add(ptype); \
    }; \
  void* getParentClassPtr(char* pclass,void* ptr){ \
    ETYPE* inst = (ETYPE*)ptr; \
    PTYPE* ret = (PTYPE*)inst; \
    char* pcname;\
    WSCtypeServer* pclient = getParentClassServer(0,&pcname); \
    void* rt; \
    if (pclass[0] == #PTYPE [0] && !strcmp(pclass,#PTYPE)){ \
      rt = ret; \
    }else if (pclass[0] == #ETYPE [0] && !strcmp(pclass,#ETYPE)){ \
      rt = inst; \
    }else if (pclient == NULL){ \
      rt = NULL; \
    }else{ \
      rt = pclient->getParentClassPtr(pclass,ret); \
    } \
    return rt; \
  }\
};\
ETYPE ## _dr_client ETYPE ## _ins_dc(#ETYPE,#PTYPE,save_hd,load_hd,create_hd,delete_hd);

#endif
