/*
	GWEN
	Copyright (c) 2010 Facepunch Studios
	See license in Gwen.h
*/

#include "Gwen/Controls/TreeNode.h"
#include "Gwen/Controls/TreeControl.h"
#include "Gwen/Utility.h"

using namespace Gwen;
using namespace Gwen::Controls;

class OpenToggleButton : public Button
{
	GWEN_CONTROL_INLINE(OpenToggleButton, Button)
	{
		SetIsToggle(true);
		SetTabable(false);
	}

	virtual void RenderFocus(Skin::Base* /*skin*/) {}

	virtual void Render(Skin::Base* skin)
	{
		skin->DrawTreeButton(this, GetToggleState());
	}
};

const int TreeIndentation = 14;
const int BranchLength = 16;

GWEN_CONTROL_CONSTRUCTOR(TreeNode)
{
	m_TreeControl = NULL;

	m_ToggleButton = new OpenToggleButton(this);
	m_ToggleButton->SetBounds(2, 2, 13, 13);
	m_ToggleButton->onToggle.Add(this, &TreeNode::OnToggleButtonPress);

	m_Title = new Button(this);
	m_Title->Dock(Pos::Top);
	m_Title->SetMargin(Margin(BranchLength, 0, 0, 0));
	m_Title->SetAlignment(Pos::Left | Pos::CenterV);
	m_Title->SetShouldDrawBackground(false);
	m_Title->onDoubleClick.Add(this, &TreeNode::OnDoubleClickName);
	m_Title->onDown.Add(this, &TreeNode::OnClickName);
	m_Title->SetHeight(16);

	m_InnerPanel = new Base(this);
	m_InnerPanel->Dock(Pos::Top);
	m_InnerPanel->SetHeight(100);
	m_InnerPanel->SetMargin(Margin(TreeIndentation, 1, 0, 0));
	m_InnerPanel->Hide();

	m_bRoot = false;
	m_bSelected = false;
	m_bSelectable = true;
}

void TreeNode::Render(Skin::Base* skin)
{
	int iBottom = 0;
	if (m_InnerPanel->Children.size() > 0)
	{
		iBottom = m_InnerPanel->Children.back()->Y() + m_InnerPanel->Y();
	}

	skin->DrawTreeNode(this, m_InnerPanel->Visible(), IsSelected(), m_Title->Height(), m_Title->TextRight(), m_ToggleButton->Y() + m_ToggleButton->Height() * 0.5, iBottom, GetParent() == m_TreeControl);
}

TreeNode* TreeNode::AddNode(const UnicodeString& strLabel)
{
	//	int sz = sizeof(TreeNode);
	TreeNode* node = new TreeNode(this);
	node->SetText(strLabel);
	node->Dock(Pos::Top);
	node->SetRoot(this->DynamicCastTreeControl() != NULL);
	node->SetTreeControl(m_TreeControl);

	if (m_TreeControl)
	{
		m_TreeControl->OnNodeAdded(node);
	}

	return node;
}

TreeNode* TreeNode::AddNode(const String& strLabel)
{
	return AddNode(Utility::StringToUnicode(strLabel));
}

void TreeNode::Layout(Skin::Base* skin)
{
	if (m_ToggleButton)
	{
		if (m_InnerPanel->NumChildren() == 0)
		{
			m_ToggleButton->Hide();
			m_ToggleButton->SetToggleState(false);
			m_InnerPanel->Hide();
		}
		else
		{
			m_ToggleButton->Show();
			m_InnerPanel->SizeToChildren(false, true);
		}
	}

	BaseClass::Layout(skin);
}
//too many calls to PostLayout...
//int numCalls = 0xfd;
void TreeNode::PostLayout(Skin::Base* /*skin*/)
{
	//int bla = numCalls&0xffff;
	//if (bla==0)
	//	printf("TreeNode::PostLayout numCalls = %d\n", numCalls);

	//numCalls++;
	if (SizeToChildren(false, true))
	{
		InvalidateParent();
	}
}

void TreeNode::SetText(const UnicodeString& text) { m_Title->SetText(text); };
void TreeNode::SetText(const String& text) { m_Title->SetText(text); };

UnicodeString TreeNode::GetText() const
{
	UnicodeString bla = m_Title->GetText();
	return bla;
}

void TreeNode::Open()
{
	m_InnerPanel->Show();
	if (m_ToggleButton) m_ToggleButton->SetToggleState(true);
	Invalidate();
	if (m_TreeControl)
		m_TreeControl->ForceUpdateScrollBars();
}

