#include "stdafx.h"
#include "WidgetObjectList.h"

#include "FormMain.h"
#include "TreeUtil.h"

#include <QMessageBox>

#include <Qt5Utility/QGui.h>



WidgetObjectList::WidgetObjectList(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);
}

WidgetObjectList::~WidgetObjectList()
{

}

void WidgetObjectList::setMainForm(FormMain* mainFrm_)
{
	mainFrm = mainFrm_;
}

void WidgetObjectList::RegisterContextMenu(void)
{
	QList<QAction*> actions;
	actions
		<< ui.actionSelObjectVisible
		<< ui.actionSelObjectVertexOnlyMode
		<< ui.actionSelObjectDelete
		<< ui.actionSelObjectReload
		<< ui.actionSelObjectFlipFace
		<< ui.actionSelObjectFlipNormal
		<< ui.actionSelObjectResetNormal
		<< ui.actionSelObjectOpenDir
		<< ui.actionActionSelObjectShowOnlyOnce
		<< ui.actionSelObjectTriangulate
		<< ui.actionTreeCollapseAll
		<< ui.actionTreeExpandAll;

	QTreeWidget* obj_tree = ui.treeObjects;

	obj_tree->setContextMenuPolicy(Qt::ActionsContextMenu);
	obj_tree->addActions(actions);
}

void WidgetObjectList::focusList(void)
{
	ui.treeObjects->setFocus();
}

void WidgetObjectList::OnSelectedObjectChanged(int sel_obj, int sel_mesh)
{
	QTreeWidgetItem* on = ui.treeObjects->topLevelItem(sel_obj);

	if (sel_mesh == -1)
	{
		ui.treeObjects->setCurrentItem(on);
	}
	else
	{
		QTreeWidgetItem* mn = on->child(sel_mesh);
		ui.treeObjects->setCurrentItem(mn);
	}
}

void WidgetObjectList::AddSelectObjectIdx(int step)
{
	QTreeWidget* obj_tree = ui.treeObjects;

	int num_obj = obj_tree->topLevelItemCount();
	if (num_obj == 0)
		return;

	QTreeWidgetItem * i = obj_tree->currentItem();
	int idx = obj_tree->indexOfTopLevelItem(i);
	idx += step;

	if (0 > idx)
		idx = num_obj - 1;
	else if (idx >= num_obj)
		idx = 0;

	QTreeWidgetItem * j = obj_tree->topLevelItem(idx);
	obj_tree->setCurrentItem(j);
}

void WidgetObjectList::FlipVisibleSelectedObject()
{
	QTreeWidget* obj_tree = ui.treeObjects;
	QTreeWidgetItem * item = obj_tree->currentItem();
	if (item == NULL)
		return;

	item->setCheckState(1, FilpState(item->checkState(1)));
}

Qt::CheckState WidgetObjectList::FilpState(Qt::CheckState state) const
{
	if(state == Qt::Checked)
		return Qt::Unchecked;
	else
		return Qt::Checked;
}

void WidgetObjectList::SetPrimayrSelectObjectToScene(void)
{
	Selection3D& sels = mainFrm->m_Scene.m_Sels;

	QTreeWidget* tree = ui.treeObjects;

	QTreeWidgetItem* sel_node = tree->currentItem();
	if (sel_node == NULL)
		return;

	QTreeWidgetItem* on = sel_node->parent();
	if (on == NULL)
	{
		int obj_idx = tree->indexOfTopLevelItem(sel_node);
		sels.SelectObject(obj_idx);
	}
	else
	{
		int obj_idx = tree->indexOfTopLevelItem(on);
		int mb_idx = on->indexOfChild(sel_node);
		sels.SelectMBuf(obj_idx, mb_idx);
	}

	UpdateContextmenuState();
}

