#include "CWorldEditor.h"
#include "resource.h"
#include "CMainEditor.h"
#include "COSLabel.h"
#include "COSText.h"

IMPLEMENT_DYNAMIC(CWorldEditor, CDialog)

BEGIN_MESSAGE_MAP(CWorldEditor, CDialog)
	ON_COMMAND(IDOK, &CWorldEditor::OnEnterKey)
	ON_WM_SHOWWINDOW()
	ON_WM_SIZE()
	ON_COMMAND(ID_ADD_POS, &CWorldEditor::OnAddPos)
	ON_COMMAND(ID_RENAME_POS, &CWorldEditor::OnRenamePos)
	ON_COMMAND(ID_EDIT_POSINFO, &CWorldEditor::OnEditPosinfo)
	ON_COMMAND(ID_COPY_POS, &CWorldEditor::OnCopyPos)
	ON_COMMAND(ID_PASTE_POS, &CWorldEditor::OnPastePos)
	ON_COMMAND(ID_CUT_POS, &CWorldEditor::OnCutPos)
	ON_COMMAND(ID_DELETE_POS, &CWorldEditor::OnDeletePos)
	ON_COMMAND(ID_ADD_LABEL, &CWorldEditor::OnAddLabel)
	ON_COMMAND(ID_RENAME_LABEL, &CWorldEditor::OnRenameLabel)
	ON_COMMAND(ID_DELETE_LABEL, &CWorldEditor::OnDeleteLabel)
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_POSLIST, &CWorldEditor::OnTvnSelchangedTreePoslist)
END_MESSAGE_MAP()

CWorldEditor::CWorldEditor(CWnd* pParent)
	: CDialog(IDD_CWORLDEDITOR, pParent)
{
}

CWorldEditor::~CWorldEditor()
{
}
//递归添加
void CWorldEditor_UpdateContext_TreeAddItem(std::unordered_map<int, MyWorldSet>* worldsetList, CMyTreeCtrl* treeCtrl, HTREEITEM item, tinyxml2::XMLElement* xmlElement, int* idInc)
{
	if (xmlElement == nullptr)
		return;
	//跳过设定标签
	if (strcmp(xmlElement->Name(), "Pos") == 0)//pos
	{
		std::vector<wchar_t> wchar_buff;
		MyWorldSet ws;
		//取地点名称
		GBKToUTF16(xmlElement->Attribute("Name"), &wchar_buff);
		ws.name = wchar_buff.data();
		//取地点描述
		GBKToUTF16(xmlElement->Attribute("Info"), &wchar_buff);
		//给字符串变量补上\r符
		ws.info = StrAddLr(wchar_buff.data());
		//遍历设定实现表
		for (auto p = xmlElement->FirstChildElement(); p != nullptr; p = p->NextSiblingElement())
		{
			//如果不是设定标签，则跳过
			if (strcmp(p->Name(), "Set") != 0)
				continue;
			MyLabelXML label;
			GBKToUTF16(p->Attribute("Name"), &wchar_buff);
			label.name = wchar_buff.data();
			ws.labelMap.insert(std::make_pair(label.name.GetString(), label));
		}
		//插入节点
		HTREEITEM childItem = treeCtrl->InsertItem(ws.name.GetString(), item);
		int& id = *idInc;
		treeCtrl->SetItemData(childItem, id);
		worldsetList->insert(std::make_pair(id, ws));
		id++;

		//遍历子节点
		CWorldEditor_UpdateContext_TreeAddItem(worldsetList, treeCtrl, childItem, xmlElement->FirstChildElement(), idInc);
	}
	//遍历兄弟节点
	CWorldEditor_UpdateContext_TreeAddItem(worldsetList, treeCtrl, item, xmlElement->NextSiblingElement(), idInc);
}

