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

/* ------------------------------------------------------------------------ */
/* @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);
}

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

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


/* ------------------------------------------------------------------------ */
/* ======================================================================== */
/* [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.%repr(OutputStream w=new, Any m) */

void knh_Object__repr(Ctx *ctx, Object *o, OutputStream *w, Any *m)
{
	knh_format(ctx, w, METHODN__s, o, KNH_NULL);
}

/* ------------------------------------------------------------------------ */
/* @method void Object.%dump(OutputStream w=new, 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=new, Any m) */

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

/* ------------------------------------------------------------------------ */
/* @method void Object.%refc(OutputStream w=new, 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=new, 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