void WidgetObjectList::on_treeObjects_itemChanged(QTreeWidgetItem * item, int column)
{
	if (column != 1)
		return;

	QTreeWidget* obj_tree = ui.treeObjects;

	QTreeWidgetItem* t = item->parent();
	bool checked = (item->checkState(1) == Qt::Checked);
	if (t == NULL)
	{
		int sel_idx = obj_tree->indexOfTopLevelItem(item);
		GeomObject& obj = mainFrm->m_Scene.m_Objects[sel_idx];
		obj.m_Visible = checked;
	}
	else
	{
		int sel_idx = obj_tree->indexOfTopLevelItem(t);
		int midx = t->indexOfChild(item);

		GeomObject& obj = mainFrm->m_Scene.m_Objects[sel_idx];
		MeshBuf& mb = obj.m_MeshAry[midx];
		mb.m_Visible = checked;
	}

	mainFrm->updateView_All();
}

QTreeWidget* WidgetObjectList::GetTree(void)
{
	return ui.treeObjects;
}

void WidgetObjectList::applyConfig(void)
{
	ui.checkShowOnlySelect->setChecked(mainFrm->m_View3d.m_Config.m_ShowOnlySelect);
}

void WidgetObjectList::on_treeObjects_currentItemChanged(QTreeWidgetItem * current, QTreeWidgetItem * previous)
{
	mainFrm->RefreshObjectSelectState();
}

void WidgetObjectList::on_checkShowOnlySelect_toggled(bool checked)
{
	mainFrm->m_View3d.m_Config.m_ShowOnlySelect = checked;
	mainFrm->updateView_All();
}

void WidgetObjectList::on_buttonClearAllGeoms_clicked()
{
	mainFrm->ClearAllObjects();
}

void WidgetObjectList::on_pushDeleteSelectedObject_clicked()
{
	mainFrm->DeleteSelectedObject();
}


void WidgetObjectList::on_actionTreeCollapseAll_triggered()
{
	TreeUtil::SetAllTopExpand(GetTree(), false);
}

void WidgetObjectList::on_actionTreeExpandAll_triggered()
{
	TreeUtil::SetAllTopExpand(GetTree(), true);
}

void WidgetObjectList::on_actionSelObjectVisible_triggered()
{
	FlipVisibleSelectedObject();
}

void WidgetObjectList::on_actionSelObjectVertexOnlyMode_triggered()
{
	GeomObject* obj = mainFrm->m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	obj->m_VertexOnlyMode = !obj->m_VertexOnlyMode;

	ui.actionSelObjectVertexOnlyMode->setChecked(obj->m_VertexOnlyMode);

	mainFrm->updateView_All();
}

void WidgetObjectList::UpdateContextmenuState(void)
{
	GeomObject* obj = mainFrm->m_Scene.GetPrimaryObject();
	MeshBuf* mbuf = mainFrm->m_Scene.GetPrimaryMeshbuf();

	if (mbuf != NULL)
	{
		ui.actionSelObjectVisible->setChecked(mbuf->IsVisible());
	}
	else if (obj != NULL)
	{
		ui.actionSelObjectVisible->setChecked(obj->m_Visible);
	}

	if (obj != NULL)
		ui.actionSelObjectVertexOnlyMode->setChecked(obj->m_VertexOnlyMode);
}

void WidgetObjectList::on_actionSelObjectTriangulate_triggered()
{
	MeshBuf* mbuf = mainFrm->m_Scene.GetPrimaryMeshbuf();
	if (mbuf == NULL)
		return;

	mbuf->Triangulate();

	mainFrm->m_View3d.ReleaseAllRenderBuffer();

	RebuildObjectList();

	mainFrm->updateView_All();
}

void WidgetObjectList::on_actionSelObjectResetNormal_triggered()
{
	mainFrm->m_Scene.RebuildCurselNormal();

	mainFrm->RebuildAllGLBuf();
}

void WidgetObjectList::on_actionSelObjectReload_triggered()
{
	reloadSelObject();
}

void WidgetObjectList::reloadSelObject(void)
{
	SceneMain& scene = mainFrm->m_Scene;

	GeomObject* obj = scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (!obj->IsFileObject())
	{
		QMessageBox::information(mainFrm, "", "IsNotFileObject");
		return;
	}

	scene.ReloadObject(obj);

	RebuildObjectList();

	mainFrm->m_View3d.ClearRenderMap();
	mainFrm->updateView_All();
}