void CWorldEditor::UpdateContext()
{
	//从数据库获取xml
	auto mainEditor = (CMainEditor*)pMainEditor;
	std::vector<char> gbk_buff;
	UTF16ToGBK(mainEditor->GetDBWorldSet().GetString(), &gbk_buff);
	tinyxml2::XMLDocument xmlDoc;
	xmlDoc.Parse(gbk_buff.data());
	tree_posList.DeleteAllItems();
	//重新添加
	int id = 0;
	worldsetList.clear();
	CWorldEditor_UpdateContext_TreeAddItem(&worldsetList, &tree_posList, TVI_ROOT, xmlDoc.RootElement(), &id);
}

BOOL CWorldEditor::PreTranslateMessage(MSG* pMsg)
{
	HOTKEYPROC;
}

void CWorldEditor::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	static_posList = (CStatic*)GetDlgItem(IDC_STATIC_POSLIST);
	DDX_Control(pDX, IDC_TREE_POSLIST, tree_posList);
	static_linkView = (CStatic*)GetDlgItem(IDC_STATIC_LINKVIEW);
	static_linkView_draw = (CStatic*)GetDlgItem(IDC_STATIC_LINKVIEW_DRAW);
	static_posInfo = (CStatic*)GetDlgItem(IDC_STATIC_POSINFO);
	DDX_Control(pDX, IDC_EDIT_POSINFO, edit_posInfo);
	static_set = (CStatic*)GetDlgItem(IDC_STATIC_SET);
	DDX_Control(pDX, IDC_LIST_SET, listbox_set);
}

BOOL CWorldEditor::OnInitDialog()
{
	CDialog::OnInitDialog();
	//载入快捷键
	LOADHOTKEY(IDR_ACC_WORLDEDITOR);
	//设置应用程序图标
	auto hIcon = AfxGetApp()->LoadIcon(IDI_APPICON_TABLE);
	SetIcon(hIcon, true);
	//设置控件tree_posList
	tree_posList.SetMenu(IDR_CWORLDEDITOR_RMENU, IDR_CWORLDEDITOR_RMENU_NOSEL);
	auto style = tree_posList.GetStyle(); 
	style |= TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;
	tree_posList.ModifyStyle(0, style);
	//设置控件edit_posInfo
	edit_posInfo.SetReadOnly();
	//设置控件listbox_set
	listbox_set.SetMenu(IDR_CMCPREP_RMENU, IDR_CMCPREP_RMENU_NOSEL);
	return 0;
}

void CWorldEditor::OnCancel()
{
	ShowWindow(SW_HIDE);
}

void CWorldEditor::OnEnterKey()
{
}

void CWorldEditor::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CDialog::OnShowWindow(bShow, nStatus);
	auto mainEditor = (CMainEditor*)pMainEditor;
	
	if (bShow)
		mainEditor->GetMenu()->GetSubMenu(CMAINEDITOR_MENUINDEX_STORYEDITOR)->CheckMenuItem(ID_WORLD_EDITOR, MF_BYCOMMAND | MF_CHECKED);
	else
		mainEditor->GetMenu()->GetSubMenu(CMAINEDITOR_MENUINDEX_STORYEDITOR)->CheckMenuItem(ID_WORLD_EDITOR, MF_BYCOMMAND | MF_UNCHECKED);
}


