/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER  
 * 
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation  
 * All rights reserved.
 * 
 * You may choose one of the following two licenses when you use konoha. 
 * See www.konohaware.org/license.html for further information.
 * 
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 ****************************************************************************/

/* ************************************************************************ */

#include"commons.h"

/* ************************************************************************ */

#ifdef __cplusplus 
extern "C" {
#endif

/* ======================================================================== */
/* [constructor] */

/* ------------------------------------------------------------------------ */
/* @method[VARARGS] This! Object.new:init(Any value) @VARARGS */

METHOD knh__Object_new__init(Ctx *ctx, knh_sfp_t *sfp)
{
	Object *o = sfp[0].o;
	knh_class_t cid = knh_Object_cid(o);
	knh_sfp_t *v = sfp + 1;
	knh_vargc_t ac = knh_sfp_argc(ctx, v);
	int i;
	for(i = 0; i < ac; i+= 2) {
		if(IS_bString(v[i].s)) {
			knh_fieldn_t fn = knh_tName_get_fnq(ctx, knh_String_tobytes(v[i].s), FIELDN_NONAME);
			if(fn == FIELDN_NONAME) continue;
			knh_index_t idx = knh_Class_queryField(cid, fn);
			if(idx == -1) continue;
			knh_cfield_t *cf = knh_Class_fieldAt(cid, idx);
			knh_type_t type = knh_pmztype_totype(ctx, cf->type, cid);
			DBG2_P("[%d] %s%s %s", (int)idx, TYPEQN(type), FIELDN(fn));
			KNH_SETv(ctx, KNH_FIELDn(o, idx), knh_Object_opAs__type(ctx, v[i+1].o, type, KNH_FIELDn(o,idx)));
		}
	}
	METHOD_RETURN(ctx, sfp, o);
}

/* ------------------------------------------------------------------------ */
/* @method This! Object.getDefault() */

METHOD knh__Object_getDefault(Ctx *ctx, knh_sfp_t *sfp)
{
	METHOD_RETURN(ctx, sfp, knh_tClass_defaultValue(ctx, knh_Object_cid(sfp[0].o)));
}

/* ======================================================================== */
/* [method] */

/* ------------------------------------------------------------------------ */
/* @method Int! Object.compareTo(Any o) */

INLINE
int knh_Object_compareTo(Object *o1, Object *o2)
{
	knh_class_t bcid = o1->h.bcid;
	knh_class_t bcid2 = o2->h.bcid; 
	if(bcid == bcid2) {
		if(bcid == CLASS_Object) {
			int idx = knh_tClass[o1->h.cid].keyidx;
			if(idx != -1) {
				int res = knh_Object_compareTo(KNH_FIELDn(o1, idx), KNH_FIELDn(o2, idx));
				if(res == 0) return res;
				idx = knh_tClass[o1->h.cid].keyidx2;
				if(idx != -1) {
					return knh_Object_compareTo(KNH_FIELDn(o1, idx), KNH_FIELDn(o2, idx));
				}
				return res;
			}
			return (knh_int_t)o1 - (knh_int_t)o2;
		}
		else {
			return knh_tStruct[bcid].fcompareTo(o1, o2);
		}
	}
	else {
		if((o1->h.cid == CLASS_Int || o1->h.cid == CLASS_Float || o1->h.cid == CLASS_Int64)
		&& (o2->h.cid == CLASS_Int || o2->h.cid == CLASS_Float || o2->h.cid == CLASS_Int64)) {
			return (int)(knh_Number_tofloat(o1) - knh_Number_tofloat(o2));
		}
		DBG2_P("Compared Incompatible Type %s - %s", CLASSN(o1->h.cid), CLASSN(o2->h.cid));
		return (int)(o1 - o2);
	}
}

/* ------------------------------------------------------------------------ */

INLINE
knh_bool_t knh_Object_equals(Object *o1, Object *o2)
{
	return (knh_Object_compareTo( o1, o2) == 0); 
}


/* ======================================================================== */
/* [operators] */

/* @method[STATIC] Boolean Object.opEq(Any value) */

METHOD knh__Object_opEq(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) == 0) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opNeq(Any value) */

METHOD knh__Object_opNeq(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) == 0) {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opLt(Any value) */

METHOD knh__Object_opLt(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) < 0) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opLte(Any value) */

METHOD knh__Object_opLte(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) <= 0) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opGt(Any value) */

METHOD knh__Object_opGt(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) > 0) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opGte(Any value) */

