#include "mk.h"
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <stdio.h>

static const MK_CHAR className[] = CLASS_INTERNAL_FLOAT;
static const MK_CHAR classSuper[] = CLASS_INTERNAL_OBJECT;

static
int mk_floatto_s( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM **result )
{
	MK_CHAR value[32];
	*result = 
		mk_create_vm_frame_item_object( &vm->pFrameItemTable );
	(*result)->flags |= MK_VM_FRAME_ITEM_TYPE_STRING_VALUE;
	sprintf( value, "%f", mk_vm_frame_item_to_float( target ) );
	mk_copy_string( &(*result)->stringTypeValue, 
		(const char*)value );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}


static
int mk_float_to_i( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM **result )
{
	*result = 
		mk_vm_create_int32_frame_item( vm, mk_vm_frame_item_to_int32(target) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_float_to_f( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM **result )
{
	*result = 
		mk_vm_create_float_frame_item( vm, mk_vm_frame_item_to_float(target) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static 
int mk_float_plus( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	MK_FLOAT newValue = 
		mk_vm_frame_item_to_float( target ) + mk_vm_frame_item_to_float( right );
	*result = mk_vm_create_float_frame_item( vm, newValue );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_float_minus( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	MK_FLOAT newValue = 
		mk_vm_frame_item_to_float( target ) - mk_vm_frame_item_to_float( right );
	*result = mk_vm_create_float_frame_item( vm, newValue );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static 
int mk_float_mul( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	MK_FLOAT newValue = 
		mk_vm_frame_item_to_float( target ) * mk_vm_frame_item_to_float( right );
	*result = mk_vm_create_float_frame_item( vm, newValue );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static 
int mk_float_div( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	MK_FLOAT newValue = 
		mk_vm_frame_item_to_float( target ) / mk_vm_frame_item_to_float( right );
	*result = mk_vm_create_float_frame_item( vm, newValue );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static 
int mk_float_small( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	(*result) = 
		mk_vm_create_bool_frame_item( 
			mk_vm_frame_item_to_float( target ) < mk_vm_frame_item_to_float( right ) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}


static 
int mk_float_large( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	(*result) = 
		mk_vm_create_bool_frame_item( 
			mk_vm_frame_item_to_float( target ) > mk_vm_frame_item_to_float( right ) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}


static 
int mk_float_small_same( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	(*result) = 
		mk_vm_create_bool_frame_item( 
			mk_vm_frame_item_to_float( target ) <= mk_vm_frame_item_to_float( right ) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}


static 
int mk_float_large_same( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	(*result) = 
		mk_vm_create_bool_frame_item( 
			mk_vm_frame_item_to_float( target ) >= mk_vm_frame_item_to_float( right ) );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

MK_CLASS *mk_create_float_class( MK_VM_STRUCT *vm )
{
	MK_CLASS *result =
		mk_create_object( MK_TYPE_CLASS );
	
	result->nameThis = mk_get_symbol_name_ptr( vm, className );
	result->nameSuper = mk_get_symbol_name_ptr( vm, classSuper );

	mk_register_variable(
		vm,
		mk_create_method(
			vm, 
			"to_s",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_STATIC |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			0,
			(INT_PTR)mk_floatto_s ),
		result );

	mk_register_variable(
		vm,
		mk_create_method(
			vm,
			"to_i",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			0,
			(INT_PTR)mk_float_to_i ),
		result );

	mk_register_variable(
		vm,
		mk_create_method(
			vm,
			"to_f",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			0,
			(INT_PTR)mk_float_to_f ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"+",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_PLUS, 
			1, 
			(INT_PTR)mk_float_plus ),
		result);

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"-", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_MINUS, 
			1, 
			(INT_PTR)mk_float_minus ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"*", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_MUL, 
			1, 
			(INT_PTR)mk_float_mul ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"/", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_DIV, 
			1, 
			(INT_PTR)mk_float_div ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method(
			vm, 
			"<",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_SMALL, 
			1,
			(INT_PTR)mk_float_small ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method(
			vm, 
			">",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_BIG, 
			1,
			(INT_PTR)mk_float_large ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method(
			vm, 
			"<=",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_SE, 
			1,
			(INT_PTR)mk_float_small_same ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method(
			vm, 
			">=",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_OPERATOR |
				MK_LEX_TYPE_RESERVED_MARK_BE, 
			1,
			(INT_PTR)mk_float_large_same ),
		result );

	return result;
}
