class QuestDialogWnd extends UICommonAPI;

const DISTTICK = 50;
const TALK_DISTANCE = 250;
const TEXTTICK = 50;
const TEXTNUM = 2;
const MONSTERID_DEACTIVE = 19652;
const QUEST_CATEGORY_MAIN = 10001;
const QUEST_CATEGORY_SUB = 20001;
const QUEST_CATEGORY_SPECIAL = 30001;
const DIALOG_HELP_KEY = "\\#$help_index=";
const DIALOG_CLASSCHANGE_KEY = "\\#$class_change";

enum QUESTDialogType 
{
	non,
	Start,
	Accept,
	complete,
	End,
	AGAIN
};

struct questData
{
	var int QuestID;
	var int dialogType;
	var Vector npcLoc;
};

var private TextBoxHandle textBox;
var private TextBoxHandle textBox2;
var private TextListBoxHandle textBoxList;
var private CharacterViewportWindowHandle Viewport;
var private ButtonHandle confirmBtn;
var private ButtonHandle helpBtn;
var private ButtonHandle CancelBtn;
var int _currentQuestID;
var int _currentDialogType;
var private int lastAcceptedQuestID;
var private string dialog;
var private int currentHelpIndex;
var private int clickedX;
var private int clickedY;
var private L2UITimerObject tObjectTalk;
var private L2UITimerObject tObjectDist;
var array<questData> qDatas;

static function QuestDialogWnd Inst()
{
	return QuestDialogWnd(GetScript("QuestDialogWnd"));	
}

event OnRegisterEvent()
{
	RegisterEvent(EV_Restart);
	RegisterEvent(EV_PacketID(class'UIPacket'.const.S_EX_QUEST_DIALOG));	
}

event OnLoad()
{
	textBox = GetTextBoxHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".textBox");
	textBox2 = GetTextBoxHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".textBox2");
	textBoxList = GetTextListBoxHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".textBoxList");
	textBoxList.SetScrollBarPosition(0, -12, 15);
	Viewport = GetCharacterViewportWindowHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".viewport");
	Viewport.SetUISound(false);
	Viewport.SetSpawnDuration(0.10f);
	confirmBtn = GetButtonHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".confirmBtn");
	helpBtn = GetButtonHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".helpBtn");
	CancelBtn = GetButtonHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".cancelBtn");
	tObjectTalk = class'L2UITimer'.static.Inst()._AddNewTimerObject(TEXTTICK, -1);
	tObjectTalk._DelegateOnStart = HandleTimerOnStart;
	tObjectTalk._DelegateOnTime = HandleTimerOnTime;
	tObjectDist = class'L2UITimer'.static.Inst()._AddNewTimerObject(DISTTICK, -1);
	tObjectDist._DelegateOnTime = HandleOnTimeUpdateLocChk;
	GetButtonHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".portraitSetterBtn").HideWindow();
	if(IsBuilderPC() && GetReleaseMode() == RM_DEV)
	{
		GetButtonHandle(m_hOwnerWnd.m_WindowNameWithFullPath $ ".portraitSetterBtn").ShowWindow();
	}	
}

event OnEvent(int Event_ID, string param)
{
	switch(Event_ID)
	{
		case EV_Restart:
			HandleRestart();
			break;
		case EV_PacketID(class'UIPacket'.const.S_EX_QUEST_DIALOG):
			RT_S_EX_QUEST_DIALOG();
			break;
	}	
}

event OnLButtonDown(WindowHandle a_WindowHandle, int X, int Y)
{
	GetClientCursorPos(clickedX, clickedY);
	if(dialog == "")
	{
		return;
	}
	tObjectTalk._Stop();
	textBoxList.Clear();
	textBoxList.AddString(dialog, GetColor(199, 199, 199, 255));
	dialog = "";	
}

event OnClickButton(string strID)
{
	if(CheckDrag())
	{
		return;
	}
	switch(strID)
	{
		case "helpBtn":
			ShowCurrentHelp();
			break;
		case "confirmBtn":
			HandleConfirmBtn();
			break;
		case "cancelBtn":
			HandleCancelBtn();
			break;
		case "portraitSetterBtn":
			GetWindowHandle("UIPortraitSetter").ShowWindow();
			UIPortraitSetter(GetScript("UIPortraitSetter"))._SetCurrentQuestInfo();
			break;
	}
}

