#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "IMBasicObject.hh"
#include "IMUtil.hh"
#include "IMLog.hh"
#include "IMLock.hh"

/*******************************************************************************
                                 IMObject
 *******************************************************************************/

enum IMObject::OBJCATEGORY
IMObject::get_category() const
{
    switch (get_type()) {
      case EIMIL_CONFIG:
       return SYNTAX_RULE_OBJECT;

      case JAVA_GUI:
      case BINARY_GUI:
      case SCRIPT_GUI:
       return GUI_OBJECT;

      case BINARY_LWE:
      case JAVA_LWE:
      case SCRIPT_LWE:
       return LWE_OBJECT;

      case UNKNOWN:
      case IMDESCRIPTOR:
      case OPERATION:
      case NUMBER_VARIABLE:
      case BOOL_VARIABLE:
      case CHAR_VARIABLE:
      case MTEXT_VARIABLE:
      case EVENT_VARIABLE:

      case NUMBER_PROPERTY:
      case BOOL_PROPERTY:
      case CHAR_PROPERTY:
      case MTEXT_PROPERTY:
      case EVENT_PROPERTY:
       return UNKNOWN_OBJECT;

      default:
       ERROR_INTERNAL("Invalid object type.");
   }
}

IMObject::IMObject(enum OBJTYPE x_type, bool x_downloadable)
    : type(x_type), downloadable(x_downloadable)
{
    IMObjectMgr::get_instance()->add(this, id);
}

/*******************************************************************************
                                 IMLang
 *******************************************************************************/

IMLangMatchPredicate::LocaleMap IMLangMatchPredicate::localemap;

IMLangMatchPredicate::IMLangMatchPredicate(
    const string* pattern
)
{
    if (localemap.empty()) {
	// Japanese locale variant.
	localemap["ja_JP.EUC"] = "ja";
	localemap["ja_JP.EUC-JP"] = "ja";
	localemap["ja_JP.eucJP"] = "ja";
	localemap["ja_JP.PCK"] = "ja";
	localemap["ja_JP.UTF-8"] = "ja";
	localemap["japanese"] = "ja";
	// Korean locale variant.
	localemap["ko.UTF-8"] = "ko";
	localemap["ko_KR.UTF-8"] = "ko";
	localemap["ko_KR.EUC"] = "ko";
	localemap["ko_KR.EUC-KR"] = "ko";
	localemap["korean"] = "ko";
	// Chinese locale variant
	localemap["zh.UTF-8"] = "zh_CN";
	localemap["zh_CN.UTF-8"] = "zh_CN";
	localemap["zh_CN.EUC"] = "zh_CN";
	localemap["zh_CN.EUC-CN"] = "zn_CN";
	localemap["zh_CN.GB18030"] = "zh_CN";
	localemap["zh.GBK"] = "zh_CN";
	localemap["zh_CN.GBK"] = "zh_CN";
	localemap["zh_CN.GB-K"] = "zh_CN";
	localemap["zh"] = "zh_CN";
	// Taiwanese locale variant
	localemap["zh_TW.UTF-8"] = "zh_TW";
	localemap["zh_TW.BIG5"] = "zh_TW";
	localemap["zh_TW.BIG-5"] = "zh_TW";
	localemap["zh_TW.EUC"] = "zh_TW";
	localemap["zh_TW.EUC-TW"] = "zh_TW";
	// Hongkong locale variant
	localemap["zh_HK.UTF-8"] = "zh_HK";
	localemap["zh_HK.BIG5HK"] = "zh_HK";
	// Thai locale variant
	localemap["th_TH.UTF-8"] = "th_TH";
	localemap["th_TH.TIS620"] = "th_TH";
	localemap["th_TH.ISO8859-11"] = "th_TH";
	localemap["th"] = "th_TH";
    }
    ppattern = pattern;
}

bool
IMLangMatchPredicate::operator()(
    const IMLang &l
) const
{
    if (ppattern->compare(l.identifier) == 0) return true;
    LocaleMap::iterator it = localemap.find(l.identifier);
    if ((it != localemap.end()) && (ppattern->compare(it->second) == 0)) return true;
    return false;
}

/*******************************************************************************
                                 IMKeySpec
 *******************************************************************************/

IMKeySpec::IMKeySpec(
    int x_keycode,
    int x_keychar,
    int x_modifier,
    int x_timestamp
)
{
    keycode = x_keycode;
    keychar = x_keychar;
    modifier = x_modifier;
    timestamp = x_timestamp;
}


/*******************************************************************************
                                 IMDescriptor
 *******************************************************************************/

IMDescriptor::IMDescriptor(
    u16string x_imname,
    u16string x_hrn,
    string x_domainname,
    const IMLangList& x_langs
) : IMObject(IMObject::IMDESCRIPTOR, false)
{
    imname = x_imname;
    hrn = x_hrn;
    domainname = x_domainname;
    langs = x_langs;
}

bool
IMDescriptorMatchPredicate::operator()(
    const IMDescriptor &d
) const
{
    return (ppattern->compare(d.imname) == 0);
}

/*******************************************************************************
                              IMObjectWithDesc
 *******************************************************************************/

