DialogView = class("DialogView", ContainerView)

DialogView.ViewType = UIViewType.DialogLayer;

autoImport("Dialog_MenuData");
autoImport("NpcMenuBtnCell");
autoImport("DialogCell");
autoImport("EndLessTowerCountDownInfo");

local tempV3 = LuaVector3();

function DialogView:GetShowHideMode()
	return PanelShowHideMode.MoveOutAndMoveIn
end

function DialogView:Init()
	self:InitView();
	self:MapEvent();
end

function DialogView:InitView()
	self.menu = self:FindGO("Menu");
	self.menuSprite = self.menu:GetComponent(UISprite);

	local bottom = self:FindGO("Anchor_bottom");
	local activeH = GameObjectUtil.Instance:GetUIActiveHeight(self.gameObject)
	tempV3:Set(0, -activeH/2, 0);
	bottom.transform.localPosition = tempV3;

	self.top = self:FindGO("Anchor_Top");
	tempV3:Set(0, activeH/2, 0);
	self.top.transform.localPosition = tempV3;

	local obj = self:LoadPreferb("cell/DialogCell", bottom);
	obj.transform.localPosition = LuaVector3.zero;
	self.dialogCtl = DialogCell.new(obj);
	self.dialogCtl:AddEventListener(MouseEvent.MouseClick, self.ClickDialogEvent, self);

	-- updateTasks
	local grid = self:FindChild("MenuGrid", self.menu):GetComponent(UIGrid);
	self.menuCtl = UIGridListCtrl.new(grid, NpcMenuBtnCell, "NpcMenuBtnCell");
	self.menuCtl:AddEventListener(MouseEvent.MouseClick, self.ClickMenuEvent, self);
end

function DialogView:ClickDialogEvent()
	local preDialog = self.dialogInfo[self.dialogIndex];
	-- 如果上一段對話有選項 則必須點選選項才可以進行下一步 否則無法進行
	if(preDialog and (not preDialog.Option or preDialog.Option == "") and self.forceClickMenu ~= true)then
		self:DialogGoUpdate();
	end
end

function DialogView:ResetViewData()
	self.defaultDialogId = nil;
	self.dialoglist = nil;
	self.dialognpcs = nil;
	self.tasks = nil;
	self.callback = nil;
	self.callbackData = nil;
	self.camera = nil;
	self.wait = nil;
	self.questId = nil;
	if(self.questParams)then
		TableUtility.ArrayClear(self.questParams);
	else
		self.questParams = {};
	end
	self.addconfig = nil;
	self.addleft = nil;
	self.addfunc = nil;
	self.custommenudata = nil;
	self.npcguid = nil;
	self.npcdata = nil;
	self.optionid = nil;
	self.dialogInfo = nil;
	self.dialogIndex = nil;
	self.dialogend = false;
	self.subViewId = nil;
	self.optionWait = 0;
	self.midShowFunc = nil;
	self.midShowFuncParam = nil;
	self.midHideFunc = nil;
	self.forceClickMenu = false;
end

function DialogView:OnEnter()
	DialogView.super.OnEnter(self);

	self:ResetViewData();
	self:UpdateViewData();

	self:UpdateShow();

	self.gameObject:SetActive(true);

	local npcinfo = self:GetCurNpc();
	if(npcinfo)then
		local npcRootTrans = npcinfo.assetRole.completeTransform;
		if(npcRootTrans)then
			local viewPort = CameraConfig.NPC_Dialog_ViewPort;
			if(type(self.camera)=="number")then
				viewPort = Vector3(viewPort.x, viewPort.y, self.camera);
			end
			local duration = CameraConfig.NPC_Dialog_DURATION;
			self:CameraFocusOnNpc(npcRootTrans, viewPort, duration);
		end
	end

	local midShowFunc = self.viewdata.midShowFunc;
	if(midShowFunc)then
		self.midHideFunc = midShowFunc(self.gameObject, self.viewdata.midShowFuncParam);
	end

	FunctionVisitNpc.Me():AddVisitRef();
end