private function HandleRestart()
{
	Clear();
	_currentQuestID = -1;
	_currentDialogType = -1;	
}

private function Clear()
{
	qDatas.Length = 0;	
}

private function HandleCancelBtn()
{
	switch(qDatas[0].dialogType)
	{
		case 2:
		case 1:
			DialogShow(DialogModalType_Modalless, DialogType_OKCancel, GetSystemMessage(13821), string(self), 294);
			class'DialogBox'.static.Inst().AnchorToOwner(0, 0);
			class'DialogBox'.static.Inst().SetDefaultAction(EDefaultCancel);
			class'DialogBox'.static.Inst().DelegateOnOK = HandleDialogCancel;
			return;
	}
	_NextShowQuest();
}

private function HandleDialogCancel()
{
	switch(_currentDialogType)
	{
		case 2:
			RQ_C_EX_QUEST_ACCEPT(false);
			break;
	}
	_NextShowQuest();	
}

private function ShowCurrentHelp()
{
	if(currentHelpIndex > 0)
	{
		class'HelpWnd'.static.ShowHelp(currentHelpIndex);
	}	
}

private function HandleConfirmBtn()
{
	switch(_currentDialogType)
	{
		case 1:
			ShowTeleport();
			break;
		case 2:
			class'QuestConfirmWnd'.static.Inst()._ShowQuestConfirm();
			break;
		case 3:
			ShowTeleport();
			break;
		case 4:
			class'QuestConfirmWnd'.static.Inst()._ShowQuestEnd();
			break;
	}	
}

private function ShowTeleport()
{
	DialogShow(DialogModalType_Modalless, DialogType_OKCancel, GetSystemString(13853), string(self), 294);
	class'DialogBox'.static.Inst().AnchorToOwner(0, 0);
	class'DialogBox'.static.Inst().SetDefaultAction(EDefaultCancel);
	class'DialogBox'.static.Inst().DelegateOnOK = HandleDialogOK;	
}

private function HandleDialogOK()
{
	RQ_C_EX_QUEST_TELEPORT();
	_NextShowQuest();	
}

event OnHide()
{
	CheckAcceptOnHide();
	tObjectTalk._Stop();
	tObjectDist._Stop();
	textBoxList.Clear();
	dialog = "";
	class'QuestConfirmWnd'.static.Inst().m_hOwnerWnd.HideWindow();
	if(DialogIsMine())
	{
		class'DialogBox'.static.Inst().HideDialog();
	}	
}

private function CheckAcceptOnHide()
{
	if(_currentDialogType != 2)
	{
		return;
	}
	if(! IsMainCurrent())
	{
		return;
	}
	if(lastAcceptedQuestID == _currentQuestID)
	{
		return;
	}
	if(CollectionSystem(GetScript("CollectionSystem"))._IsCollectionOpen())
	{
		return;
	}
	RQ_C_EX_QUEST_ACCEPT(true);	
}

event OnEnterState(name a_CurrentStateName)
{
	if(qDatas.Length > 0)
	{
		ShowQuest(_currentQuestID == qDatas[0].QuestID);
	}
}