void CWorldEditor::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	if (!static_posList)
		return;
	auto dpi = MyGetDPI();
	CRect rc;
	//地点列表
	int x, y, w, h;
	x = DPISCALE(10);
	y = DPISCALE(10);
	w = DPISCALE(200);
	h = cy - DPISCALE(20);
	static_posList->MoveWindow(x, y, w, h);
	y += DPISCALE(20);
	h -= DPISCALE(20);
	tree_posList.MoveWindow(x, y, w, h);
	//连接视图
	x = DPISCALE(220);
	y = DPISCALE(10);
	w = cx - DPISCALE(230);
	h = cy - DPISCALE(220);
	static_linkView->MoveWindow(x, y, w, h);
	y += DPISCALE(20);
	h -= DPISCALE(20);
	w -= DPISCALE(1);
	static_linkView_draw->MoveWindow(x, y, w, h);
	//地点描述
	x = DPISCALE(220);
	y = cy - DPISCALE(200);
	w = (cx - DPISCALE(230)) / 2 - DPISCALE(5);
	h = DPISCALE(190);
	static_posInfo->MoveWindow(x, y, w, h);
	y += DPISCALE(20);
	h -= DPISCALE(20);
	edit_posInfo.MoveWindow(x, y, w, h);
	//地点设定实现表
	x = DPISCALE(220) + (cx - DPISCALE(230)) / 2 + DPISCALE(5);
	y = cy - DPISCALE(200);
	w = (cx - DPISCALE(230)) / 2 - DPISCALE(5);
	h = DPISCALE(190);
	static_set->MoveWindow(x, y, w, h);
	y += DPISCALE(20);
	h -= DPISCALE(20);
	listbox_set.MoveWindow(x, y, w, h);
	//重绘窗口
	GetClientRect(&rc);
	InvalidateRect(&rc);
}

//递归添加
void CWorldEditor_OnAddPos_TreeItemToXML(std::unordered_map<int, MyWorldSet>* worldsetList, CMyTreeCtrl* treeCtrl, HTREEITEM item, tinyxml2::XMLDocument* xmlDoc, tinyxml2::XMLElement* xmlElement, bool onlySelf = false)
{
	if (item == nullptr)
		return;
	int id = (int)treeCtrl->GetItemData(item);
	MyWorldSet& ws = worldsetList->at(id);
	auto newElem = xmlDoc->NewElement("Pos");
	//设置地点名称
	std::vector<char> gbk_buff;
	UTF16ToGBK(ws.name.GetString(), &gbk_buff);
	newElem->SetAttribute("Name", gbk_buff.data());
	//设置地点描述
	UTF16ToGBK(ws.info.GetString(),&gbk_buff);
	newElem->SetAttribute("Info", gbk_buff.data());
	//添加设定实现表
	for (auto& p : ws.labelMap)
	{
		auto newLabel = xmlDoc->NewElement("Set");
		UTF16ToGBK(p.second.name.GetString(), &gbk_buff);
		newLabel->SetAttribute("Name", gbk_buff.data());
		newElem->InsertEndChild(newLabel);
	}
	//插入节点
	if (xmlElement)
		xmlElement->InsertEndChild(newElem);
	else
		xmlDoc->InsertEndChild(newElem);
	//遍历子节点
	CWorldEditor_OnAddPos_TreeItemToXML(worldsetList, treeCtrl, treeCtrl->GetChildItem(item), xmlDoc, newElem);
	//遍历兄弟节点
	if (!onlySelf)
		CWorldEditor_OnAddPos_TreeItemToXML(worldsetList, treeCtrl, treeCtrl->GetNextSiblingItem(item), xmlDoc, xmlElement);
}

void CWorldEditor::OnAddPos()
{
	
	auto item = tree_posList.GetSelectedItem();
	//添加地点
	COSLabel dlg;
	dlg.SetWindowTitleAndLabel(L"添加地点", L"地点名称：");
	if (dlg.DoModal() != IDOK)
		return;
	
	//worldsetList添加
	MyWorldSet ws;
	ws.info = L"";
	ws.name = dlg.outLabel;
	auto iter = worldsetList.end();
	iter--;
	int nextId = iter->first + 1;
	worldsetList.insert(std::make_pair(nextId, ws));
	//tree添加
	HTREEITEM childItem = tree_posList.InsertItem(dlg.outLabel.GetString(), item);
	tree_posList.SetItemData(childItem, nextId);
	//上传到数据库
	UploadDB();
}

void CWorldEditor::OnRenamePos()
{
	
	auto item = tree_posList.GetSelectedItem();
	auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
	//重命名地点
	COSLabel dlg;
	dlg.load = true;
	dlg.outLabel = ws.name;
	dlg.SetWindowTitleAndLabel(L"重命名地点", L"地点名称：");
	if (dlg.DoModal() != IDOK)
		return;
	if (ws.name == dlg.outLabel)
		return;
	//更新到显示列表
	ws.name = dlg.outLabel;
	tree_posList.SetItemText(item, dlg.outLabel.GetString());
	//更新到数据库
	UploadDB();
}

