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

	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomohito Nakajima <nakajima@zeta.co.jp>
	Tomoki Sekiyama <sekiyama@yahoo.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 "machine/gb_windows.h"
#include "v/VTabView.h"
#include "v/VLayout.h"
#include "VApplication.h"
#include "vobject_main.h"
#include "vwin_error.h"
#include "vwin_control.h"
#include "machine/lc_util.h"
extern "C" {
#include "memory_debug.h"
void
_v_set_descriptor_set_font(VInfo *info,
		const L_CHAR *desc,
		const LC_WRITING_STYLE *ws,
		int fsize);
}

const short tab_client_margin = 6;


static HWND CreateTabContorl(
		int style, HWND hwnd, int id, VTabView::tab_set *arg){
	HWND ret = ::CreateWindowEx(
		0, 
		WC_TABCONTROL,
		WC_TABCONTROL,
		style,
		0,
		0,
		0,
		0,
		hwnd,
		(HMENU)id,
		theApp->get_instance(),
		NULL);
	for ( int i = 0 ; i < arg->pages ; i++ ) {
		if ( arg->names[i] ) {
			char *cstr=0;
			wchar_t *wstr=0;
			l2native(&cstr, &wstr, arg->names[i]);
			if ( cstr ) {
				TCITEMA tcitem;
				tcitem.pszText = cstr;
				tcitem.mask = TCIF_TEXT;
				SendMessage(ret, TCM_INSERTITEMA, i, (LPARAM)&tcitem);
			}
			else if ( wstr ) {
				TCITEMW tcitem;
				tcitem.pszText = wstr;
				tcitem.mask = TCIF_TEXT;
				SendMessage(ret, TCM_INSERTITEMW, i, (LPARAM)&tcitem);
			}
			if ( cstr )
				d_f_ree(cstr);
			if ( wstr )
				d_f_ree(wstr);
		}
		else {
			TCITEM tcitem;
			tcitem.pszText = TEXT("");
			tcitem.mask = TCIF_TEXT;
			TabCtrl_InsertItem(ret, i, &tcitem);
		}
	}
	return ret;
}

VExError
VTabView::create_do(const VObjectStatus* s, int flags, VObject * parent, void * arg)
{
	int i;
	tab_set *set = (tab_set*)arg;
	n_pages = set->pages;
	sts.value = 0;
	min_width = 80;
	
	DWORD style = WS_CHILD | WS_TABSTOP;// | WS_CLIPSIBLINGS;
	
	if(!s->enabled){
		style |= WS_DISABLED;
	}
	if(s->visible){
		style |= WS_VISIBLE;
	}
	
	/* find container window that will own this button.*/
	VContainerInfo *container_info = VInfo::get_container_info(parent);
	int id = container_info->get_next_control_id();
	HWND hwnd = v_serialized_exec_func(CreateTabContorl, style, container_info->get_hwnd(), id, set);
	VContainerInfo *win_info = new VContainerInfo(this, hwnd, id, 0, 0, 1, 0,
							(WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC));
	info = win_info;
	
	info->add_message_handler(new OnNotify(::value_changed));
	VExError err = parent->add_child_do(this);
	if ( err.code )
		goto end;
	
	creating = 1;
	pages = new VTabPage*[n_pages];
	VObjectStatus cs;
	cs.parent = this;
	cs.attr = VTabPage::tab_page;
	cs.alignh = cs.alignv = VALIGN_FILL;
	cs.padding.w = cs.padding.h = 0;
	for ( i = 0 ; i < n_pages ; i++ ) {
		pages[i] = VTabPage::create(&cs, VSF_PARENT|VSF_ATTR|VSF_ALIGN|VSF_PADDING, &err);
		if ( i || !s->visible )
			v_serialized_exec_sub(ShowWindow, pages[i]->get_info_this()->get_hwnd(), SW_HIDE);
		if ( err.code != V_ER_NO_ERR )
			er_panic("VTabView::create_do");
	}
	creating = 0;
	
end:
	return err;
}

void
VTabView::destroy_do(VObject* parent)
{
	parent->remove_child_do(this);
	delete[] pages;
	if(info){
		v_serialized_exec_sub(::DestroyWindow, info->get_hwnd());
		delete info;
		info = NULL;
	}
	parent->redraw();
}

VTabView::~VTabView()
{
}

VExError
VTabView::get_status(VObjectStatus *s, int flags) const
{
	V_OP_START_EX

	if ( flags & VSF_VALUE ) {
		struct v_tab_view_get_status {
			static int f(HWND hwnd) { return TabCtrl_GetCurSel(hwnd); }
		};
		s->value = v_serialized_exec_func(v_tab_view_get_status::f, info->get_hwnd());
		flags &= ~VSF_VALUE;
	}

	VExError err = VObject::get_status(s,flags);
	win_control_default_get_status(info->get_hwnd(), s, flags, &err);
	V_OP_END
	return err;
};

