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

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

int mk_node_initialize( MK_VM_STRUCT *vm, 
			   MK_VM_FRAME_ITEM *target /* Node */,
			   MK_VM_FRAME_ITEM *node,	/* MK_NODE_EXPR(NodeWithParam) */
			   MK_VM_FRAME_ITEM **result 
			   )
{
	if( ( MK_TYPE_ATTRIBUTE( node->flags ) == MK_VM_FRAME_ITEM_TYPE_NODE_VALUE ) &&
		( MK_OBJECT_TYPE( *node->code.node ) == MK_TYPE_NODE_EXPR ) &&
		( MK_TYPE_ATTRIBUTE( *node->code.node ) == MK_TYPE_NODE_EXPR_NODE_WITH_PARAM ) )
	{

		MK_VM_FRAME_ITEM *value = NULL;
		mk_find_item_hashtable( target->classTypeValue.variables,
			mk_get_symbol_name_ptr( vm, "node" ),
			(void**)&value );
		mk_object_equal( vm, value, node, &value );
	}
	else
	{
		// type error.
	}
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

int mk_node_invoke( MK_VM_STRUCT *vm, 
			   MK_VM_FRAME_ITEM *target /* Node */,
			   MK_VM_FRAME_ITEM *param,	/* Array<MK_VM_FRAME_ITEM> */
			   MK_VM_FRAME_ITEM **result 
			   )
{
	MK_VARIABLE *nodeWithParam = NULL;
	MK_VM_FRAME_ITEM *nodeItem = NULL;
	unsigned int*node = NULL;
	int index = 0;
	int sizeParam = 0;
	MK_VM_FRAME *newFrame = NULL, *oldFrame = NULL;
	
	if( MK_TYPE_ATTRIBUTE( param->flags ) != MK_VM_FRAME_ITEM_TYPE_ARRAY_VALUE )
		;	//todo: type error
	
	if( MK_TYPE_ATTRIBUTE( target->flags ) == MK_VM_FRAME_ITEM_TYPE_CLASS )
	{
		mk_find_item_hashtable( target->classTypeValue.variables,
			mk_get_symbol_name_ptr( vm, "node" ),
			(void**)&nodeItem );
		nodeWithParam = (MK_VARIABLE*)nodeItem->code.node;
	}
	else if( MK_TYPE_ATTRIBUTE( target->flags ) == MK_VM_FRAME_ITEM_TYPE_NODE_VALUE )
	{
		nodeWithParam = 
			(MK_VARIABLE*)target->code.node;
	}
	else
	{
		;	// todo: type error.
	}
	sizeParam = mk_size_vector( param->arrayTypeValue );
	mk_vm_push_stack( vm->localStack, (INT_PTR)vm->pCurrentFrame->pThis );
	for( index = 0; index < sizeParam; index ++ )
		mk_vm_push_stack( vm->localStack, mk_get_at_vector( param->arrayTypeValue, index ) );
	return mk_vm_call_method( vm, nodeWithParam );
}

MK_CLASS *mk_create_node_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, 
			"initialize", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE, 
			1,
			(INT_PTR)mk_node_initialize ),
		result );


	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"invoke", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE |
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_VARARGS,
			0, 
			(INT_PTR)mk_node_invoke ),
		result );

	mk_register_variable(
		vm,
		mk_create_variable(
			vm,
			"node",
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_VALUE |
				MK_TYPE_ATTRIBUTE_VARIABLE_READ_PROTECTED |
				MK_TYPE_ATTRIBUTE_VARIABLE_WRITE_PRIVATE |
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL,
			NULL ),
		result );

	return result;
}