void WidgetObjectList::on_actionSelObjectOpenDir_triggered()
{
	GeomObject* obj = mainFrm->m_Scene.GetPrimaryObject();
	if (obj == NULL)
		return;

	if (!obj->IsFileObject())
		return;

	QString path = QString::fromLocal8Bit(obj->m_FilePath.c_str());
	QString p2 = QDir::toNativeSeparators(path);
	QGui::ShowExplorerFileSel(p2);
}

void WidgetObjectList::on_actionSelObjectFlipNormal_triggered()
{
	mainFrm->m_Scene.FlipCurselFace(true);

	mainFrm->RebuildAllGLBuf();
}

void WidgetObjectList::on_actionSelObjectFlipFace_triggered()
{
	mainFrm->m_Scene.FlipCurselFace(false);

	mainFrm->RebuildAllGLBuf();
}

void WidgetObjectList::on_actionActionSelObjectShowOnlyOnce_triggered()
{
	mainFrm->ShowObjectOnlySelected();
}

void WidgetObjectList::on_actionSelObjectDelete_triggered()
{
	mainFrm->DeleteSelectedObject();
}

void WidgetObjectList::ResizeObjectTreeColumns(void)
{
	QTreeWidget* t = GetTree();

	t->setVisible(false);
	t->resizeColumnToContents(0);
	t->resizeColumnToContents(1);
	t->resizeColumnToContents(2);
	t->resizeColumnToContents(3);
	t->setVisible(true);
}

void WidgetObjectList::InitObjectListHeader(void)
{
	QTreeWidget* obj_tree = GetTree();

	QStringList qs;
	qs << "Name" << "Visible" << "Verts" << "Faces";
	
	obj_tree->setColumnCount(4);

	obj_tree->setHeaderLabels(qs);
}

QTreeWidgetItem* WidgetObjectList::CreateMeshBufNode(const geom::GeomObject& obj, const MeshBuf& mbuf, int idx) const
{
	QTreeWidgetItem* n = new QTreeWidgetItem;

	QString name;
	if (mbuf.m_Name.empty())
		name = QString::fromLocal8Bit(obj.m_Name.c_str()) + QString::number(idx);
	else
		name = QString::fromLocal8Bit(mbuf.m_Name.c_str());

	n->setText(0, name);
	n->setCheckState(1, mbuf.m_Visible ? Qt::Checked : Qt::Unchecked);
	n->setText(2, QString::number(mbuf.GetNumVerts()));
	n->setText(3, QString::number(mbuf.GetNumFaces()));

	return n;
}

void WidgetObjectList::PushbackTreeNode(QTreeWidget* tree, QTreeWidgetItem *node)
{
	int next_idx = tree->topLevelItemCount();
	tree->insertTopLevelItem(next_idx, node);
}

void WidgetObjectList::InitTreConfig(void)
{
	QTreeWidget* obj_tree = GetTree();

	obj_tree->setSelectionBehavior(QAbstractItemView::SelectRows);
	obj_tree->setSelectionMode(QAbstractItemView::SingleSelection);
	obj_tree->setEditTriggers(QAbstractItemView::NoEditTriggers);
}

void WidgetObjectList::RebuildObjectList(void)
{
	QTreeWidget* obj_tree = GetTree();

	obj_tree->setCurrentItem(NULL);
	obj_tree->blockSignals(true);

	obj_tree->clear();

	InitTreConfig();
	InitObjectListHeader();

	addAllObjectsToTree();

	SetPrimayrSelectObjectFromScene();

	obj_tree->blockSignals(false);

	initUVViewOnUpdateList();

	ResizeObjectTreeColumns();
}

void WidgetObjectList::addAllObjectsToTree(void)
{
	QTreeWidget* obj_tree = ui.treeObjects;

	for (const geom::GeomObject& obj : mainFrm->m_Scene.m_Objects)
	{
		QTreeWidgetItem* n = CreateObjectTreeNode(obj);
		PushbackTreeNode(obj_tree, n);
		n->setExpanded(false);
	}
}

