/**********************************************************************

	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomohito Nakajima <nakajima@zeta.co.jp>

	This program is free software; you can redistribute it
	and/or modify it under the terms of the GLOBALBASE
	Library General Public License (G-LGPL) as published by

	http://www.globalbase.org/

	This program is distributed in the hope that it will be
	useful, but WITHOUT ANY WARRANTY; without even the
	implied warranty of MERCHANTABILITY or FITNESS FOR A
	PARTICULAR PURPOSE.

**********************************************************************/


#include <stdlib.h>
#include <io.h>

#include "machine/gb_windows.h"
#include "VApplication.h"

#include "v/VDisplay.h"
#include "v/VWindow.h"
#include "v/VChooseFile.h"
#include "vwin_error.h"

extern "C" {

#include "init.h"
#include "long_char.h"
#include "stream.h"
#include "task.h"
#include "utils.h"
#include "memory_debug.h"
#include "machine/msequence.h"
#include "pri_level.h"

void check_endian();
void init_msequence();
void check_endian();
void init_longchar();
void init_utils();
void init_netutils();
void init_event();
void init_resolve();
void init_wct();
void init_blacklist();
int _main(int,char**);
extern void v_loop();
}

VApplication *theApp = NULL;

static const WORD MAX_CONSOLE_LINES = 500;


void RedirectIOToConsole()
{
int hConHandle;
long lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;

	AllocConsole();
	GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
	coninfo.dwSize.Y = MAX_CONSOLE_LINES;
	SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);

	lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "w" );
	*stdout = *fp;
	setvbuf( stdout, NULL, _IONBF, 0 );

	lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "r" );
	*stdin = *fp;
	setvbuf( stdin, NULL, _IONBF, 0 );

	lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
	fp = _fdopen( hConHandle, "w" );
	*stderr = *fp;
	setvbuf( stderr, NULL, _IONBF, 0 );
}


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow )
{
	RedirectIOToConsole();
	VApplication app(hInstance, lpCmdLine, nCmdShow);
	theApp = &app;
	app.init();
	app.run();
	return 0;
}

VApplication::VApplication(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow)
{
	strcpy(command_line,lpCmdLine);
	command_show = nCmdShow;
	hinstance = hInstance;
	main_threadid = ::GetCurrentThreadId();
}

VApplication::~VApplication()
{
	// VDisplay::get_main_display()->destroy();
}

extern "C"{
	void init_app_window(){
		theApp->_init_app_window();
	}
}

static LRESULT CALLBACK VAppWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	return DefWindowProc( hWnd, message, wParam, lParam );
}
void VApplication::_init_app_window(){

	WNDCLASSEX wc;
	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
	wc.lpfnWndProc = VAppWndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = sizeof(DWORD);
	wc.hInstance = get_instance();
	wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = get_app_window_class_name();
	wc.hIconSm = NULL;
	
	if(!::RegisterClassEx(&wc)){
		VWinError();
	}

	// create application window (invisible)
	hwndMain = ::CreateWindowEx(
		0,
		get_app_window_class_name(),
		get_app_window_name(),
		WS_OVERLAPPEDWINDOW,
		0,
		0,
		0, 
		0, 
		NULL, 
		NULL, 
		theApp->get_instance(), 
		NULL);
}

void VApplication::init()
{
	check_endian();
	init_task(INI_DONTWAITCHI);
	init_msequence();
	check_endian();
	init_tick();
	init_d_alloc();
	init_longchar();
	init_wct();
	init_stream();
	init_utils();
	init_netutils();
	init_resolve();

	init_app_window();
}

int cmdline2args(char ***argv, const char *command_line){
	*argv = (char**)d_alloc(sizeof(char*)*__argc);
	for(int i=0; i<__argc; ++i){
		(*argv)[i] = __argv[i];
	}
	return __argc;
}

void
call_main()
{
	char **argv = 0;
	int argc = cmdline2args(&argv, theApp->get_command_line());
	_main(argc,argv);
}

void
VApplication::run()
{
	create_task(call_main, 0, 5);
	v_loop();
}

bool VApplication::quit()
{
	::PostMessage(hwndMain, WM_QUIT, NULL, NULL);
	return true;
}