private function SetPortrait(NQuestUIData questUIData)
{
	local NQuestNpcPortraitUIData questNpcPortraitUIData;
	local int questPortraitID;

	switch(_currentDialogType)
	{
		case 1:
		case 2:
		case 5:
			questPortraitID = questUIData.StartNPC.Id;
			break;
		case 3:
		case 4:
			questPortraitID = questUIData.EndNPC.Id;
			break;
	}
	if(questPortraitID < 1)
	{
		textBox2.SetText(GetSystemString(118));
		Viewport.HideWindow();
		return;
	}
	Viewport.ShowWindow();
	API_GetNQuestNpcPortraitData(questPortraitID, questNpcPortraitUIData);
	textBox2.SetText(API_GetNPCName(questPortraitID));
	Viewport.SetNPCInfo(questPortraitID);
	Viewport.SetCameraDistance(questNpcPortraitUIData.ViewDist);
	Viewport.SetCharacterOffsetX(questNpcPortraitUIData.ViewOffsetX);
	Viewport.SetCharacterOffsetY(questNpcPortraitUIData.ViewOffsetY);
	Viewport.SetCharacterOffsetZ(questNpcPortraitUIData.ViewOffsetZ);
	Viewport.SetCurrentRotation(questNpcPortraitUIData.ViewRotationYaw);
	Viewport.SetCharacterScale(questNpcPortraitUIData.ViewScale);
	Viewport.SpawnNPC();	
}

private function ShowQuest(optional bool isfullDialog)
{
	local NQuestUIData questUIData;
	local NQuestDialogUIData questDialogUIData;
	local UserInfo uInfo;

	if(GetGameStateName() == "COLLECTIONSTATE")
	{
		return;
	}
	tObjectDist._Pause();
	lastAcceptedQuestID = -1;
	_currentQuestID = qDatas[0].QuestID;
	_currentDialogType = qDatas[0].dialogType;
	SetCurrentNPcLoc();
	API_GetNQuestData(_currentQuestID, questUIData);
	if(! GetPlayerInfo(uInfo))
	{
		_NextShowQuest();
		return;
	}
	switch(_currentDialogType)
	{
		case 1:
		case 2:
			if((questUIData.LevelMin > 0) && questUIData.LevelMin > uInfo.nLevel)
			{
				_NextShowQuest();
				return;
			}
			if((questUIData.LevelMax > 0) && questUIData.LevelMax < uInfo.nLevel)
			{
				_NextShowQuest();
				return;
			}
	}

	m_hOwnerWnd.ShowWindow();
	m_hOwnerWnd.SetFocus();
	textBox.SetText(questUIData.Name);
	SetPortrait(questUIData);
	API_GetNQuestDialogData(_currentQuestID, questDialogUIData);
	SetDialog(questDialogUIData, isfullDialog);
	SetConfirmBtn(questUIData);
	SetDistanceCheck(isfullDialog);
}

private function SetConfirmBtn(NQuestUIData questUIData)
{
	CancelBtn.EnableWindow();
	switch(_currentDialogType)
	{
		case 1:
			confirmBtn.ShowWindow();
			confirmBtn.SetButtonName(900);
			CancelBtn.SetButtonName(14180);
			if(IsMainCurrent())
			{
				CancelBtn.DisableWindow();
			}
			break;
		case 2:
			confirmBtn.ShowWindow();
			confirmBtn.SetButtonName(7422);
			CancelBtn.SetButtonName(14180);
			if(IsMainCurrent())
			{
				CancelBtn.DisableWindow();
			}
			break;
		case 3:
			confirmBtn.ShowWindow();
			confirmBtn.SetButtonName(900);
			CancelBtn.SetButtonName(14180);
			break;
		case 4:
			confirmBtn.ShowWindow();
			confirmBtn.SetButtonName(898);
			CancelBtn.SetButtonName(646);
			break;
		case 5:
			confirmBtn.HideWindow();
			CancelBtn.SetButtonName(646);
			break;
	}
	if(currentHelpIndex > 0)
	{
		helpBtn.ShowWindow();		
	}
	else
	{
		helpBtn.HideWindow();
	}	
}

private function SetDialog(NQuestDialogUIData questDialogUIData, optional bool isfullDialog)
{
	local int firstIndex;
	local string tmpDialog;

	tObjectTalk._Pause();
	tmpDialog = GetCurrentDialog(questDialogUIData);
	firstIndex = InStr(tmpDialog, DIALOG_CLASSCHANGE_KEY);
	if(firstIndex > -1)
	{
		class'UIAPI_WINDOW'.static.ShowWindow("JobChangeWnd");
		tmpDialog = Left(tmpDialog, firstIndex);
	}
	firstIndex = InStr(tmpDialog, DIALOG_HELP_KEY);
	if(firstIndex > -1)
	{
		dialog = Left(tmpDialog, firstIndex);
		currentHelpIndex = int(Right(tmpDialog, (Len(tmpDialog) - firstIndex) - Len(DIALOG_HELP_KEY)));		
	}
	else
	{
		dialog = tmpDialog;
		currentHelpIndex = -1;
	}
	if(isfullDialog)
	{
		textBoxList.AddString(dialog, GetColor(199, 199, 199, 255));		
	}
	else
	{
		tObjectTalk._Play();
	}
}