void CWorldEditor_OnDeletePos_ForeachAllChild(std::vector<int>* idList, CMyTreeCtrl* treeCtrl, HTREEITEM item)
{
	if (item == nullptr)
		return;
	idList->push_back((int)treeCtrl->GetItemData(item));
	//遍历子节点
	CWorldEditor_OnDeletePos_ForeachAllChild(idList, treeCtrl, treeCtrl->GetChildItem(item));
	//遍历兄弟节点
	CWorldEditor_OnDeletePos_ForeachAllChild(idList, treeCtrl, treeCtrl->GetNextSiblingItem(item));
}

void CWorldEditor::OnEditPosinfo()
{
	
	auto item = tree_posList.GetSelectedItem();
	auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
	//编辑描述
	COSText dlg;
	dlg.load = true;
	dlg.outLabel = ws.info;
	CString str;
	str.Format(L"%s的描述：", ws.name.GetString());
	dlg.SetWindowTitleAndLabel(L"编辑描述", str.GetString());
	if (dlg.DoModal() != IDOK)
		return;
	if (ws.info == dlg.outLabel)
		return;
	//更新到显示列表
	ws.info = dlg.outLabel;
	edit_posInfo.SetWindowTextW(ws.info.GetString());
	//更新到数据库
	UploadDB();
}

void CWorldEditor::OnCopyPos()
{
	
	auto item = tree_posList.GetSelectedItem();
	if (!item)
		return;
	tinyxml2::XMLDocument xmlDoc;
	CWorldEditor_OnAddPos_TreeItemToXML(&worldsetList, &tree_posList, item, &xmlDoc, xmlDoc.RootElement(), true);
	tinyxml2::XMLPrinter xmlPrinter;
	xmlDoc.Print(&xmlPrinter);
	std::vector<wchar_t> wchar_buff;
	GBKToUTF16(xmlPrinter.CStr(), &wchar_buff);
	posCopyXML = wchar_buff.data();
}

void CWorldEditor::OnPastePos()
{
	
	if (posCopyXML.GetLength() == 0)
		return;
	auto item = tree_posList.GetSelectedItem();
	std::vector<char> gbk_buff;
	UTF16ToGBK(posCopyXML.GetString(), &gbk_buff);
	tinyxml2::XMLDocument xmlDoc;
	xmlDoc.Parse(gbk_buff.data());
	auto iter = worldsetList.end();
	iter--;
	int nextId = iter->first + 1;
	CWorldEditor_UpdateContext_TreeAddItem(&worldsetList, &tree_posList, item, xmlDoc.RootElement(), &nextId);
	tree_posList.RedrawWindow();
	//上传到数据库
	UploadDB();
}

void CWorldEditor::OnCutPos()
{
	
	OnCopyPos();
	OnDeletePos();
}

void CWorldEditor::OnDeletePos()
{
	
	auto item = tree_posList.GetSelectedItem();
	if (!item)
		return;
	//tree删除
	std::vector<int> idList;
	//先保留要删除的所有item的id
	CWorldEditor_OnDeletePos_ForeachAllChild(&idList, &tree_posList, tree_posList.GetChildItem(item));//记录要删除子节点
	idList.push_back((int)tree_posList.GetItemData(item));//记录删除自己
	tree_posList.DeleteItem(item);
	//worldsetList删除
	for (auto& p : idList)
		worldsetList.erase(p);
	//上传到数据库
	UploadDB();
}

