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


/* ======================================================================== */
/* [macros] */

#define _INT_BUFSIZ 32
#define _knh_Int_value(b)      (b)->value

/* ======================================================================== */
/* [structs] */

void
knh_Int_struct_init(Ctx *ctx, Struct *s1, int init, Object *cs)
{
	Int *b =  (Int*)s1;
	b->value = 0;
}

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

void
knh_Int_struct_copy(Ctx *ctx, Struct *s1, Struct *s2)
{
	Int *b =  (Int*)s1;
	Int *b2 = (Int*)s2;
	b2->value = b->value;
}

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

knh_int_t
knh_Int_struct_compare(Ctx *ctx, Struct *s1, Struct *s2) 
{
	Int *b =  (Int*)s1;
	Int *b2 = (Int*)s2;
	knh_class_t cid = knh_struct_cid(s1);
	return knh_IntUnit_compare(knh_tclass_getIntUnit(ctx, cid), b->value, b2->value);
}

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

#define _knh_Int_struct_traverse NULL

/* ======================================================================== */
/* [constructors] */

Int* new_Int__fast(Ctx *ctx, knh_class_t cid, knh_int_t value)
{
	Int *b = (Int*)knh_Object_malloc0(ctx, OF_Int, cid, sizeof(Int));
	b->value = value;
	return b;
}

#define _new_Int(ctx, value) new_Int__checked(ctx, CLASS_Int, value)

/* ======================================================================== */
/* [utils] */

INLINE
knh_int_t knh_int_max(knh_int_t a, knh_int_t b)
{
	return (a > b) ? a : b;
}

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

INLINE
knh_int_t knh_int_min(knh_int_t a, knh_int_t b)
{
	return (a < b) ? a : b;
}

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

INLINE
knh_uint_t knh_uint_max(knh_uint_t a, knh_uint_t b)
{
	return (a > b) ? a : b;
}

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

INLINE
knh_uint_t knh_uint_min(knh_uint_t a, knh_uint_t b)
{
	return (a < b) ? a : b;
}

/* ======================================================================== */
/* [mappings] */

/* @map[STATIC] String Int */

Object* knh_String_Int(Ctx *ctx, Object *self, MapMap *map)
{
	knh_bytes_t t = knh_String_tobytes(self);
//	if(!knh_byte_isNumber(t)) {
//		return_Null(ctx, "Format!!: %s", t.buf);
//	}
	return new_Int(ctx, knh_bytes_toint(t));
}

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

/* @map[STATIC] Int String! */

Object* knh_Int_String(Ctx *ctx, Object *self, MapMap *map)
{
	Int *b = (Int*)self;
	char buf[KNH_INTUNIT_BUFSIZ];
	knh_IntUnit_format(knh_tclass_getIntUnit(ctx, knh_Object_cid(b)), buf, b->value);
	return new_String__fast(ctx, CLASS_String, B(buf));
}

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

/* @method[STATIC] Int! Int.opAdd(Int! v) */

//INLINE
//knh_int_t knh_Int_opAdd(Int *b, Int *n)
//{
//	return knh_Int_value(b) + knh_Int_value(n);
//}

void knh__Int_opAdd(Ctx *ctx, Object **sfp)
{
	Int *n = new_Int(ctx, (knh_Int_value((Int*)sfp[0]) + knh_Int_value((Int*)sfp[1])));
	VM_RET(ctx, n);
}

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

/* @method[STATIC] Int! Int.opSub(Int! n) */

//INLINE
//knh_int_t knh_Int_opSub(Int *b, Int *n)
//{
//	return knh_Int_value(b) - knh_Int_value(n);
//}

void knh__Int_opSub(Ctx *ctx, Object **sfp)
{
	Int *n = new_Int(ctx, (knh_Int_value((Int*)sfp[0]) - knh_Int_value((Int*)sfp[1])));
	VM_RET(ctx, n);
}

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

/* @method[STATIC] Int! Int.opMul(Int! n) */

//INLINE
//knh_int_t knh_Int_opMul(Int *b, Int *n)
//{
//	return knh_Int_value(b) * knh_Int_value(n);
//}

void knh__Int_opMul(Ctx *ctx, Object **sfp)
{
	Int *n = new_Int(ctx, (knh_Int_value((Int*)sfp[0]) * knh_Int_value((Int*)sfp[1])));
	VM_RET(ctx, n);
}

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

