/****************************************************************************
 * 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 KNH_USING_MATH
#include<math.h>
#endif

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

#ifdef __cplusplus
extern "C" {
#endif

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


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

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opAdd:2(Float! v) */

METHOD knh__Float_opAdd__2(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value + (sfp[1].f)->value));
	METHOD_RETURN(ctx, sfp, n);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opNeg() */

METHOD knh__Float_opNg(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, -((sfp[0].f)->value));
	METHOD_RETURN(ctx, sfp, n);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opSub:2(Float! n) */

METHOD knh__Float_opSub__2(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value - (sfp[1].f)->value));
	METHOD_RETURN(ctx, sfp, n);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opMul:2(Float! n) */

METHOD knh__Float_opMul__2(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value * (sfp[1].f)->value));
	METHOD_RETURN(ctx, sfp, n);
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opDiv:2(Float! n) */

METHOD knh__Float_opDiv__2(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value / (sfp[1].f)->value));
	METHOD_RETURN(ctx, sfp, n);
}

/* ------------------------------------------------------------------------ */
/* @method[VARARGS|STATIC] Float! Float.opAdd(Float! v) */

METHOD knh__Float_opAdd(Ctx *ctx, knh_sfp_t *sfp)
{
	knh_vargc_t ac = knh_sfp_argc(ctx, sfp);
	int i; knh_float_t n = (sfp[0].f)->value;
	for(i = 1; i < ac; i++) {
		n += (sfp[i].f)->value;
	}
	METHOD_RETURN(ctx, sfp, new_Float(ctx, n));
}

/* ------------------------------------------------------------------------ */
/* @method[VARARGS|STATIC] Float! Float.opSub(Float! n) */

METHOD knh__Float_opSub(Ctx *ctx, knh_sfp_t *sfp)
{
	knh_vargc_t ac = knh_sfp_argc(ctx, sfp);
	int i; knh_float_t n = (sfp[0].f)->value;
	for(i = 1; i < ac; i++) {
		n -= (sfp[i].f)->value;
	}
	METHOD_RETURN(ctx, sfp, new_Float(ctx, n));
}

/* ------------------------------------------------------------------------ */
/* @method[VARARGS|STATIC] Float! Float.opMul(Float! n) */

METHOD knh__Float_opMul(Ctx *ctx, knh_sfp_t *sfp)
{
	knh_vargc_t ac = knh_sfp_argc(ctx, sfp);
	int i; knh_float_t n = (sfp[0].f)->value;
	for(i = 1; i < ac; i++) {
		n *= (sfp[i].f)->value;
	}
	METHOD_RETURN(ctx, sfp, new_Float(ctx, n));
}

/* ------------------------------------------------------------------------ */
/* @method[VARARGS|STATIC] Float! Float.opDiv(Float! n) */

METHOD knh__Float_opDiv(Ctx *ctx, knh_sfp_t *sfp)
{
	knh_vargc_t ac = knh_sfp_argc(ctx, sfp);
	int i; knh_float_t n = (sfp[0].f)->value;
	for(i = 1; i < ac; i++) {
		n /= (sfp[i].f)->value;
	}
	METHOD_RETURN(ctx, sfp, new_Float(ctx, n));
}

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