void
IMObjectWithDesc::log_obj()
{
    const char none[] = "NONE";
    if (IMLog::get_instance()->check(IMLog::DEBUGLOG)) {
	LOG_DEBUG("object for %s\n"
		  "    object_type      = %d\n"
		  "    object id        = %d\n"
		  "    object size      = %d\n"
		  "    rev. domain name = %s\n"
		  "    path             = %s\n"
		  "    scope            = %s\n"
		  "    signature        = %s\n"
		  "    basepath         = %s\n"
		  "    encoding         = %s",
		  leid.c_str(),
		  (int) get_type(),
		  (int) get_attribid(),
		  size,
		  domain.get_charstr() ? domain.get_charstr() : none,
		  path.get_charstr() ? path.get_charstr() : none,
		  scope.get_charstr() ? scope.get_charstr() : none,
		  signature.get_charstr() ? signature.get_charstr() : none,
		  basepath.get_charstr() ? basepath.get_charstr() : none,
		  encoding.get_charstr() ? encoding.get_charstr() : none
	);
	list<u16string>::iterator it;
	for (it = jarfile_classes.begin();
	     it != jarfile_classes.end();
	     it++) {
	    LOG_DEBUG("    jarfile class    = %s",
		      it->get_charstr() ? it->get_charstr() : "Invalid");
	}
    }
}

const CARD8BIT*
IMObjectWithDesc::get_binary_representation()
{
    if (pbinrep) return pbinrep;
    switch (get_type()) {
      case IMObject::JAVA_GUI:
      case IMObject::JAVA_LWE:
       if (size > 0) {
	   if (!path.get_charstr()) return NULL;
	   pbinrep = IM_read_file(path.get_charstr(), size);
	   return pbinrep;
       }
       break;
    }
    return NULL;
}

void
IMObjectWithDesc::set_size()
{
    switch (get_type()) {
      case IMObject::JAVA_GUI:
      case IMObject::JAVA_LWE:
      {
	  int tsize;
	  if (!path.get_charstr()) return;
	  tsize = IM_file_size(path.get_charstr());
	  if (tsize > 0) size = tsize;
      }
       break;
    }
}

static enum IMObject::OBJTYPE
convert_od_type(IMObjectType ot)
{
    switch (ot) {
      case IM_DOWNLOADINGOBJECT_JARGUI_TYPE:
       return IMObject::JAVA_GUI;
      case IM_DOWNLOADINGOBJECT_JARLWE_TYPE:
       return IMObject::JAVA_LWE;
      case IM_DOWNLOADINGOBJECT_EIMIL_TYPE:
       return IMObject::EIMIL_CONFIG;
      case IM_DOWNLOADINGOBJECT_BINGUI_TYPE:
       return IMObject::BINARY_GUI;
      case IM_DOWNLOADINGOBJECT_BINLWE_TYPE:
       return IMObject::BINARY_LWE;
      case IM_DOWNLOADINGOBJECT_SGUI_TYPE:
       return IMObject::SCRIPT_GUI;
      case IM_DOWNLOADINGOBJECT_SLWE_TYPE:
       return IMObject::SCRIPT_LWE;
      default:
       ERROR_INTERNAL("Invalid Object Type.");
    }
    return IMObject::UNKNOWN;
}

IMObjectWithDesc::IMObjectWithDesc(
    const IMObjectDescriptorStruct &desc
) : IMObject(convert_od_type(desc.type), true)
{
    pbinrep = NULL;
    leid = desc.leid;
    size = desc.size;

    for (int i = 0; i < desc.count_names; i++) {
	jarfile_classes.push_back(u16string(desc.class_names[i]));
    }
    if (desc.name_length > 0) hrn = u16string(desc.name, desc.name_length);
    if (desc.domain) domain = u16string(desc.domain);
    if (desc.path) path = u16string(desc.path);
    if (desc.scope) scope = u16string(desc.scope);
    if (desc.signature) signature = u16string(desc.signature);
    if (desc.basepath) basepath = u16string(desc.basepath);
    if (desc.encoding) encoding = u16string(desc.encoding);

    set_size();
}

IMObjectWithDesc::~IMObjectWithDesc()
{
    if (pbinrep) free(pbinrep);
}

/*******************************************************************************
                                 IMObjectMgr
 *******************************************************************************/

const int attribid_id_max = ((1 << 15) - 1);

IMObjectMgr* IMObjectMgr::pimobjmgr = NULL;

CARD16BIT
IMObjectMgr::get_attribid(
    CARD32BIT id
)
{
    return (id & ((1 << 16) - 1));
}


IMObjectMgr::IMObjectMgr()
{
    attribid_counter = 0;
}

IMObjectMgr*
IMObjectMgr::construct()
{
    pimobjmgr = new IMObjectMgr();
    return pimobjmgr;
}

bool
IMObjectMgr::add(
    IMObject *pobj,
    CARD32BIT &id
)
{
    IMLock lock(sync_object);
    CARD32BIT aid;
#if 0
    if (pobj->downloadablep()) aid = attribid_counter++;
    else aid = id_counter++;
#else
    aid = attribid_counter++;
#endif
    if (aid > attribid_id_max) {
	LOG_CRITICAL("Maximum attribid is exceeded!!!.\n"
		     "We cannot continue operation any longer.");
	// TODO
	// we should throw exeption...
	exit(255);
    }
    if (pobj->downloadablep()) aid = aid | (1 << 15);
    id = (pobj->get_type() << 16) | aid;
    objmap[aid] = pobj;
    return true;
}

IMObject*
IMObjectMgr::get_object_from_fullid(
    CARD32BIT id
)
{
    return get_object_from_attribid(get_attribid(id));
}

IMObject*
IMObjectMgr::get_object_from_attribid(
    CARD16BIT id
)
{
    IMLock lock(sync_object);
    IMObjectMap::iterator it = objmap.find(id);
    if (it == objmap.end()) return NULL;
    return it->second;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