private function string GetCurrentDialog(NQuestDialogUIData questDialogUIData)
{
	switch(_currentDialogType)
	{
		case 1:
			return questDialogUIData.StartDialog;
		case 2:
			return questDialogUIData.AcceptDialog;
		case 3:
			return questDialogUIData.CompleteDialog;
		case 4:
			return questDialogUIData.EndDialog;
		case 5:
			return questDialogUIData.AcceptDialog;
	}
	return "";
}

private function SetDistanceCheck(optional bool isfullDialog)
{
	switch(_currentDialogType)
	{
		case 1:
		case 3:
		case 5:
			return;
	}
	if((GetCurrentNPCTeleportID()) < 0)
	{
		return;
	}
	tObjectDist._Play();
	if(isfullDialog)
	{
		return;
	}
	if(class'UIDATA_TARGET'.static.GetTargetClassID() == GetCurrentNPCData().Id)
	{
		return;
	}
	ExecuteCommand("/target" @ (API_GetNPCName(GetCurrentNPCData().Id)));
}

private function SetCurrentNPcLoc()
{
	switch(_currentDialogType)
	{
		case 1:
		case 2:
			qDatas[0].npcLoc = GetCurrentNPCData().Location;
			break;
		case 3:
		case 4:
			qDatas[0].npcLoc = GetCurrentNPCData().Location;
			break;
	}
}

function _NextShowQuest()
{
	m_hOwnerWnd.HideWindow();
	DelQuest(0);
	if(qDatas.Length == 0)
	{
		return;
	}
	ShowQuest();	
}

function _ConfirmQuest()
{
	switch(_currentDialogType)
	{
		case 2:
			RQ_C_EX_QUEST_ACCEPT(true);
			break;
		case 4:
			RQ_C_EX_QUEST_COMPLETE();
			break;
	}
	_NextShowQuest();	
}

function _SohwDialogAgain(int QuestID)
{
	local questData qData;

	qData.QuestID = QuestID;
	qData.dialogType = 5;
	switch(qDatas.Length)
	{
		case 0:
			if(AddQuestData(qData))
			{
				ShowQuest();
				return;
			}
			break;
		case 1:
			if(qDatas[0].dialogType == 5)
			{
				if(AddQuestData(qData))
				{
					_NextShowQuest();
					return;
				}
			}
			break;
	}
	getInstanceL2Util().showGfxScreenMessage(GetSystemMessage(13822));	
}

private function HandleTimerOnStart()
{
	textBoxList.Clear();	
}

private function HandleTimerOnTime(int t)
{
	local int addStringLen;

	textBoxList.Clear();
	addStringLen = (t + 1) * 2;
	if(addStringLen < Len(dialog))
	{
		textBoxList.AddString(Left(dialog, addStringLen), GetColor(199, 199, 199, 255));
		return;		
	}
	else
	{
		tObjectTalk._Stop();
		textBoxList.AddString(dialog, GetColor(199, 199, 199, 255));
		dialog = "";
	}
}

function _ShowStartDialog(int QuestID)
{
	local questData qData;
	local NQuestUIData o_data;

	if(qDatas.Length > 0)
	{
		getInstanceL2Util().showGfxScreenMessage(GetSystemMessage(13822));
		return;
	}
	qData.QuestID = QuestID;
	if(! API_GetNQuestData(QuestID, o_data))
	{
		return;
	}
	if(CheckDistanceToStart(QuestID))
	{
		qData.dialogType = 1;		
	}
	else
	{
		qData.dialogType = 2;
	}
	if(AddQuestData(qData))
	{
		if(qDatas.Length == 1)
		{
			ShowQuest();
		}
	}
}