-- ViewData參數
-- 1. dialoglist(Dialog表中的ids or string(s){Text=string,ViceText=string}(s)這種情況是爲了處理文字文字大小不一樣)
-- 2. dialognpcs(對話里涉及到的NPCIDS)
-- 3. tasks 對話的任務配置(支線任務或者對話任務)
-- 4. callback(對話結束的回撥) function(callbackData, optionid, isSuccess)
-- 5. camera(攝像機的Z軸角度)
-- 6. wait(對話結束 攝像機重置的等待時間)
-- 7. questdata(任務對話的任務數據)
-- 8. addconfig( 自主新增的功能配置(npcfunc表中的功能型別) )
-- 9. addleft( 是否新增離開按鈕 )
-- 10. addfunc( 自主新增的功能(NameZh = string, event, eventParam, closeDialog, waitClose) )
-- 11. npcinfo( 對話的NPC )
-- 12. subViewId( 對話面板id );
-- 13. midShowFunc(gameObject, showEventParam)( 對話界面中間需要建立其他預設時呼叫 );
-- 14. midShowFuncParam( 對話界面建立時呼叫 );
-- 15. forceClickMenu (點選界面不會關閉對話)
function DialogView:UpdateViewData()
	self.defaultDialogId = self.viewdata.defaultDialogId;
	self.dialoglist = self.viewdata.dialoglist;
	self.dialognpcs = self.viewdata.dialognpcs;
	self.tasks = self.viewdata.tasks;
	self.callback = self.viewdata.callback;
	self.callbackData = self.viewdata.callbackData;
	self.camera = self.viewdata.camera;
	self.wait = self.viewdata.wait;
	self.questId = self.viewdata.questId;
	self.addconfig = self.viewdata.addconfig;
	self.addleft = self.viewdata.addleft;
	self.addfunc = self.viewdata.addfunc;
	self.subViewId = self.viewdata.subViewId;
	self.forceClickMenu = self.viewdata.forceClickMenu;
	self.custommenudata = self.viewdata.custommenudata;

	local npcinfo = self.viewdata.npcinfo;
	if(npcinfo~=nil)then
		self.npcguid = npcinfo.data.id;
		self.npcdata = npcinfo.data.staticData;
	end
	
	self.dialogInfo = {};
	self.dialogIndex = 1;
	self:UpdateQuestParams();
end

function DialogView:GetCurNpc()
	if(self.npcguid)then
		return SceneCreatureProxy.FindCreature(self.npcguid);
	end
	return nil;
end

function DialogView:UpdateQuestParams()
	if(self.questId)then
		local questdata = QuestProxy.Instance:getQuestDataByIdAndType( self.questId );
		if(questdata and questdata.names)then
			TableUtility.ArrayShallowCopy(self.questParams, questdata.names);
		end
	end
end

function DialogView:UpdateShow()
	if(self.dialognpcs~=nil and type(self.dialognpcs) == "table")then
		for _,id in pairs(self.dialognpcs) do
			local npc = NSceneNpcProxy.Instance:FindNearestNpc(Game.Myself:GetPosition(), id);
			if(npc~=nil)then
				FunctionVisitNpc.Me():NpcTurnToMe(npc)
			end
		end
	end

	if(self.dialoglist)then
		self:UpdateDialoglst(self.dialoglist);
	else
		self:UpdateDefaultDialog();
	end
end

