#include "machine/v_m.h"
#include "v/VObject.h"
#include "v/VWindow.h"

VWindowInfo::~VWindowInfo(){
	for(int i=0;i<MAX_MESSAGE_HANDLER;++i){
		delete message_handler[i];
	}
}

void VWindowInfo::add_message_handler(MessageHandler *handler){
/*
	pair<UINT,MessageHandler*> h(handler->get_messageid(), handler);
	message_handler.insert(h);
*/
	for(int i=0;i<MAX_MESSAGE_HANDLER; ++i){
		if(message_handler[i]==0){
			message_handler[i] = handler;
			return;
		}
	}
	er_panic("too many message handler. if you want more handers, change MAX_MESSAGE_HANDLER or make message_handler resizable :)");
}


/* call back from vqueue */
V_CALLBACK_D(message_handler_via_vqueue)
{
	MSG *msg = (MSG*)sys_arg;
	VWindowInfo *info = (VWindowInfo*)(((VWindow*)object)->get_info_this());
	info->dispatch_message(msg);
}


/*
This function is called from vqueue. 
This function dispatches VObject's events;
*/
void VWindowInfo::dispatch_message(MSG *msg){
	VWindow* vwin = dynamic_cast<VWindow*>(get_obj());
	
	// message_handler.equal_range(msg->message);
	for(int i=0;i<MAX_MESSAGE_HANDLER;++i){
		if(message_handler[i]==0)
			break;
		if(message_handler[i]->get_messageid()==msg->message){
			message_handler[i]->on_event(msg);
		}
	}

	switch(msg->message){
		case WM_SIZE:
		{
			VObjectStatus sts;
			RECT r;
			::GetClientRect(msg->hwnd, &r);
			sts.size.w = r.right-r.left;
			sts.size.h = r.bottom-r.top;
			if(vwin)
				VLayout::mark(vwin);
		}
		break;
		case WM_MOVE:
		{
			VObjectStatus sts;
			RECT r;
			::GetWindowRect(msg->hwnd, &r);
			sts.position.x = r.left;
			sts.position.y = r.top;
		}
		break;
		case WM_CLOSE:
		{
			if(vwin)
				vwin->attempt_close();
		}
		break;
		/*
		case WM_COMMAND:
		{
			if(!info)
				er_panic("VWindow must have VWindowInfo");
			OnCommand &cmd = info->on_command_handler[(int)msg->wParam];
			if(cmd.func)
				cmd.func(cmd.obj);
		}
		*/
		break;
		case WM_LBUTTONDOWN:
		{
			int debug=1;
		}
		break;
		case WM_LBUTTONUP:
		{
			int debug=1;
		}
	}
}

LRESULT VWindowInfo::dispatch_message_before_vqueue(MSG *msg){
	switch( msg->message ) {
	case WM_CREATE:
		{
			
		}
		break;
	case WM_PAINT:
		{
			
		}
		break;

	case WM_SIZE:
	case WM_MOVE:
	case WM_CLOSE:
	case WM_COMMAND:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
		{
			/* call message handler via vqueue */
			vq_insert_callback(this->get_obj(), message_handler_via_vqueue, NULL, msg, sizeof(*msg));
			
			if(msg->message == WM_CLOSE){
				/* 
					if you don't want close window, return 0.
					return 0; 
				*/
			}
		}
		break;
	}

	return DefWindowProc( msg->hwnd, msg->message, msg->wParam, msg->lParam );
}


LRESULT CALLBACK VWindowInfo::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	VWindowInfo *info = dynamic_cast<VWindowInfo *>(VInfo::get_from_hwnd(hWnd));
	MSG msg;
	if(!info)
		return DefWindowProc( hWnd, message, wParam, lParam );
	
	memset(&msg, 0, sizeof(msg));
	msg.hwnd = hWnd;
	msg.message = message;
	msg.lParam = lParam;
	msg.wParam = wParam;

	return info->dispatch_message_before_vqueue(&msg);
}