function _ShowCompleteDialog(int QuestID, optional bool bClicked)
{
	local questData qData;
	local NQuestUIData o_data;

	if(qDatas.Length > 0 && bClicked)
	{
		getInstanceL2Util().showGfxScreenMessage(GetSystemMessage(13822));
		return;
	}
	qData.QuestID = QuestID;
	if(! API_GetNQuestData(QuestID, o_data))
	{
		return;
	}
	if(CheckDistanceToComplete(QuestID))
	{
		qData.dialogType = 3;		
	}
	else
	{
		qData.dialogType = 4;
	}
	if(AddQuestData(qData))
	{
		if(qDatas.Length == 1)
		{
			ShowQuest();
		}
	}	
}

private function bool CheckDistanceToStart(int qID)
{
	local UserInfo uInfo;
	local NQuestUIData questUIData;
	local int dist;

	API_GetNQuestData(qID, questUIData);
	if(questUIData.StartNPC.TeleportID < 1)
	{
		return false;
	}
	GetPlayerInfo(uInfo);
	dist = Distance(uInfo.Loc, questUIData.StartNPC.Location);
	Debug(("CheckDistanceToStart" @ string(Distance(uInfo.Loc, questUIData.StartNPC.Location))) @ string(250));
	if(dist < 0)
	{
		return true;
	}
	return dist > 250;	
}

private function bool CheckDistanceToComplete(int qID)
{
	local UserInfo uInfo;
	local NQuestUIData questUIData;
	local int dist;

	API_GetNQuestData(qID, questUIData);
	if(questUIData.EndNPC.TeleportID < 1)
	{
		return false;
	}
	GetPlayerInfo(uInfo);
	dist = Distance(uInfo.Loc, questUIData.EndNPC.Location);
	Debug("CheckDistanceToComplete" @ string(Distance(uInfo.Loc, questUIData.EndNPC.Location)) @ string(250));
	if(dist < 0)
	{
		return true;
	}
	return dist > 250;	
}

private function HandleNewQuestData(int QuestID, int dialogType)
{
	local questData qData;

	qData.QuestID = QuestID;
	qData.dialogType = dialogType;
	if(AddQuestData(qData))
	{
		if(qDatas.Length == 1)
		{
			ShowQuest();
		}
	}
}

function bool _IsDialogAgain()
{
	return qDatas[0].dialogType == 5;	
}

private function int GetQuestIndex(questData qData)
{
	local int i;

	for(i = 0; i < qDatas.Length; i++)
	{
		if((qDatas[i].QuestID == qData.QuestID) && qDatas[i].dialogType == qData.dialogType)
		{
			return i;
		}
	}
	return -1;	
}

private function bool AddQuestData(questData qData)
{
	local int Index;

	Index = GetQuestIndex(qData);
	if(Index != -1)
	{
		return false;
	}
	qDatas[qDatas.Length] = qData;
	return true;	
}

private function DelQuestData(questData qData)
{
	local int Index;

	Index = GetQuestIndex(qData);
	if(Index != -1)
	{
		DelQuest(Index);
	}
}

private function DelQuest(int Index)
{
	_currentQuestID = -1;
	_currentDialogType = -1;
	dialog = "";
	if(qDatas.Length <= Index)
	{
		return;
	}
	qDatas.Remove(Index, 1);	
}

private function bool CurrentDataDistChk()
{
	local UserInfo uInfo;
	local int dist;

	switch(_currentDialogType)
	{
		case 1:
		case 3:
		case 5:
			return true;
		case 2:
		case 4:
			break;
	}
	GetPlayerInfo(uInfo);
	dist = Distance(uInfo.Loc, qDatas[0].npcLoc);
	if(dist < 0)
	{
		return false;
	}
	return dist < 250;	
}

private function HandleOnTimeUpdateLocChk(int t)
{
	if(CurrentDataDistChk())
	{
		return;
	}
	_NextShowQuest();	
}

private function bool IsMainCurrent()
{
	return qDatas[0].QuestID < QUEST_CATEGORY_SUB;	
}