METHOD knh__Object_opGte(Ctx *ctx, knh_sfp_t *sfp)
{
	if(knh_Object_compareTo( sfp[0].o, sfp[1].o) >= 0) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opNot() */

METHOD knh__Object_opNot(Ctx *ctx, knh_sfp_t *sfp)
{
	if(!(IS_TRUE(sfp[0].o))) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opSeq(Any value) */

METHOD knh__Object_opSeq(Ctx *ctx, knh_sfp_t *sfp)
{
	TODO_THROW(ctx);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean Object.opIsMapTo(Any value) */

METHOD knh__Object_opIsMapTo(Ctx *ctx, knh_sfp_t *sfp)
{
	TODO();
	METHOD_RETURN(ctx, sfp, KNH_FALSE);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Class Object.getClass() */

METHOD knh__Object_getClass(Ctx *ctx, knh_sfp_t *sfp)
{
	METHOD_RETURN(ctx, sfp, knh_tClass[(sfp[0].o)->h.cid].class);
}

/* ======================================================================== */
/* [mapping] */

/* ------------------------------------------------------------------------ */
/* @map[STATIC] Object Iterator! */

Iterator* knh_Object_Iterator(Ctx *ctx, Object *o, Mapper *mpr)
{
	return new_Iterator(ctx, o->h.cid, o, NULL);
}

/* ------------------------------------------------------------------------ */
/* @method This.. Object.opItr() */

METHOD knh__Object_opItr(Ctx *ctx, knh_sfp_t *sfp)
{
	METHOD_RETURN(ctx, sfp, new_Iterator(ctx, knh_Object_cid(sfp[0].o), sfp[0].o, NULL));
}

/* ------------------------------------------------------------------------ */
/* ======================================================================== */
/* [movabletext] */

/* @method void Object.%s(OutputStream w, Any m) */

INLINE
void knh_Object__s(Ctx *ctx, Object *b, OutputStream *w, Any *m)
{
	if(IS_NULL(b)) {
		knh_write(ctx, w, STEXT("null"));
	}
	else {
		knh_write__s(ctx,w, CLASSN(knh_Object_cid(b)));
		knh_write(ctx,w, STEXT(":"));
		knh_write__p(ctx,w, (void*)b);
	}
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%k(OutputStream w, Any m) */

void knh_Object__k(Ctx *ctx, Object *o, OutputStream *w, Any *m)
{
	if(o->h.bcid == CLASS_Object) {
		size_t bsize = knh_tClass[o->h.cid].bsize;
		knh_write__s(ctx, w, CLASSN(o->h.cid));
		if(bsize > 0) {
			int i;
			Object **v = (Object**)o->ref;
			knh_putc(ctx, w, '{');
			for(i = 0; i < bsize; i++) {
				knh_cfield_t *cf = knh_Class_fieldAt(knh_Object_cid(o), i);
				if(i > 0) {
					knh_write_delim(ctx, w);
				}
				knh_printf(ctx, w, "%s: ", FIELDN(cf->fn));
				knh_format(ctx, w, METHODN__k, v[i], KNH_NULL);
			}
			knh_putc(ctx, w, '}');
		}
	}
	else {
		knh_format(ctx, w, METHODN__s, o, KNH_NULL);
	}
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%dump(OutputStream w, Any m) */

INLINE
void knh_Object__dump(Ctx *ctx, Object *b, OutputStream *w, Any *m)
{
	knh_class_t cid = knh_Object_cid(b);
	if(cid < KONOHA_TSTRUCT_SIZE) {
		knh_format(ctx, w, METHODN__s, b, KNH_NULL);
		return ;
	}
	knh_int_t i, c = 0;
	knh_putc(ctx, w, '[');
	for(i = 0; i < knh_tClass[cid].bsize; i++) {
		knh_cfield_t *cf = knh_Class_fieldAt(cid, i);
		if(cf->fn == FIELDN_NONAME || KNH_FLAG_IS(cf->flag, KNH_FLAG_CFF_HIDDEN)) continue;
		if(c > 0) {
			knh_write_delim(ctx, w);
		}
		knh_printf(ctx, w, "%s=", /* cf->type, */ FIELDN(cf->fn));
		Object *v = KNH_FIELDn(b, i);
		if(IS_bString(v)) {
			knh_format(ctx, w, METHODN__dump, v, KNH_NULL);
		}
		else {
			knh_format(ctx, w, METHODN__s, v, KNH_NULL);
		}
		c++;
	}
	knh_putc(ctx, w, ']');
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%empty(OutputStream w, Any m) */

INLINE
void knh_Object__empty(Ctx *ctx, Object *b, OutputStream *w, Any *m)
{
	
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%refc(OutputStream w, Any m) */

INLINE
void knh_Object__refc(Ctx *ctx, Object *o, OutputStream *w, Any *m)
{
#if defined(KONOHA_WITH_RCGC)
	knh_write__u(ctx, w, o->h.refc);
#else
	knh_write__s(ctx, w, "0");
#endif
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%addr(OutputStream w, Any m) */

INLINE
void knh_Object__addr(Ctx *ctx, Object *b, OutputStream *w, Any *m)
{
	knh_write__p(ctx, w, (void*)b);
}

/* ------------------------------------------------------------------------ */

/* ======================================================================== */
/* [mapping] */

/* ------------------------------------------------------------------------ */

#ifdef __cplusplus
}
#endif
