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

	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 "vwin_control.h"
#include "machine/gb_windows.h"
#include "machine/lc_util.h"
#include "v/v_serialized_exec.h"

extern "C"{
#include "memory_debug.h"

int
_SendMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	return SendMessage(hwnd, msg, wp, lp);
}
}

void win_control_default_get_status(
	HWND hwnd, VObjectStatus *s, int flags, VExError *err)
{
	if ( flags & VSF_ENABLED ) {
		s->enabled = ::IsWindowEnabled(hwnd)==TRUE;
		err->subcode1 &= ~VSF_ENABLED;
	}
	
	if ( (flags & VSF_POSITION) || (flags & VSF_SIZE) ) {
		RECT r;
		::GetWindowRect(hwnd, &r);
	
		if ( flags & VSF_POSITION ) {
			int sx = 0, sy = 0;
			VContainerInfo *parent = dynamic_cast<VContainerInfo*>(
				VInfo::get_from_hwnd(GetParent(hwnd)));
			parent->get_scroll_pos(sx, sy);
			s->position.x = r.left + sx;
			s->position.y = r.top + sy;
			err->subcode1 &= ~VSF_POSITION;
		}

		if ( flags & VSF_SIZE ) {
			s->size.w = r.right-r.left;
			s->size.h = r.bottom-r.top;
			err->subcode1 &= ~VSF_SIZE;
		}
	}
}

void _win_control_default_set_status(
	HWND hwnd, const VObjectStatus *s, int flags, VExError *err)
{
	if ( flags & VSF_DESC ) {
		if ( s->descriptor ) {
			char *cstr;
			wchar_t *wstr;
			l2native(&cstr, &wstr, s->descriptor);
			if(cstr){
				::SetWindowTextA(hwnd, cstr);
				d_f_ree(cstr);
			}
			else if(wstr){
				::SetWindowTextW(hwnd, wstr);
				d_f_ree(wstr);
			}
		}
		else{
			::SetWindowTextW(hwnd, L"");
		}
		err->subcode1 &= ~VSF_DESC;
	}

	if ( flags & VSF_ENABLED ) {
		if( (::IsWindowEnabled(hwnd)==TRUE) != s->enabled )
			::EnableWindow(hwnd, (BOOL)s->enabled);
		err->subcode1 &= ~VSF_ENABLED;
	}

	if ( ! (flags & (VSF_SIZE | VSF_POSITION)) )
		return;

	RECT current_rect;
	::GetWindowRect(hwnd, &current_rect);
	HWND hParent = GetParent(hwnd);
	LPPOINT pt = (LPPOINT)&current_rect;
	ScreenToClient(hParent, pt);
	ScreenToClient(hParent, pt+1);

	int swp_flags = SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE;
	int x = 0, y = 0, cx = 0, cy = 0;
	if ( (flags & VSF_SIZE) && 
			((current_rect.right-current_rect.left)!=s->size.w ||
			(current_rect.bottom-current_rect.top)!=s->size.h)) {
		swp_flags &= ~SWP_NOSIZE;
		cx = s->size.w;
		cy = s->size.h;
	}

	if ( flags & VSF_POSITION ) {
		int sx = 0, sy = 0;
		VContainerInfo *parent = dynamic_cast<VContainerInfo*>(
			VInfo::get_from_hwnd(hParent));
		parent->get_scroll_pos(sx, sy);
		if ( (pt->x != s->position.x - sx) || 
			 (pt->y  != s->position.y - sy) ) {
			swp_flags &= ~SWP_NOMOVE;
			x = s->position.x - sx;
			y = s->position.y - sy;
		}
	}

	if ( swp_flags != (SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE) ) {
		char class_name[32];
		GetClassName(hParent, class_name, sizeof(class_name));
		if ( strcmp("Button", class_name) == 0 ) {
			HWND _hParent = GetParent(hParent);
			while ( 1 ) {
				GetClassName(_hParent, class_name, sizeof(class_name));
				if ( strcmp("Button", class_name) != 0 )
					break;
				_hParent = GetParent(hParent);
			}
			MapWindowPoints(hParent, _hParent, (LPPOINT)&current_rect, 2);
			hParent = _hParent;
		}
		else {
			GetClassName(hwnd, class_name, sizeof(class_name));
			if ( strcmp("vobj_align_view", class_name) == 0 )
				hParent = NULL;
		}

		if ( hParent )
			InvalidateRect(hParent, &current_rect, TRUE);
		::SetWindowPos(hwnd, NULL, x, y, cx, cy, swp_flags);
		if ( ! (swp_flags & SWP_NOMOVE) )
			InvalidateRect(hwnd, NULL, FALSE);
	}
	err->subcode1 &= ~VSF_POSITION|VSF_POSITION;
}


void win_control_default_set_status(
	HWND hwnd, const VObjectStatus *s, int flags, VExError *err)
{
	if ( flags & (VSF_DESC|VSF_ENABLED|VSF_SIZE|VSF_POSITION) )
		v_serialized_exec_sub(_win_control_default_set_status, hwnd, s, flags, err);
}

void win_redraw_(HWND hwnd, VRect *rect){

	if ( rect ){
		RECT r;
		r.left = rect->l;
		r.top = rect->t;
		r.right = rect->r;
		r.bottom = rect->b;
		::InvalidateRect(hwnd, &r, TRUE);
	}
	else
	{
		::InvalidateRect(hwnd, NULL, TRUE);
	}

	::UpdateWindow(hwnd);
}

void win_redraw(HWND hwnd, VRect *rect){
	v_serialized_exec_sub(win_redraw_, hwnd, rect);
}