METHOD knh__Float_opMod(Ctx *ctx, knh_sfp_t *sfp)
{
#ifdef KNH_USING_MATH
	knh_float_t a = (sfp[0].f)->value;
	knh_float_t b = (sfp[1].f)->value;
#if defined(KNH_FLOAT_TYPE__LONG_DOUBLE)
	Float *v = new_Float(ctx, (knh_float_t)fmodl((long double)a, (long double)b));
#elif defined(KNH_FLOAT_TYPE__FLOAT)
	Float *v = new_Float(ctx, (knh_float_t)fmodf((float)a, (float)b));
#else
	Float *v = new_Float(ctx, (knh_float_t)fmod((double)a, (double)b));
#endif
	METHOD_RETURN(ctx, sfp, v);
#else
	TODO_THROW(ctx);
#endif
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opEq(Float! value) */

METHOD knh__Float_opEq(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value == (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opNeq(Float! value) */

METHOD knh__Float_opNeq(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value != (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opLt(Float! value) */

METHOD knh__Float_opLt(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value < (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opLte(Float! value) */

METHOD knh__Float_opLte(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value <= (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opGt(Float! value) */

METHOD knh__Float_opGt(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value > (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}

/* ------------------------------------------------------------------------ */
/* @method[STATIC] Boolean! Float.opGte(Float! value) */

METHOD knh__Float_opGte(Ctx *ctx, knh_sfp_t *sfp)
{
	if((sfp[0].f)->value >= (sfp[1].f)->value) {
		METHOD_RETURN(ctx, sfp, KNH_TRUE);
	}
	else {
		METHOD_RETURN(ctx, sfp, KNH_FALSE);
	}
}



/* ------------------------------------------------------------------------ */
/* @method[STATIC] Float! Float.opNext() */

METHOD knh__Float_opNext(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value)+1.0);
	METHOD_RETURN(ctx, sfp, n);
}

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

/* @method[STATIC] Float! Float.opPrev() */

METHOD knh__Float_opPrev(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *n = new_Float(ctx, ((sfp[0].f)->value) - 1.0);
	METHOD_RETURN(ctx, sfp, n);
}

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

/* ------------------------------------------------------------------------ */
/* @method Float Float.random() @ClassFunc */

METHOD knh__Float_random(Ctx *ctx, knh_sfp_t *sfp)
{
	Float *v = new_Float(ctx, ((knh_float_t)knh_rand()) / KNH_UINT_MAX);
	METHOD_RETURN(ctx, sfp, v);
}

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

/* @map[STATIC] String Float */

Float* knh_String_Float(Ctx *ctx, String *s, Mapper *mpr)
{
	return new_FloatX__b(ctx, DP(mpr)->tcid, knh_String_tobytes(s));
}

/* ------------------------------------------------------------------------ */
/* @map Float String! @Static @Final */

String* knh_Float_String(Ctx *ctx, Float *o, Mapper *mpr)
{
	char buf[BUFSIZ_FLOAT];
	knh_format_Float(buf, sizeof(buf), o);
	return new_String(ctx, B(buf), NULL);
}

/* ------------------------------------------------------------------------ */
/* @map Int Float! @Static @Final */

Float* knh_Int_Float(Ctx *ctx, Int *o, Mapper *mpr)
{
	return new_FloatX(ctx, DP(mpr)->tcid, (knh_float_t)knh_Int_value((o)));
}

/* ------------------------------------------------------------------------ */
/* @map Float Int! @Static @Final */

Int* knh_Float_Int(Ctx *ctx, Float *o, Mapper *mpr)
{
	return new_IntX(ctx, DP(mpr)->tcid, knh_Float_toint(o));
}

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

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

void knh_Float__s(Ctx *ctx, Float *b, OutputStream *w, Any *m)
{
	knh_write__ffmt(ctx, w, KNH_FLOAT_FMT, b->value);
}

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

void knh_Float__k(Ctx *ctx, Float *b, OutputStream *w, Any *m)
{
	FloatUnit *u = (FloatUnit*)knh_tClass[b->h.cid].cspec;
	KNH_ASSERT(IS_FloatUnit(u));
	knh_write__ffmt(ctx, w, DP(u)->FMT, b->value);
}

/* ------------------------------------------------------------------------ */
/* @method void Float.%bits(OutputStream w, Any m) */

void knh_Float__bits(Ctx *ctx, Float *o, OutputStream *w, Any *m)
{
	if(sizeof(knh_uint_t) == 4) {
		union {
			struct { knh_uint64_t f; knh_uint_t l; } n;
			knh_float_t f;
		} u;
		u.f = o->value;;
		knh_write_bits(ctx, w, u.n.f, sizeof(knh_int_t) * 8);
		knh_putc(ctx, w, ' ');
		knh_write_bits(ctx, w, u.n.l, sizeof(knh_int_t) * 8);
	}
	else {
		TODO_THROW(ctx);
	}
}

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

void knh_Float__dump(Ctx *ctx, Float *b, OutputStream *w, Any *m)
{
	FloatUnit *u = (FloatUnit*)knh_tClass[b->h.cid].cspec;
	KNH_ASSERT(IS_FloatUnit(u));
	knh_write__ffmt(ctx, w, DP(u)->FMT, b->value);
	knh_bytes_t tag = knh_String_tobytes(DP(u)->spec.tag);
	if(tag.len > 0) {
		knh_putc(ctx, w, '[');
		knh_write(ctx, w, tag);
		knh_putc(ctx, w, ']');
	}
}

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

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

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

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

#ifdef __cplusplus
}
#endif
