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

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

static 
int mk_io_open( MK_VM_STRUCT *vm,  
			   MK_VM_FRAME_ITEM *target /* IO */,
			   MK_VM_FRAME_ITEM *targetName, /* String */
			   MK_VM_FRAME_ITEM *mode, /* String */
			   MK_VM_FRAME_ITEM **result /* IO( this ) */ )
{
	MK_VM_FRAME_ITEM *fp = NULL;
	FILE *file = NULL;

	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	file = 
		fopen(targetName->stringTypeValue, mode->stringTypeValue );
	if( fp->nativeObjectTypeValue.nativePtr != NULL )
		fclose( fp->nativeObjectTypeValue.nativePtr );
	fp->nativeObjectTypeValue.nativePtr = file;
	if( fp == NULL )
		;	// TODO:IOException
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static 
int mk_io_is_open( MK_VM_STRUCT *vm,  
			   MK_VM_FRAME_ITEM *target /* IO */,
			   MK_VM_FRAME_ITEM **result /* IO( this ) */ )
{
	MK_VM_FRAME_ITEM *fp = NULL;
	FILE *file = NULL;

	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	*result =
		mk_vm_create_bool_frame_item( fp->nativeObjectTypeValue.nativePtr != NULL );
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_io_reopen( MK_VM_STRUCT *vm, 
			   MK_VM_FRAME_ITEM *target /* IO */,
			   MK_VM_FRAME_ITEM *targetName, /* String */
			   MK_VM_FRAME_ITEM *mode, /* String */
			   MK_VM_FRAME_ITEM **result /* IO( this ) */ )
{
	MK_VM_FRAME_ITEM *fp = NULL;
	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	if( fp->nativeObjectTypeValue.nativePtr != NULL )
	{
		fp->nativeObjectTypeValue.nativePtr = 
			freopen( 
				targetName->stringTypeValue, 
				mode->stringTypeValue, 
				fp->nativeObjectTypeValue.nativePtr );
	}
	else
	{
		// file do not opened exception.
	}
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_io_print( MK_VM_STRUCT *vm, 
				MK_VM_FRAME_ITEM *target, 
				MK_VM_FRAME_ITEM *string,
				MK_VM_FRAME_ITEM **result )
{
	MK_VM_FRAME_ITEM *fp = NULL;
	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	if( fp->nativeObjectTypeValue.nativePtr != NULL )
	{
		fputs( string->stringTypeValue, fp->nativeObjectTypeValue.nativePtr );
	}
	else
	{
		// file do not opened exception.
	}
	*result = target;
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_io_println( MK_VM_STRUCT *vm, 
				MK_VM_FRAME_ITEM *target, 
				MK_VM_FRAME_ITEM *string,
				MK_VM_FRAME_ITEM **result )
{
	MK_VM_FRAME_ITEM *fp = NULL;
	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	if( fp->nativeObjectTypeValue.nativePtr != NULL )
	{
		fputs( string->stringTypeValue, fp->nativeObjectTypeValue.nativePtr );
		fputs( "\n", fp->nativeObjectTypeValue.nativePtr );
	}
	else
	{
		// file do not opened exception.
	}
	*result = target;
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_io_read( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *fname, MK_VM_FRAME_ITEM *mode, MK_VM_FRAME_ITEM **result )
{
	return MK_VM_EXECUTE_EXPR_RETURN_NEXTSTEP;
}

static
int mk_io_write( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *fname, MK_VM_FRAME_ITEM *mode, MK_VM_FRAME_ITEM **result )
{
	return MK_VM_EXECUTE_EXPR_RETURN_NEXTSTEP;
}

static
int mk_io_getc( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *fname, MK_VM_FRAME_ITEM *mode, MK_VM_FRAME_ITEM **result )
{
	return MK_VM_EXECUTE_EXPR_RETURN_NEXTSTEP;
}

static
int mk_io_close( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM **result )
{
	MK_VM_FRAME_ITEM *fp = NULL;

	mk_find_item_hashtable( target->classTypeValue.variables,
		mk_get_symbol_name_ptr( vm, "fp" ), (void**)&fp );
	if( fp != NULL &&
		fp->nativeObjectTypeValue.nativePtr != NULL )
	{
		fclose( (FILE*)fp->nativeObjectTypeValue.nativePtr );
		if( fp != NULL )
			fp->nativeObjectTypeValue.nativePtr = NULL;
	}
	else
	{
		;	// TODO: file do not open exception.
	}
	*result = target;
	return MK_VM_EXECUTE_EXPR_RETURN_RETURN;
}

static
int mk_io_lshift( MK_VM_STRUCT *vm, MK_VM_FRAME_ITEM *target, MK_VM_FRAME_ITEM *fname, MK_VM_FRAME_ITEM *mode, MK_VM_FRAME_ITEM **result )
{
	return MK_VM_EXECUTE_EXPR_RETURN_NEXTSTEP;
}


MK_CLASS *mk_create_io_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, 
			"open", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			2, 
			(INT_PTR)mk_io_open ),
		result );

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

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"reopen", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			2, 
			(INT_PTR)mk_io_reopen ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"print", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			1, 
			(INT_PTR)mk_io_print ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"println", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			1, 
			(INT_PTR)mk_io_println ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"read", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			2, 
			(INT_PTR)mk_io_read ),
		result );

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"write", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			2, 
			(INT_PTR)mk_io_write ),
		result );

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

	mk_register_variable( 
		vm,
		mk_create_method( 
			vm, 
			"close", 
			MK_TYPE_VARIABLE | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD | 
				MK_TYPE_ATTRIBUTE_VARIABLE_FINAL | 
				MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE,
			0, 
			(INT_PTR)mk_io_close ),
		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_LSHIFT, 
			1, 
			(INT_PTR)mk_io_lshift ),
		result);

	mk_register_variable( 
		vm,
		mk_create_variable( vm, 
			"fp", 
			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;
}
