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

	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 "vwin_control.h"
#include "v/VAlignView.h"
#include "v/VLayout.h"
#include "VApplication.h"
#include "vwin_error.h"

VInfo* make_TabPageDialog(
	const VObjectStatus *s, VObject* obj, VContainerInfo *parent_info, int id);


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

VAlignView::~VAlignView()
{
}

VExError
VAlignView::get_status(VObjectStatus *s, int flags) const
{
	V_OP_START_EX
	VExError err = VObject::get_status(s,flags);
	win_control_default_get_status(info->get_hwnd(), s, flags, &err);
	V_OP_END
	return err;
};

VExError
VAlignView::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_CALC_MIN ) {
		for ( VObjectList *list = sts.children ; list ; list = list->next ) {
			list->object->set_status(0, VSF_CALC_MIN);
		}
		VLayout layout;
		layout.layout_in_align_view(this, get_type()==VVAlignView::object_type, true);
		sts.min_size = layout.parent_min_size();
		err.subcode1 &= ~VSF_CALC_MIN;
	}
	if ( flags & VSF_LAYOUT ) {
		VLayout layout;
		layout.layout_in_align_view(this, get_type()==VVAlignView::object_type);
		layout.do_layout(this);
		err.subcode1 &= ~VSF_LAYOUT;
	}

	if ( flags & VSF_VISIBLE ) {
		if ( s->visible != (::IsWindowVisible(hwnd)!=FALSE) ){
			v_serialized_exec_sub(ShowWindow, hwnd, s->visible ? SW_SHOW : 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 VAlignView::add_child_do(VObject* child)
{
	return initial_VExError(V_ER_NO_ERR,0,0);
}

void
VAlignView::remove_child_do(VObject* child)
{

}

VExError
VAlignView::reorder_child(VObject* child, int order)
{
	VObjectList *c, *p = 0, *k;
	int i = 0;
	for ( c = sts.children ; c && c->object != child ; p = c, c = c->next ) { i++; }
	VExError err = initial_VExError(V_ER_NO_ERR, 0, 0);
	V_OP_START_EX
	if ( c == 0 )
		return initial_VExError(V_ER_NOT_FOUND, 0, 0);
	if ( i == order )
		return initial_VExError(V_ER_NO_ERR, 0, 0);
	p->next = c->next;
	k = c;
	
	i = 0;
	p = 0;
	c = sts.children;
	while ( i++ != order && c ) {
			p = c;
			c = c->next;
	}
	if ( p ) {
		k->next = p->next;
		p->next = k;
	}
	else {
		k->next = sts.children;
		sts.children = k;
	}
	V_OP_END
	VLayout::mark(this);
	return err;
}

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

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

class AlignViewRegister{
public:
	
	AlignViewRegister(){
		WNDCLASSEX wc;
		wc.cbSize = sizeof(WNDCLASSEX);
		wc.style = CS_PARENTDC;
		wc.lpfnWndProc = VContainerInfo::WndProc;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = sizeof(DWORD);
		wc.hInstance = ::GetModuleHandle(NULL);
		wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
		wc.hCursor = LoadCursor(NULL,IDC_ARROW);
		wc.hbrBackground = NULL;
		wc.lpszMenuName = NULL;
		wc.lpszClassName = "vobj_align_view";
		wc.hIconSm = NULL;
		
		if(!::RegisterClassEx(&wc)){
			VWinError();
			er_panic("AlignViewRegister");
		}
	}
}align_view_register;

static HWND CreateAlignWindow(int style, VContainerInfo *info, int id){
	return ::CreateWindowEx(
		WS_EX_CONTROLPARENT,
		"vobj_align_view",
		"align_view",
		style,
		0,
		0,
		0,
		0,
		info->get_hwnd(),
		(HMENU)id,
		theApp->get_instance(),
		NULL);
}

VInfo* make_AlignView(
	const VObjectStatus *s, VObject* obj, VContainerInfo *parent_info, int id, DWORD st)
{
	DWORD style=WS_CHILD | st;
	if(!s->enabled)
		style |= WS_DISABLED;
	if(s->visible)
		style |= WS_VISIBLE;
	
	HWND hwnd;
	hwnd = v_serialized_exec_func(CreateAlignWindow, style, parent_info, 0);
	VContainerInfo *info = new VContainerInfo(obj, hwnd, id, 1, 0, 0,1);
	if(info->get_hwnd()==NULL){
		VWinError();
		er_panic("make_AlignView");
	}

	return info;
}


VExError 
VHAlignView::create_do(const VObjectStatus* s, int flags, VObject *parent, void * arg)
{
	info = make_AlignView(s,this,VInfo::get_container_info(parent),s->id, 0);
	return parent->add_child_do(this);
}

VExError
VVAlignView::create_do(const VObjectStatus* s, int flags, VObject *parent, void * arg)
{
	if ( (flags & VSF_ATTR) && s->attr == tab_page )
		info = make_TabPageDialog(s,this,VInfo::get_container_info(parent),s->id);
	else
		info = make_AlignView(s,this,VInfo::get_container_info(parent),s->id, 0);
	return parent->add_child_do(this);
}
