
#include "../src/xtal/xtal.h"
#include "../src/xtal/xtal_macro.h"

#include "../src/xtal/xtal_lib/xtal_winthread.h"
#include "../src/xtal/xtal_lib/xtal_wincstdiostream.h"
#include "../src/xtal/xtal_lib/xtal_winfilesystem.h"
#include "../src/xtal/xtal_lib/xtal_winerrormessage.h"
#include "../src/xtal/xtal_lib/xtal_chcode.h"

using namespace xtal;

#include <vector>

#if defined(XTAL_USE_WCHAR)

#include <clocale>

#else

static int kcode = 's';

#endif

static bool debug_compile = false;

static void print_usage(){
	fprintf(stdout,
		"usage: xtal [options] [script [args]].\n"
		"Available options are:\n"
#if !defined(XTAL_USE_WCHAR)
		"  -Ks      set kcode sjis\n"
		"  -Ku      set kcode utf-8\n"
		"  -Ke      set kcode euc\n"
#endif
		"  -dc      enable debug compile\n"
		"  -v       show version information\n"
	);
}

static void handle_argv_options(char_t** argv){
	int i;
	for(i=1; argv[i]!=0; i++){
		if(argv[i][0]!=XTAL_L('-'))
			break;

		switch(argv[i][1]){
		case XTAL_L('v'):
			fprintf(stdout, "xtal %d.%d.%d.%d\n", VERSION1, VERSION2, VERSION3, VERSION4);
			break;

		case XTAL_L('d'):
			switch( argv[i][2] ){
			case XTAL_L('c'):
				debug_compile = true;
				break;
			}
			break;
			
#if !defined(XTAL_USE_WCHAR)
		case XTAL_L('K'):
			kcode = argv[i][2];
			break;
#endif
		default:
			print_usage();
			return;
		}
	
	}
}

static void handle_argv(char_t** argv){
	int i;
	for(i=1; argv[i]!=0; i++){
		if(argv[i][0]!=XTAL_L('-'))
			break;
	}

	if(argv[i]!=0){
		ArrayPtr arg_list(xnew<Array>());
		const char_t *filename = argv[i++];
		for(i=1; argv[i]!=0; i++){
			arg_list->push_back(argv[i]);
		}
		builtin()->def(Xid(argv), arg_list);
		load(filename);
	}
}

int _tmain(int argc, char_t** argv)
{
#if defined(XTAL_USE_WCHAR)
	std::setlocale(LC_ALL,"");
#endif

	WinThreadLib thread_lib;
	WinFilesystemLib filesystem_lib;
#if defined(XTAL_USE_WCHAR)
	WinUTF16CStdStreamLib utf16_std_stream_lib;
	UTF16ChCodeLib utf16_ch_code_lib;
#else
	WinSJISCStdStreamLib sjis_std_stream_lib;
	WinEUCCStdStreamLib euc_std_stream_lib;
	WinUTF8CStdStreamLib utf8_std_stream_lib;
	SJISChCodeLib sjis_ch_code_lib;
	EUCChCodeLib euc_ch_code_lib;
	UTF8ChCodeLib utf8_ch_code_lib;
#endif

	handle_argv_options(argv);

	Setting setting;
	setting.thread_lib = &thread_lib;
	setting.filesystem_lib = &filesystem_lib;
	
#if defined(XTAL_USE_WCHAR)
	setting.std_stream_lib = &utf16_std_stream_lib;
	setting.ch_code_lib = &utf16_ch_code_lib;
#else
	switch(kcode){
	case 's': 
		setting.std_stream_lib = &sjis_std_stream_lib;
		setting.ch_code_lib = &sjis_ch_code_lib;
		break;
	case 'u': 
		setting.std_stream_lib = &utf8_std_stream_lib;
		setting.ch_code_lib = &utf8_ch_code_lib;
		break;
	case 'e': 
		setting.std_stream_lib = &euc_std_stream_lib;
		setting.ch_code_lib = &euc_ch_code_lib;
		break;
	}
#endif

	initialize(setting);

	if( debug_compile ) 
		debug::enable_debug_compile();

	XTAL_PROTECT{
		bind_error_message();

		handle_argv(argv);
		
		XTAL_CATCH_EXCEPT(e){
#if defined(XTAL_USE_WCHAR)
			stderr_stream()->println(e);
#else
			UINT const console_codepage( GetConsoleOutputCP() );
			if( xtal::error_message_codepage == console_codepage ){
				stderr_stream()->println(e);
			}else{
				//	コンソールのコードページへ変換して出力
				WinCharCStdStreamLib	stream_lib(xtal::error_message_codepage);
				if( void* stream = stream_lib.new_stderr_stream() ){
					xtal::StringPtr str( e.to_s() );
					stream_lib.write_stderr_stream(  stream, str->c_str(), str->data_size() );
					stream_lib.delete_stderr_stream( stream );
				}
			}
#endif
		}

	}
	XTAL_OUT_OF_MEMORY{
		puts("out of memory");
	}
	
	uninitialize();

	return 0;
}