void WidgetObjectList::OnDoneAddGeom(void)
{
	QTreeWidget* obj_tree = GetTree();

	obj_tree->setCurrentItem(NULL);
	obj_tree->blockSignals(true);

	const GeomObject& obj = mainFrm->m_Scene.m_Objects.back();
	QTreeWidgetItem* n = CreateObjectTreeNode(obj);
	PushbackTreeNode(obj_tree, n);
	n->setExpanded(false);

	SetPrimayrSelectObjectFromScene();

	obj_tree->blockSignals(false);

	initUVViewOnUpdateList();

	ResizeObjectTreeColumns();
}

QTreeWidgetItem* WidgetObjectList::CreateObjectTreeNode(const geom::GeomObject& obj) const
{
	QTreeWidgetItem* n = new QTreeWidgetItem;

	n->setText(0, QString::fromLocal8Bit(obj.m_Name.c_str()));
	n->setCheckState(1, obj.m_Visible ? Qt::Checked : Qt::Unchecked);
	n->setText(2, QString::number(obj.GetNumTotalVerts()));
	n->setText(3, QString::number(obj.GetNumTotalFaces()));

	int idx = 0;
	for (const MeshBuf& mbuf : obj.m_MeshAry)
	{
		n->addChild(CreateMeshBufNode(obj, mbuf, idx++));
	}

	n->setExpanded(false);

	return n;
}

void WidgetObjectList::SyncViewMark(void)
{
	// TODO: 階層をリビルドせずにマークだけ更新
	RebuildObjectList();
}

void WidgetObjectList::ClearTree(void)
{
	RebuildObjectList();
}


// シーンオブジェクトの選択情報をGUIに反映
void WidgetObjectList::SetPrimayrSelectObjectFromScene(void)
{
	QTreeWidget* obj_tree = ui.treeObjects;

	Selection3D& sels = mainFrm->m_Scene.m_Sels;
	if (!sels.IsObjectSelected())
		return;

	int sel_idx = sels.GetSelObjectIdx();

	QTreeWidgetItem* on = obj_tree->topLevelItem(sel_idx);
	if (on == NULL)
		return;

	if (sels.IsMBufSelected())
	{
		QTreeWidgetItem* mn = on->child(sels.GetMBufIdx());
		obj_tree->setCurrentItem(mn);
	}
	else
	{
		obj_tree->setCurrentItem(on);
	}
}

void WidgetObjectList::initUVViewOnUpdateList(void)
{
	QTreeWidget* obj_tree = GetTree();

	if (obj_tree->currentItem() == NULL)
	{
		if (!mainFrm->m_Scene.m_Objects.empty())
		{
			QTreeWidgetItem* ti = obj_tree->topLevelItem(0);
			obj_tree->setCurrentItem(ti);
			if (mainFrm->IsAutUVFit())
				mainFrm->m_View2d.FitView();
		}
	}
}

int WidgetObjectList::getSelObjIdx()
{
	QTreeWidget* obj_tree = GetTree();
	QTreeWidgetItem* ti = obj_tree->currentItem();
	if (ti == NULL)
		return -1;

	QTreeWidgetItem* pn = ti->parent();

	// 2層構造であるという前提で
	// 1層目がオブジェクトノード
	// 2層目がメッシュノード
	if (pn == NULL)
		return obj_tree->indexOfTopLevelItem(ti);
	else
		return obj_tree->indexOfTopLevelItem(pn);
}

int WidgetObjectList::getSelObjIdxWhenSelObjNode()
{
	QTreeWidget* obj_tree = GetTree();
	QTreeWidgetItem* ti = obj_tree->currentItem();
	return obj_tree->indexOfTopLevelItem(ti);
}

void WidgetObjectList::removeObject(int objectIdx)
{
	QTreeWidget* obj_tree = GetTree();
	obj_tree->setCurrentItem(NULL);
	obj_tree->takeTopLevelItem(objectIdx);

	ResizeObjectTreeColumns();
}

void WidgetObjectList::on_buttonReloadSel_clicked()
{
	reloadSelObject();
}