/* @method[STATIC] Int! Int.opDiv(Int! n) */

//INLINE
//knh_int_t knh_Int_opDiv(Int *b, Int *n)
//{
//	return knh_Int_value(b) / knh_Int_value(n);
//}

void knh__Int_opDiv(Ctx *ctx, Object **sfp)
{
	Int *n = new_Int(ctx, (knh_Int_value((Int*)sfp[0]) / knh_Int_value((Int*)sfp[1])));
	VM_RET(ctx, n);
}

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

/* @method[STATIC] Int! Int.opMod(Int! n) */

//INLINE
//knh_int_t knh_Int_opMod(Int *b, Int *n)
//{
//	return knh_Int_value(b) % knh_Int_value(n);
//}

void knh__Int_opMod(Ctx *ctx, Object **sfp)
{
	Int *n = new_Int(ctx, (knh_Int_value((Int*)sfp[0]) % knh_Int_value((Int*)sfp[1])));
	VM_RET(ctx, n);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Bool Int.opEq(Int! value) */

void knh__Int_opEq(Ctx *ctx, Object **sfp)
{
	if(((Int*)sfp[0])->value == ((Int*)sfp[1])->value) {
		VM_RET(ctx, True);
	}
	else {
		VM_RET(ctx, False);
	}
}

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

/* @method[STATIC] Int! Int.opBitAnd(Int! v) */

INLINE
knh_int_t knh_Int_opBitAnd(Int *b, Int *n)
{
	return knh_Int_value(b) & knh_Int_value(n);
}

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

/* @method[STATIC] Int! Int.opBitOr(Int! v) */

INLINE
knh_int_t knh_Int_opBitOr(Int *b, Int *n)
{
	return knh_Int_value(b) | knh_Int_value(n);
}

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

/* @method[STATIC] Int! Int.opLShift(Int! n) */

INLINE
knh_int_t knh_Int_opLShift(Int *b, knh_int_t n)
{
	return knh_Int_value(b) << n;
}

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

/* @method[STATIC] Int! Int.opRShift(Int! n) */

INLINE
knh_int_t knh_Int_opRShift(Int *b, knh_int_t n)
{
	return knh_Int_value(b) >> n;
}

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

/* @method[STATIC] Int! Int.opBitXor(Int! n) */

INLINE
knh_int_t knh_Int_opBitXor(Int *b, knh_int_t n)
{
	return (knh_Int_value(b)) ^ n;
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Int! Int.opBitNot() */

INLINE
knh_int_t knh_Int_opBitNot(Int *b)
{
	return ~(knh_Int_value(b));
}

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

/* @method void Int.%s(Writer w, Any m) */

void knh_Int__s(Ctx *ctx, Int *b, Writer *w, Any *m)
{
	knh_write__i(ctx, w, b->value);
}

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

/* @method void Int.%x(Writer w, Any m) */

void knh_Int__x(Ctx *ctx, Int *b, Writer *w, Any *m)
{
	knh_write__x(ctx, w, b->value);
}

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

/* @method void Int.%bits(Writer w=new, Any m) */

void knh_Int__bits(Ctx *ctx, Int *b, Writer *w, Any *m)
{
	knh_uint_t i, flag = 1 << (sizeof(knh_int_t) - 1);
	for(i = 0; i < sizeof(knh_int_t); i++) {
		if(i > 0 && i % 8 == 0) {
			knh_putc(ctx, w, ' ');
		}
		if((flag & b->value) == flag) {
			knh_putc(ctx, w, '1');
		}else{
			knh_putc(ctx, w, '0');
		}
		flag >>= 1;
	}
}

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

///* @method void Int.%dump(Writer w=new, Any m) */
//
//void knh_Int__dump(Ctx *ctx, Int *b, Writer *w, Any *m)
//{
////	char buf[FMT_NSPEC_BUFSIZE];
////	IntSpec *spec = knh_tclass_getIntUnit(ctx, knh_Object_cid(b));
////	knh_IntSpec_format(spec, buf, knh_Int_value(b)); 
////	knh_prints(ctx, w, buf);
//}

#ifdef __cplusplus
}
#endif