VExError
VTabView::set_status(const VObjectStatus *s, int flags)
{
	V_OP_START_EX
	VExError err = VObject::set_status(s,flags);
	HWND hwnd = info->get_hwnd();
	win_control_default_set_status(hwnd, s, flags, &err);

	if ( flags & (VSF_FSIZE | VSF_WS) ) {
		_v_set_descriptor_set_font(
			info, sts.descriptor, sts.ws, sts.fsize);
		err.subcode1 &= ~(VSF_FSIZE | VSF_WS);
	}

	if ( flags & (VSF_CALC_MIN | VSF_LAYOUT) && n_pages > 0 ) {
		RECT r;
		GetClientRect(info->get_hwnd(), &r);
		RECT r2 = r;
		TabCtrl_AdjustRect(info->get_hwnd(), FALSE, &r2);
		MapWindowPoints(info->get_hwnd(),
			GetParent(pages[0]->get_info_this()->get_hwnd()),
			(LPPOINT)&r2, 2);
		VSize sh = {r2.left-tab_client_margin, r2.top-tab_client_margin}, tl = {0,0},
			br = {(r.right-r.left)-(r2.right-r2.left)-tab_client_margin*2,
				  (r.bottom-r.top)-(r2.bottom-r2.top)-tab_client_margin*2};

		if ( flags & VSF_CALC_MIN ) {
			for ( VObjectList *list = sts.children ; list ; list = list->next )
				list->object->set_status(0, VSF_CALC_MIN);
			sts.min_size.w = min_width;
			sts.min_size.h = 24;
			for ( int i = 0 ; i < n_pages ; i++ ) {
				VLayout layout;
				layout.set_margin(tl, br);
				layout.layout_in_frame(this, true, i);
				if ( sts.min_size.w < layout.parent_min_size().w )
					sts.min_size.w = layout.parent_min_size().w;
				if ( sts.min_size.h < layout.parent_min_size().h )
					sts.min_size.h = layout.parent_min_size().h;
			}
			err.subcode1 &= ~VSF_CALC_MIN;
		}
		if ( flags & VSF_LAYOUT ) {
			VLayout layout;
			if ( n_pages > 0 ) {

				for ( int i = 0 ; i < n_pages ; i++ ) {
					VLayout layout;
					layout.set_margin(tl, br);
					layout.layout_in_frame(this, false, i);
					layout.shift_children(sh);
					layout.do_layout(this);
				}
			}
			err.subcode1 &= ~VSF_LAYOUT;
		}
	}

	if ( flags & VSF_VISIBLE ) {
		if ( s->visible != (::IsWindowVisible(hwnd)!=FALSE) ){
			if ( s->visible ) {
				v_serialized_exec_sub(ShowWindow, hwnd, SW_SHOW);
				v_serialized_exec_sub(ShowWindow,
						pages[sts.value]->get_info_this()->get_hwnd(), SW_SHOW);
			}
			else {
				v_serialized_exec_sub(ShowWindow, hwnd, SW_HIDE);
				v_serialized_exec_sub(ShowWindow,
						pages[sts.value]->get_info_this()->get_hwnd(), SW_HIDE);
			}
		}
		err.subcode1 &= ~VSF_VISIBLE;
	}

	V_OP_END

	if ( flags & ( VSF_HOMOGEN | VSF_SPACING | VSF_ALIGN | VSF_PADDING | VSF_VISIBLE ) )
		VLayout::mark(this);

	return err;
}

VExError
VTabView::add_child_do(VObject*child)
{
	return initial_VExError(V_ER_NO_ERR,0,0);
}

void
VTabView::remove_child_do(VObject* child)
{
	// do nothing
}

void
VTabView::child_status_changed(VObject* child, VInfo* info)
{
	// do nothing - object is marked when status is changed
}

void
VTabView::value_changed()
{
	if ( IsWindowVisible(info->get_hwnd()) ) {
		int v = TabCtrl_GetCurSel(info->get_hwnd());
		if ( sts.value != v ) {
			ShowWindow(pages[sts.value]->get_info_this()->get_hwnd(), SW_HIDE);
			ShowWindow(pages[v]->get_info_this()->get_hwnd(), SW_SHOW);
			SetFocus(info->get_hwnd());
			sts.value = v;
			VObject::value_changed();
		}
	}
}

void
VTabView::redraw(VRect* rect) const
{
	if ( ! info )
		return;
	_V_OP_START_VOID
	win_redraw(info->get_hwnd(), rect);
	V_OP_END
}

VTabPage*
VTabView::get_page(int n)
{
	VTabPage *ret;
	_V_OP_START(0)
	if ( n < 0 || n >= n_pages )
		ret = 0;
	else
		ret = pages[n];
	V_OP_END
	return ret;
}