function DialogView:UpdateDialoglst(dialoglist)
	if(#dialoglist>0)then
		local dlst = {};
		-- 伺服器下發改為讀配置 重新組裝數據結構
		for i = 1,#dialoglist do
			local dilg, data = dialoglist[i];
			if(type(dilg)=="number")then
				-- data = Table_Dialog[dilg];
				data = DialogUtil.GetDialogData(dilg);
			elseif(type(dilg)=="string")then
				data = {id = 0, Text = dilg, SubViewId = self.subViewId};
				if(self.npcdata)then
					data.Speaker = self.npcdata.id;
				end
			elseif(type(dilg) == "table")then
				data = {id = 0, Text = dilg.Text, ViceText = dilg.ViceText};
				if(self.npcdata)then
					data.Speaker = self.npcdata.id;
				end
			end
			if(data)then
				table.insert(dlst, data);
			else
				errorLog( string.format("%s not config", dialoglist[i]) );
			end
		end
		self.dialogInfo = dlst;
		self:UpdateDialog();
	else
		self:CloseSelf();
	end
end

function DialogView:UpdateDefaultDialog()
	if(self.npcdata)then
		local defaultDialogId = self.defaultDialogId;
		if(defaultDialogId == nil)then
			defaultDialogId = self.npcdata.DefaultDialog
		end
		if(defaultDialogId)then
			local configs = {};
			if(self.npcdata)then
				configs = self.npcdata.NpcFunction;
			end
			-- self.dialogInfo ={ Table_Dialog[defaultDialogId] };
			self.dialogInfo ={ DialogUtil.GetDialogData(defaultDialogId) };
			self:UpdateDialog(configs, self.tasks);
		else
			-- 如果npc沒有配置預設對話 並且有任務事件 則新增預設對話
			local configs = self.npcdata.NpcFunction;
			local tempData = {
				id = 1, 
				Speaker = self.npcdata.id, 
				Text = '……', 
			}; 
			self.dialogInfo ={ tempData };
			self:UpdateDialog(configs, self.tasks);
		end
	else
		self:CloseSelf();
	end
end

-- config 和 tasks 可以不傳
function DialogView:UpdateDialog(config, tasks)
	if(#self.dialogInfo>0)then
		self.nowDialogData = self.dialogInfo[self.dialogIndex];

		if(self.nowDialogData)then
			self.dialogCtl:SetData(self.nowDialogData, self.questParams);
			if(self.nowDialogData.Option and self.nowDialogData.Option~="")then
				local optionConfig = StringUtil.AnalyzeDialogOptionConfig(self.nowDialogData.Option);
				if(#optionConfig>0)then
					self:UpdateMenu(config,tasks,optionConfig);
				end
			else
				self:UpdateMenu(config,tasks, nil);
			end
			self:UpdateDialogSubView(self.nowDialogData.SubViewId);
			self.menuSprite.enabled = self.nowDialogData.Text ~= "";
		else
			errorLog("Not Find Dialog");
			self:CloseSelf();
		end
	else
		self.nowDialogData = nil;
	end
end

function DialogView:UpdateDialogSubView(subId)
	if(self.nowSubId)then
		self:RemoveSubView(self.nowSubId);
		self.nowSubId = nil;
	end
	if(subId)then
		self.nowSubId = subId;
		local subPage = SubViewMap.Instance:GetSubView(subId);
		local nowSubPage = self:AddSubView(subId, subPage);
		nowSubPage:OnEnter(subId, self);
	end
end

function DialogView:DialogGoUpdate()
	self.dialogend = self.dialogIndex == #self.dialogInfo;

	self.dialogIndex = self.dialogIndex+1;
	if(self.dialogIndex<=#self.dialogInfo)then
		self:UpdateDialog();
	else
		-- 沒有特定的離開按鈕
		if(not self.addleft)then
			self:CloseSelf();
		end
	end
end

local tempArray = {};
function DialogView:UpdateMenu(configs, tasks, option)
	if(not self.menuData)then
		self.menuData = {};
	else
		TableUtility.ArrayClear(self.menuData);
	end
	-- Tasks
	if(tasks)then
		for i=1,#tasks do
			if(tasks[i])then
				if(tasks[i].staticData)then
					local taskMenuData = Dialog_MenuData.new();
					taskMenuData:Set_ByTask(tasks[i]);
					table.insert(self.menuData, taskMenuData);
				else
					errorLog(string.format("Task:%s Not Have StaticData", tasks[i].id));
				end
			end
		end
	end
	-- Configs
	if(configs or self.addconfig)then
		TableUtility.ArrayClear(tempArray);
		if(configs)then
			TableUtility.ArrayShallowCopy(tempArray, configs);
		end
		if(self.addconfig)then
			for i=1,#self.addconfig do
				table.insert(tempArray, self.addconfig[i]);
			end
		end

		for i=1,#tempArray do
			local typeid, param, name = tempArray[i].type, tempArray[i].param, tempArray[i].name;
			local npcfunc_menuData = Dialog_MenuData.new();
			npcfunc_menuData:Set_ByNpcFunctionConfig(typeid, param, name, self:GetCurNpc());
			table.insert(self.menuData, npcfunc_menuData);
		end
	end
	-- option
	if(option)then
		for i=1,#option do
			local option_menuData = Dialog_MenuData.new();
			option_menuData:Set_ByOption(option[i]);
			table.insert(self.menuData, option_menuData);
		end
	end
	-- 額外新增的自主功能(func(event, name))
	if(self.addfunc)then
		for i=1,#self.addfunc do
			local addFunc = self.addfunc[i];
			if(addFunc.event and addFunc.NameZh)then
				local addfunc_menuData = Dialog_MenuData.new();
				addfunc_menuData:Set_Name(addFunc.NameZh);
				addfunc_menuData:Set_CloseDialogWhenClick(addFunc.closeDialog);
				addfunc_menuData:Set_WaitCloseDialogWhenClick(addFunc.waitClose);
				addfunc_menuData:Set_CusetomClickCall(addFunc.event, addFunc.eventParam);
				table.insert(self.menuData, addfunc_menuData);
			end
		end
	end
	if(self.custommenudata)then
		for i=1,#self.custommenudata do
			table.insert(self.menuData, self.custommenudata[i]);
		end
	end
	if(self.addleft)then
		local addleft_menuData = Dialog_MenuData.new();
		addleft_menuData:Set_CusetomClickCall();
		addleft_menuData:Set_CloseDialogWhenClick(true);
		addleft_menuData:Set_Name(ZhString.DialogView_Left);
		table.insert(self.menuData, addleft_menuData);
	end

	self:UpdateMenuCtl();
end

function DialogView:RegisterMenuEvent(btnGO, optionid, needReplace)
	if(btnGO == nil or optionid == nil)then
		redlog("btnGO or optionid is nil");
		return;
	end

	local menuDataDirty = false;

	local optionData;
	local m;
	for i=#self.menuData,1,-1 do
		m = self.menuData[i];
		if(m.optionid == optionid)then
			optionData = m;

			if(needReplace)then
				menuDataDirty = true;
				table.remove(self.menuData, i)
			end

			break;
		end
	end
	local func = function ()
		if(optionData == nil)then
			self:CloseSelf();
		else
			self:DoMenuEvent(optionData);
		end
	end
	self:AddClickEvent( btnGO, func);

	if(menuDataDirty)then
		self:UpdateMenuCtl();
	end
end

function DialogView:UpdateMenuCtl(menuData)
	menuData = menuData or self.menuData;

	if(#menuData>0)then
		local realCount = #menuData;
		for i=#menuData,1,-1 do
			local mData = menuData[i];
			if(mData and mData.state == NpcFuncState.InActive)then
				realCount = realCount - 1;
			end
		end
		realCount = math.max(0, realCount);

		if(realCount > 0)then
			self.menu:SetActive(true);
			self.menuSprite.height = 60 + realCount * 70;
		else
			self.menu:SetActive(false);
		end

		self.menuCtl:ResetDatas(menuData);
		self.menuCtl.layoutCtrl.repositionNow = true;
	else
		self.menu:SetActive(false);
	end
end

function DialogView:ClickMenuEvent(cellCtl)
	local cellData = cellCtl.data;
	if(not cellData)then
		return;
	end

	self:DoMenuEvent(cellData);
end

function DialogView:DoMenuEvent(cellData)
	local menuType = cellData.menuType;
	local npcinfo = self:GetCurNpc();
	if(menuType == Dialog_MenuData_Type.NpcFunc)then
		self.dialogend = true;

		local stay = FunctionNpcFunc.Me():DoNpcFunc( cellData.npcFuncData, npcinfo, cellData.param )
		if(not stay)then
			DialogView.super.CloseSelf(self);
		end
	elseif(menuType == Dialog_MenuData_Type.Option)then
		self.optionid = cellData.optionid;
		if(self.optionid == 0)then
			self:DialogGoUpdate();
		else
			self.dialogend = true;
			-- self.optionWait = 0.2;
			self:CloseSelf();	
		end
	elseif(menuType == Dialog_MenuData_Type.Task)then
		if(cellData.task)then
			if(self.callback)then
				self.callback(cellData.task.id, self.optionid);
			end
			FunctionVisitNpc.Me():ExcuteQuestEvent(npcinfo, cellData.task);
		end
	elseif(menuType == Dialog_MenuData_Type.CustomFunc)then
		if(cellData.closeDialog == true)then
			if(cellData.waitClose ~= nil)then
				self.optionWait = cellData.waitClose;
			end
			self:CloseSelf();
		end
		-- custom event excute after close(if need)
		if(cellData.clickCall)then
			local stay = cellData.clickCall(self:GetCurNpc(), cellData.clickCallParam);
			if(cellData.closeDialog ~= true and stay == false)then
				self:CloseSelf();
			end
		end
	end
end

function DialogView:MapEvent()
	self:AddListenEvt(SceneGlobalEvent.Map2DChanged, self.HandleUpdateMap2d)
	self:AddListenEvt(DialogEvent.AddMenuEvent, self.HandleAddMenuEvent);
	self:AddListenEvt(ServiceEvent.NUserRequireNpcFuncUserCmd, self.HandleRequireNpcFuncUserCmd);
	self:AddListenEvt(SceneUserEvent.SceneRemoveNpcs, self.HandleRemoveNpcs);
	self:AddListenEvt(DialogEvent.NpcFuncStateChange, self.HandleNpcFuncStateChange);
	self:AddListenEvt(DialogEvent.AddUpdateSetTextCall, self.HandleAddUpdateSetTextCall);

	self:AddListenEvt(ServiceUserProxy.RecvLogin, self.HandleRecvLogin);

	self:AddListenEvt(CarrierEvent.MyCarrierStart, self.CloseSelf);
end

function DialogView:HandleRecvLogin(note)
	self:CloseSelf();
end

function DialogView:HandleAddUpdateSetTextCall(note)
	self.dialogCtl:Set_UpdateSetTextCall(note.body[1], note.body[2]);
end

function DialogView:HandleNpcFuncStateChange(note)
	local changeFuncs = note.body;
	-- self.menuData
	for i=1,#changeFuncs do
		local cache = changeFuncs[i];

		local menuData,index;
		for j=#self.menuData,1,-1 do
			if(self.menuData[j].key == cache.key)then
				menuData = self.menuData[j];
				index = j;
				break;
			end
		end
		menuData:Set_State(cache.state);
	end

	self:UpdateMenuCtl();
end

function DialogView:HandleRemoveNpcs(note)
	local npcs = note.body
	if(npcs and #npcs>0)then
		for i=1,#npcs do
			if(self.npcguid == npcs[i])then
				self:CloseSelf();
			end
		end
	end
end

function DialogView:HandleUpdateMap2d(note)
	local npcinfo = self:GetCurNpc();
	if(npcinfo)then
		local npc = FunctionVisitNpc.Me():GetTarget()
		if(npc ~= npcinfo)then
			DialogView.super.CloseSelf(self);
		end
	end
end

function DialogView:HandleAddMenuEvent(note)
	local config = note.body;
	if(config == nil)then
		return;
	end

	local npcinfo = self:GetCurNpc();

	local dialog_menuData = Dialog_MenuData.new();
	dialog_menuData:Set_ByNpcFunctionConfig(config.type, config.param, config.name, npcinfo);
	table.insert(self.menuData, 1, dialog_menuData);
	
	self:UpdateMenuCtl();
end

function DialogView:HandleRequireNpcFuncUserCmd(note)
	local data = note.body;
	local npcinfo = self:GetCurNpc();

	if(data == nil or npcinfo == nil )then
		return;
	end

	local requireFunctions = npcinfo.data.staticData.RequireNpcFunction;
	local functions = data.functions;
	if(functions)then
		for i=1,#functions do
			local config = StringUtil.Json2Lua(functions[i]);
			if(type(config) == "table")then
				local dialog_menuData = Dialog_MenuData.new();
				dialog_menuData:Set_ByNpcFunctionConfig(config.type, config.param, config.name, npcinfo);
				table.insert(self.menuData, 1, dialog_menuData);
			end
		end
		self:UpdateMenuCtl();
	end
end

function DialogView:RemoveLeanTween()
	if(self.lt)then
		self.lt:cancel();
	end
	self.lt = nil;
end

-- 退出是否需要等待
function DialogView:CloseSelf()
	if(self.dialogend and self.callback~=nil)then
		self.callback(self.callbackData, self.optionid, true);
		self.callback = nil;
		self.callbackData = nil;
	end

	self.gameObject:SetActive(false);

	local wait = self.wait or self.optionWait or 0;
	if(wait > 0)then
		self:RemoveLeanTween();
		self.lt = LeanTween.delayedCall(wait, function ()
			DialogView.super.CloseSelf(self);
		end);
	else
		DialogView.super.CloseSelf(self);
	end
end

function DialogView:OnExit()
	-- 結束訪問
	self.super.OnExit(self);

	FunctionVisitNpc.Me():RemoveVisitRef();
	FunctionNpcFunc.Me():ClearUpdateCheck();

	if(self.callback~=nil)then
		self.callback(self.callbackData, nil, false);
		self.callback = nil;
		self.callbackData = nil;
	end
	if(type(self.midHideFunc) == "function")then
		self.midHideFunc();
		self.midHideFunc = nil;
	end

	self.dialogCtl:OnExit();

	self:CameraReset();
	self:RemoveLeanTween();
	
	if(self.dialognpcs~=nil and type(self.dialognpcs) == "table")then
		for _,id in pairs(self.dialognpcs) do
			local npc = NSceneNpcProxy.Instance:FindNearestNpc(Game.Myself:GetPosition(), id);
			if(npc~=nil)then
				FunctionVisitNpc.Me():NpcTurnBack(npc)
			end
		end
	end
end