private function int Distance(Vector locA, Vector locB)
{
	local int gabX, gabY, gabZ;

	gabX = int(locA.X - locB.X);
	gabY = int(locA.Y - locB.Y);
	gabZ = int(locA.Z - locB.Z);
	return int(Sqrt(float(((gabX * gabX) + (gabY * gabY)) + (gabZ * gabZ))));	
}

function int _GetCurrentTeleportID()
{
	local NQuestUIData questUIData;

	API_GetNQuestData(_currentQuestID, questUIData);
	return questUIData.TeleportID;	
}

private function int GetCurrentNPCTeleportID()
{
	return GetCurrentNPCData().TeleportID;	
}

private function NQuestNPCData GetCurrentNPCData()
{
	local NQuestUIData questUIData;

	API_GetNQuestData(_currentQuestID, questUIData);
	switch(_currentDialogType)
	{
		case 1:
		case 2:
		case 5:
			return questUIData.StartNPC;
		case 3:
		case 4:
			return questUIData.EndNPC;
	}
}

private function bool CheckDrag()
{
	local int X, Y, gabX, gabY;

	GetClientCursorPos(X, Y);
	gabX = X - clickedX;
	gabY = Y - clickedY;
	return Sqrt(float((gabX * gabX) + (gabY * gabY))) > 1;	
}

private function RT_S_EX_QUEST_DIALOG()
{
	local UIPacket._S_EX_QUEST_DIALOG packet;

	if(! class'UIPacket'.static.Decode_S_EX_QUEST_DIALOG(packet))
	{
		return;
	}
	HandleNewQuestData(packet.nID, packet.cDialogType);	
}

private function RQ_C_EX_QUEST_TELEPORT()
{
	local array<byte> stream;
	local UIPacket._C_EX_QUEST_TELEPORT packet;

	packet.nID = _currentQuestID;
	if(! class'UIPacket'.static.Encode_C_EX_QUEST_TELEPORT(stream, packet))
	{
		return;
	}
	class'UIPacket'.static.RequestUIPacket(class'UIPacket'.const.C_EX_QUEST_TELEPORT, stream);	
}

private function RQ_C_EX_QUEST_ACCEPT(optional bool bAccept)
{
	local array<byte> stream;
	local UIPacket._C_EX_QUEST_ACCEPT packet;

	lastAcceptedQuestID = _currentQuestID;
	packet.nID = _currentQuestID;
	if(bAccept)
	{
		packet.bAccept = 1;		
	}
	else
	{
		packet.bAccept = 0;
	}
	if(! class'UIPacket'.static.Encode_C_EX_QUEST_ACCEPT(stream, packet))
	{
		return;
	}
	class'UIPacket'.static.RequestUIPacket(class'UIPacket'.const.C_EX_QUEST_ACCEPT, stream);	
}

private function RQ_C_EX_QUEST_COMPLETE()
{
	local array<byte> stream;
	local UIPacket._C_EX_QUEST_COMPLETE packet;

	packet.nID = _currentQuestID;
	if(! class'UIPacket'.static.Encode_C_EX_QUEST_COMPLETE(stream, packet))
	{
		return;
	}
	class'UIPacket'.static.RequestUIPacket(class'UIPacket'.const.C_EX_QUEST_COMPLETE, stream);	
}

private function string API_GetNPCName(int NpcID)
{
	if(NpcID == -1)
	{
		return "?";
	}
	return class'UIDATA_NPC'.static.GetNPCName(NpcID);	
}

private function bool API_GetNQuestData(int a_QuestID, out NQuestUIData o_data)
{
	return GetNQuestData(a_QuestID, o_data);	
}

private function bool API_GetNQuestDialogData(int a_QuestID, out NQuestDialogUIData o_data)
{
	return GetNQuestDialogData(a_QuestID, o_data);	
}

private function bool API_GetNQuestNpcPortraitData(int a_NpcID, out NQuestNpcPortraitUIData o_data)
{
	return GetNQuestNpcPortraitData(1000000 + a_NpcID, o_data);	
}