void TreeNode::Close()
{
	m_InnerPanel->Hide();
	if (m_ToggleButton) m_ToggleButton->SetToggleState(false);

	Invalidate();
	if (m_TreeControl)
		m_TreeControl->ForceUpdateScrollBars();
}

void TreeNode::ExpandAll()
{
	Open();

	Base::List& children = m_InnerPanel->GetChildren();
	for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter)
	{
		TreeNode* pChild = (*iter)->DynamicCastTreeNode();
		if (!pChild) continue;

		pChild->ExpandAll();
	}
}

Button* TreeNode::GetButton() { return m_Title; }

void TreeNode::OnToggleButtonPress(Base* /*control*/)
{
	if (m_ToggleButton->GetToggleState())
	{
		Open();
	}
	else
	{
		Close();
	}
}

void TreeNode::OnDoubleClickName(Base* /*control*/)
{
	if (!m_ToggleButton->Visible()) return;

	m_ToggleButton->Toggle();
}

void TreeNode::OnClickName(Base* /*control*/)
{
	onNamePress.Call(this);

	SetSelected(!IsSelected());
}

void TreeNode::SetSelected(bool b)
{
	if (!m_bSelectable) return;
	if (m_bSelected == b) return;

	m_bSelected = b;

	onSelectChange.Call(this);

	if (m_bSelected)
		onSelect.Call(this);
	else
		onUnselect.Call(this);
}

void TreeNode::DeselectAll()
{
	m_bSelected = false;

	Base::List& children = m_InnerPanel->GetChildren();
	for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter)
	{
		TreeNode* pChild = (*iter)->DynamicCastTreeNode();
		if (!pChild) continue;

		pChild->DeselectAll();
	}
}

void TreeNode::iterate(int action, int* curIndex, int* targetIndex)
{
	Gwen::String name = Gwen::Utility::UnicodeToString(m_Title->GetText());

	//	int actualIndex = curIndex? *curIndex : -1;
	//printf("iterated over item %d with name = %s\n", actualIndex, name.c_str());

	if (action == ITERATE_ACTION_SELECT)
	{
		if (curIndex && targetIndex)
		{
			if ((*curIndex) == (*targetIndex))
			{
				SetSelected(true);

				*targetIndex = -1;
			}
		}
	}

	if (IsSelected())
	{
		//printf("current selected: name = %s\n", name.c_str());
		switch (action)
		{
			case ITERATE_ACTION_DESELECT_INDEX:
			{
				if (targetIndex && curIndex)
				{
					if (*targetIndex == *curIndex)
						SetSelected(false);
				}
				break;
			}
			case ITERATE_ACTION_FIND_SELECTED_INDEX:
			{
				if (targetIndex && curIndex)
				{
					*targetIndex = *curIndex;
				}
				break;
			}
			case ITERATE_ACTION_OPEN:
			{
				Open();

				break;
			}
			case ITERATE_ACTION_CLOSE:
			{
				//either close or select parent
				if (this->GetChildren().size())
				{
					if (m_ToggleButton && m_ToggleButton->GetToggleState())
					{
						Close();
					}
					else
					{
						TreeNode* pChild = (GetParent())->DynamicCastTreeNode();
						TreeControl* pChild2 = (GetParent())->DynamicCastTreeControl();
						if (pChild && !pChild2)
						{
							SetSelected(false);
							pChild->SetSelected(true);
						}
					}
				}
				else
				{
					TreeNode* pChild = (GetParent())->DynamicCastTreeNode();
					TreeControl* pChild2 = (GetParent())->DynamicCastTreeControl();
					if (pChild && !pChild2)
					{
						SetSelected(false);
						pChild->SetSelected(true);
					}
				}

				break;
			}
			default:
			{
			}
		};
	}

	if (curIndex)
		(*curIndex)++;

	bool needsRecursion = true;

	if (action == ITERATE_ACTION_FIND_SELECTED_INDEX || action == ITERATE_ACTION_SELECT || action == ITERATE_ACTION_DESELECT_INDEX)
	{
		if (m_ToggleButton && !m_ToggleButton->GetToggleState())
		{
			needsRecursion = false;
		}
	}

	if (needsRecursion)
	{
		Base::List& children = m_InnerPanel->GetChildren();
		for (Base::List::iterator iter = children.begin(); iter != children.end(); ++iter)
		{
			TreeNode* pChild = (*iter)->DynamicCastTreeNode();
			if (!pChild)
				continue;

			pChild->iterate(action, curIndex, targetIndex);
		}
	}
}