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

static const MK_CHAR className[] = CLASS_INTERNAL_ARRAY;
static const MK_CHAR classSuper[] = CLASS_INTERNAL_CONTAINER;

int mk_array_size( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM **result )
{
	int retCode = MK_VM_EXECUTE_EXPR_RETURN_RETURN;
	MK_VECTOR *targetArray = 
		target->arrayTypeValue;
	int size = 0;
	if( targetArray != NULL )
		size = mk_size_vector( targetArray );
	*result = 
		mk_vm_create_int32_frame_item( vm, size );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

int mk_array_grow( MK_VM_STRUCT *vm, 
				  MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *size, 
				  MK_VM_FRAME_ITEM **result )
{

	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

int mk_array_operator_bracket( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *right, MK_VM_FRAME_ITEM **result )
{
	int retCode = MK_VM_EXECUTE_EXPR_RETURN_RETURN;
	MK_VECTOR *targetArray = 
		target->arrayTypeValue;
	int index = 
		mk_vm_frame_item_to_int32( right );

	if( targetArray != NULL && 
		index >= 0 &&
		index < mk_size_vector( targetArray ) )
	{
		*result = 
			mk_create_vm_frame_item_object( &vm->pFrameItemTable );
		retCode = mk_object_equal( 
			vm, 
			*result, 
			(MK_VM_FRAME_ITEM*)mk_get_at_vector( targetArray, index ), 
			&(*result) );
	}
	else
	{
		MK_VM_FRAME_ITEM *execptionClass = NULL;
		MK_VM_FRAME_ITEM *exception = NULL;

		mk_find_item_hashtable( vm->global, 
			mk_get_symbol_name_ptr( vm, CLASS_INTERNAL_ARRAY_OUTOF_RANGE ), 
			(void**)&execptionClass );
		exception = 
			mk_create_internal_error_object( 
				vm, 
				"", 
				0,
				execptionClass,
				0,
				NULL );
		vm->exceptionObject = exception;
		retCode = MK_VM_EXECUTE_EXPR_THROW;	// todo: array out of range exception.
	}
	return retCode;
}

MK_CLASS *mk_create_array_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, 
			"size",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			0,
			(INT_PTR)mk_array_size ),
		result );

	mk_register_variable(
		vm,
		mk_create_method(
			vm,
			"grow",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			1,
			(INT_PTR)mk_array_grow ),
		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_BRACKET,
			1,
			(INT_PTR)mk_array_operator_bracket ),
		result );

	return result;
}