void CWorldEditor::OnAddLabel()
{
	
	auto item = tree_posList.GetSelectedItem();
	if (item == nullptr)
		return;
	COSLabel dlg;
	dlg.SetWindowTitleAndLabel(L"添加地图设定标签", L"标签名：");
	if (dlg.DoModal() != IDOK)
		return;
	auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
	auto& labelMap = ws.labelMap;

	MyLabelXML label;
	label.name = dlg.outLabel.GetString();
	if (labelMap.find(label.name.GetString()) != labelMap.end())
	{
		CString str;
		str.Format(L"添加失败\n已有同名设定：%s", label.name.GetString());
		MessageBoxW(str.GetString(), L"添加失败", MB_ICONINFORMATION);
		return;
	}
	labelMap.insert(std::make_pair(label.name.GetString(), label));
	//显示更新
	listbox_set.ResetContent();
	for (auto& p : labelMap)
		listbox_set.AddString(p.second.name.GetString());
	//更新到数据库
	UploadDB();
}


void CWorldEditor::OnRenameLabel()
{
	
	int sel = listbox_set.GetCurSel();
	CString name_prep;
	listbox_set.GetText(sel, name_prep);
	COSLabel dlg;
	dlg.load = true;
	dlg.outLabel = name_prep;
	dlg.SetWindowTitleAndLabel(L"重命名标签", L"设定名：");
	if (dlg.DoModal() != IDOK)
		return;
	if (dlg.outLabel == name_prep)
		return;
	auto item = tree_posList.GetSelectedItem();
	auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
	auto& labelMap = ws.labelMap;
	MyLabelXML label = labelMap.at(name_prep.GetString());
	label.name = dlg.outLabel;
	labelMap.erase(name_prep.GetString());
	if (labelMap.find(label.name.GetString()) != labelMap.end())
	{
		CString str;
		str.Format(L"重命名失败\n已有同名设定：%s", label.name.GetString());
		MessageBoxW(str.GetString(), L"重命名失败", MB_ICONINFORMATION);
		return;
	}
	labelMap.insert(std::make_pair(label.name.GetString(), label));
	//显示更新
	listbox_set.ResetContent();
	for (auto& p : labelMap)
		listbox_set.AddString(p.second.name.GetString());
	//更新到数据库
	UploadDB();
}


void CWorldEditor::OnDeleteLabel()
{
	
	int sel = listbox_set.GetCurSel();
	CString name;
	listbox_set.GetText(sel, name);
	auto item = tree_posList.GetSelectedItem();
	auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
	auto& labelMap = ws.labelMap;
	labelMap.erase(name.GetString());
	//显示更新
	listbox_set.ResetContent();
	for (auto& p : labelMap)
		listbox_set.AddString(p.second.name.GetString());
	//更新到数据库
	UploadDB();
}

void CWorldEditor::OnTvnSelchangedTreePoslist(NMHDR* pNMHDR, LRESULT* pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	
	auto item = tree_posList.GetSelectedItem();
	if (item == nullptr)
	{
		//取消选择
		edit_posInfo.SetWindowTextW(L"");
		listbox_set.ResetContent();
	}
	else
	{
		//选择
		auto& ws = worldsetList.at((int)tree_posList.GetItemData(item));
		edit_posInfo.SetWindowTextW(ws.info.GetString());
		listbox_set.ResetContent();
		for (auto& p : ws.labelMap)
			listbox_set.AddString(p.second.name.GetString());
	}
	*pResult = 0;
}

void CWorldEditor::UploadDB()
{
	tinyxml2::XMLDocument xmlDoc;
	CWorldEditor_OnAddPos_TreeItemToXML(&worldsetList, &tree_posList, tree_posList.GetRootItem(), &xmlDoc, xmlDoc.RootElement());
	tinyxml2::XMLPrinter xmlPrinter;
	xmlDoc.Print(&xmlPrinter);
	std::vector<wchar_t> wchar_buff;
	GBKToUTF16(xmlPrinter.CStr(), &wchar_buff);
	CString xmlUTF16 = wchar_buff.data();
	auto mainEditor = (CMainEditor*)pMainEditor;
	mainEditor->SetDBWorldSet(xmlUTF16);
}
