
local L = AceLibrary("AceLocale-2.2"):new("Cartographer_Quests")
local Dewdrop = AceLibrary("Dewdrop-2.0")

L:RegisterTranslations("enUS", function() return {

	["Quests"] = true,
	["Filter"] = true,
	["Filter out quests"] = true,

	["Module description"] = "Questgiver mapnotes for Cartographer",

	["Select all"] = true,
	["Select none"] = true,

	["Icon alpha"] = true,
	["Alpha transparency of the icon"] = true,
	["Icon size"] = true,
	["Size of the icons on the map"] = true,
	["Show minimap icons"] = true,
	["Show quest icons on the minimap"] = true,

	["Quest"] = true,
 	["Quest Giver"] = true,

	-- Updating messages
	["Note %q dropped due to incompatble version (%q)."] = true,
	["Upgrading quest database"] = true,
	["Quest database upgraded to current version."] = true,
	["Quest database could not be upgraded to current version."] = true,
	
	-- Note dewdrop
	['Quest status'] = true,
	['Quest log based'] = true,
	['The status of this quest can not be changed as it is directly related to your quest log.'] = true,	
	['Status based on quest log'] = true,
	['Change quest status to this new value.'] = true,
	['Delete quest'] = true,
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = true,

	-- Filters
	["Active quests"] = true,
	["Available quests"] = true,
	["Complete quests"] = true,
	["Failed quests"] = true,
	["Trivial quests"] = true,
	["Unavailable quests"]= true,
	["Done quests"] = true,
	["Repeatable quests"] = true,
	["Notes of previous version"] = true,

	-- Icons
	["Active quest"] = true,
	["Available quest"] = true,
	["Unavailable quest"] = true,
	["Complete quest"] = true,
	["Repeatable quest"] = true,

	["Statuses"] = {
		unavailable = "Unavailable",
		trivial     = "Trivial",
		available   = "Available",
		active      = "Active",
		complete    = "Complete",
		failed      = "Failed",
		done        = "Done",
		repeatable  = "Repeatable",
	},

} end)

L:RegisterTranslations("frFR", function() return {

	["Quests"] = "Qu\195\170tes",
	["Filter"] = "Filtrer",
	["Filter out quests"] = "Limiter les PNJ affich\195\169s",

	["Module description"] = "Afficher la position des PNJ de qu\195\170te avec Cartographer",

	["Select all"] = "S\195\169lectionner tou(te)s",
	["Select none"] = "S\195\169lectionner aucun(e)",

	["Icon alpha"] = "Transparence",
	["Alpha transparency of the icon"] = "Transparences des notes sur la carte",
	["Icon size"] = "Taille",
	["Size of the icons on the map"] = "Taille des notes sur la carte",
	["Show minimap icons"] = "Afficher les notes sur la minicarte",
	["Show quest icons on the minimap"] = "Affiche les notes de qu\195\170tes sur la minicarte",

	["Quest"] = "Qu\195\170te",
 	["Quest Giver"] = "PNJ de qu\195\170te",

	-- Note dewdrop
	['Quest status'] = 'Etat de la qu\195\170te',
	['Quest log based'] = 'Bas\195\169 sur le journal des qu\195\170tes',
	['The status of this quest can not be changed as it is directly related to your quest log.'] = 
		"L'\195\169tat de la qu\195\170te ne peut pas \195\170tre modifi\195\169 car il d\195\169pend de votre journal de qu\195\170tes.",	
	['Change quest status to this new value.'] = 
		"Change l'\195\170tat de la qu\195\170te pour cette nouvelle valeur.",
	['Delete quest'] = "Supprimer la qu\195\170te",
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = "ATTENTION: CELA NE PEUT PAS ETRE ANNULE.",

	-- Filters
	["Active quests"] = "Qu\195\170tes en cours",
	["Available quests"] = "Qu\195\170tes disponibles",
	["Complete quests"] = "Qu\195\170tes termin\195\169es",
	["Failed quests"] = "Qu\195\170tes \195\169chou\195\169es",
	["Trivial quests"] = "Qu\195\170tes 'grises'",
	["Unavailable quests"]= "Qu\195\170tes indisponibles",
	["Done quests"] = "Qu\195\170tes faites",
	["Repeatable quests"] = "Qu\195\170tes r\195\169p\195\169tables",
	["Notes of previous version"] = "Notes d'une version pr\195\169c\195\169dentes",

	-- Icons
	["Active quest"] = "Qu\195\170te en cours",
	["Available quest"] = "Qu\195\170te disponible",
	["Unavailable quest"] = "Qu\195\170te indisponible",
	["Complete quest"] = "Qu\195\170te termin\195\169e",

	["Statuses"] = {
		unavailable = "Indisponible",
		trivial     = "Grise",
		available   = "Disponible",
		active      = "En cours",
		complete    = "Termin\195\169e",
		failed      = "Echec",
		done        = "Faite",
		repeatable  = "R\195\169p\195\169table",
	},

} end)

L:RegisterTranslations("koKR", function() return {

	["Quests"] = "퀘스트",
	["Filter"] = "항목 분류",
	["Filter out quests"] = "퀘스트를 항목에 따라 분류하여 표시합니다.",

	["Module description"] = "맵노트에 퀘스트 제공자를 표시합니다.",

	["Select all"] = "모두 선택",
	["Select none"] = "선택 없음",

	["Icon alpha"] = "아이콘 투명도",
	["Alpha transparency of the icon"] = "아이콘의 투명도를 조절합니다.",
	["Icon size"] = "아이콘 크기",
	["Size of the icons on the map"] = "아이콘의 크기를 조절합니다.",
	["Show minimap icons"] = "미니맵 아이콘 보기",
	["Show quest icons on the minimap"] = "미니맵에 퀘스트 제공자 아이콘을 표시합니다.",

	["Quest"] = "퀘스트",
	["Quest Giver"] = "퀘스트 제공자",

	-- Updating messages
--	["Note %q dropped due to incompatble version (%q)."] = true,
	["Upgrading quest database"] = "퀘스트 정보가 업데이트 되었습니다.",
	["Quest database upgraded to current version."] = "퀘스트 정보를 업데이트하고 있습니다.",
	["Quest database could not be upgraded to current version."] = "퀘스트 정보를 업데이트할 수 없습니다.",
	
	-- Note dewdrop
	['Quest status'] = "퀘스트 상태",
	['Quest log based'] = "퀘스트 로그 기반",
	['The status of this quest can not be changed as it is directly related to your quest log.'] = "퀘스트의 상태는 임의로 변경할 수 없습니다.",	
	['Status based on quest log'] = "퀘스트 로그를 기반으로 한 상태",
	['Change quest status to this new value.'] = "퀘스트 상태를 다른 값으로 바꿉니다.",
	['Delete quest'] = "퀘스트 삭제",
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = "퀘스트를 삭제합니다. 경고 : 되돌릴 수 없습니다.",

	-- Filters
	["Active quests"] = "활성화된 퀘스트",
	["Available quests"] = "가능한 퀘스트",
	["Complete quests"] = "완료한 퀘스트",
	["Failed quests"] = "실패한 퀘스트",
	["Trivial quests"] = "일반 퀘스트",
	["Unavailable quests"]= "불가능한 퀘스트",
	["Done quests"] = "확인된 퀘스트",
	["Repeatable quests"] = "반복 퀘스트",
	["Notes of previous version"] = "이전 버전의 노트",

	-- Icons
	["Active quest"] = "활성화된 퀘스트",
	["Available quest"] = "가능한 퀘스트",
	["Unavailable quest"] = "불가능한 퀘스트",
	["Complete quest"] = "완료한 퀘스트",
	["Repeatable quest"] = "반복 퀘스트",

	["Statuses"] = {
		unavailable = "불가능",
		trivial     = "일반",
		available   = "가능",
		active      = "활성화",
		complete    = "완료",
		failed      = "실패",
		done        = "확인",
		repeatable  = "반복",
	},
} end)

L:RegisterTranslations("deDE", function() return {

	["Quests"] = "Quests",
	["Filter"] = "Filter",
	["Filter out quests"] = "Quests filtern",

	["Module description"] = "Questgeber-Kartennotizen f\195\188r Cartographer",

	["Select all"] = "Alles ausw\195\164hlen",
	["Select none"] = "Nichts ausw\195\164hlen",

	["Icon alpha"] = "Transparenz",
	["Alpha transparency of the icon"] = "Transparenz der Symbole",
	["Icon size"] = "Symbolgr\195\182\195\159e",
	["Size of the icons on the map"] = "Gr\195\182\195\159e der Symbole auf der Weltkarte",
	["Show minimap icons"] = "Zeige Minimap-Symbole",
	["Show quest icons on the minimap"] = "Zeige Questsymbole auf der Minimap.",

	["Quest"] = "Quest",
	["Quest Giver"] = "Questgeber",

  	-- Updating messages
	["Note %q dropped due to incompatble version (%q)."] = "Notiz %q wegen inkompatibler Version (%q) verworfen.",
	["Upgrading quest database"] = "Aktualisiere Questdatenbank.",
	["Quest database upgraded to current version."] = "Questdatenbank auf aktuelle Version aktualisiert.",
	["Quest database could not be upgraded to current version."] = "Questdatenbank konnte nicht aktualisiert werden.",

	-- Note dewdrop
	['Quest status'] = "Queststatus",
	['Quest log based'] = "Basiert auf dem Questlog",
	['The status of this quest can not be changed as it is directly related to your quest log.'] = "Der Status dieser Quest kann nicht ge\195\164ndert werden, da er direkt von Deinem Questlog abh\195\164ngt.",	
	['Status based on quest log'] = "Status basiert auf dem Eintrag im Questlog",
	['Change quest status to this new value.'] = "Queststatus auf diesen Wert \195\164ndern",
	['Delete quest'] = "Quest l\195\182schen",
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = "Diese Quest l\195\182schen. ACHTUNG: DIESER VORGANG KANN NICHT R\195\165CKG\195\132NGIG GEMACHT WERDEN!",
  
	-- Filters
	 ["Active quests"] = "Aktive Quests",
	 ["Available quests"] = "Verf\195\188gbare Quests",
	 ["Complete quests"] = "Abgeschlossene Quests",
	 ["Failed quests"] = "Fehlgeschlagene Quests",
	 ["Trivial quests"] = "Trivale Quests",
	 ["Unavailable quests"]= "Nicht verf\195\188gbare Quests",
	 ["Notes of previous version"] = "Notizen vorheriger Versionen",

	-- Icons
	 ["Active quest"] = "Aktive Quest",
	 ["Available quest"] = "Verf\195\188gbare Quest",
	 ["Unavailable quest"] = "Nicht verf\195\188gbare Quest",
	 ["Complete quest"] = "Abgeschlossene Quest",
   
   	["Statuses"] = {
		unavailable = "Nicht verf\195\188gbar",
		trivial     = "Trivial",
		available   = "Verf\195\188gbar",
		active      = "Aktiv",
		complete    = "Fertig",
		failed      = "Fehlgeschlagen",
		done        = "Abgeschlossen",
		repeatable  = "Wiederholbar",
	},

} end)

L:RegisterTranslations("zhTW", function() return {

	["Quests"] = "任務",
	["Filter"] = "篩選",
	["Filter out quests"] = "篩選任務",

	["Module description"] = "在地圖上註記任務起始和結束位置",

	["Select all"] = "全部選擇",
	["Select none"] = "全部取消",

	["Icon alpha"] = "圖示透明度",
	["Alpha transparency of the icon"] = "設定圖示透明度",
	["Icon size"] = "圖示大小",
	["Size of the icons on the map"] = "設定圖示在地圖上的大小",
	["Show minimap icons"] = "在小地圖上顯示",
	["Show quest icons on the minimap"] = "將任務圖示顯示在小地圖上",

	["Quest"] = "任務",
	["Quest Giver"] = "任務委託人",

	-- Updating messages
	["Note %q dropped due to incompatble version (%q)."] = "標記 %q 因為版本不相容而被移除 (%q)。",
	["Upgrading quest database"] = "更新任務資料庫",
	["Quest database upgraded to current version."] = "任務資料庫已更新完成。",
	["Quest database could not be upgraded to current version."] = "任務資料庫無法更新。",
	
	-- Note dewdrop
	['Quest status'] = "任務狀態",
	['Quest log based'] = "基於任務紀錄",
	['The status of this quest can not be changed as it is directly related to your quest log.'] = "這個任務的狀態無法被修改，因為其直接與任務記錄相關聯",	
	['Status based on quest log'] = "任務狀態和任務紀錄同步",
	['Change quest status to this new value.'] = "改變任務狀態",
	['Delete quest'] = "刪除任務",
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = "刪除這個任務，這個動作是不可回復的",

	-- Filters
	["Active quests"] = "進行中的任務",
	["Available quests"] = "可接的任務",
	["Complete quests"] = "完成的任務",
	["Failed quests"] = "失敗的任務",
	["Trivial quests"] = "簡易的任務",
	["Unavailable quests"]= "不可接的任務",
	["Done quests"] = "結束的任務",
	["Repeatable quests"] = "可重複的任務",
	["Notes of previous version"] = "舊版本的標記",

	-- Icons
	["Active quest"] = "進行中的任務",
	["Available quest"] = "可接的任務",
	["Unavailable quest"] = "不可接的任務",
	["Complete quest"] = "完成的任務",
	["Repeatable quest"] = "可重複的任務",

	["Statuses"] = {
		unavailable = "不可接",
		trivial     = "簡易",
		available   = "可接",
		active      = "進行中",
		complete    = "完成",
		failed      = "失敗",
		done        = "結束",
		repeatable  = "重複",
	},
} end)

L:RegisterTranslations("esES", function() return {

	["Quests"] = "Misiones",
	["Filter"] = "Filtrar",
	["Filter out quests"] = "Filtra misiones",

	["Module description"] = "Notas de mapa de proveedores de misi\195\179n para Cartographer",

	["Select all"] = "Seleccionar todo",
	["Select none"] = "No seleccionar nada",

	["Icon alpha"] = "Transparencia de icono",
	["Alpha transparency of the icon"] = "Transparencia del icono",
	["Icon size"] = "Tama\195\177o del icono",
	["Size of the icons on the map"] = "Tama\195\177o de los iconos en el mapa",
	["Show minimap icons"] = "Mostrar iconos en minimapa",
	["Show quest icons on the minimap"] = "Muestra los iconos de misiones en el minimapa",

	["Quest"] = "Misi\195\179n",
	["Quest Giver"] = "Proveedor de misi\195\179n",

	-- Updating messages
	["Note %q dropped due to incompatble version (%q)."] = "La nota %q ha sido eliminada debido a que su versi\195\179n no es compatible (%q).",
	["Upgrading quest database"] = "Actualizando la base de datos de misiones",
	["Quest database upgraded to current version."] = "Actualizando la base de datos de misiones a la versi\195\179n actual.",
	["Quest database could not be upgraded to current version."] = "La base de datos de misiones no ha podido ser actualizada a la versi\195\179n actual.",
	
	-- Note dewdrop
	['Quest status'] = "Estado de la misi\195\179n",
	['Quest log based'] = "Basado en el registro de misiones",
	['The status of this quest can not be changed as it is directly related to your quest log.'] = "El estado de esta misi\195\179n no puede ser cambiado ya que est\195\161 directamente relacionada con tu registro de misiones",	
	['Status based on quest log'] = "Estado basando en el registro de misiones",
	['Change quest status to this new value.'] = "Cambia el estado de la misi\195\179n a este nuevo valor.",
	['Delete quest'] = "Eliminar misi\195\179n",
	['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'] = "Elimina la misi\195\179n. AVISO: ESTO NO SE PUEDE DESHACER.",

 	-- Filters
	["Active quests"] = "Misiones activas",
	["Available quests"] = "Misiones disponibles",
	["Complete quests"] = "Misiones completadas",
	["Failed quests"] = "Misiones falladas",
	["Trivial quests"] = "Misiones triviales", -- ?
	["Unavailable quests"]= "Misiones no disponibles",
	["Done quests"] = "Misiones terminadas",
	["Repeatable quests"] = "Misiones repetibles",
	["Notes of previous version"] = "Notas de la versi\195\179n anterior",

	-- Icons
	["Active quest"] = "Misi\195\179n activa",
	["Available quest"] = "Misi\195\179n disponible",
	["Unavailable quest"] = "Misi\195\179n no disponible",
	["Complete quest"] = "Misi\195\179n completada",

	["Statuses"] = {
		unavailable = "No disponible",
		trivial     = "Trivial",
		available   = "Disponible",
		active      = "Activa",
		complete    = "Completada",
		failed      = "Fallada",
		done        = "Terminada",
		repeatable  = "Repetible",
	},
} end)

local Tablet = AceLibrary("Tablet-2.0")
local BZ = AceLibrary("Babble-Zone-2.2")

local Cartographer_Quests = Cartographer:NewModule("Quests", "AceConsole-2.0", "AceEvent-2.0", "AceDB-2.0", "AceHook-2.1")
if AceLibrary:HasInstance("AceDebug-2.0") then
	AceLibrary("AceDebug-2.0"):embed(Cartographer_Quests)
	QN = Cartographer_Quests
	--QN:SetDebugging(true)
else
	function Cartographer_Quests:Debug() end
	function Cartographer_Quests:SetDebugging() end
end
Cartographer_Quests.revision = tonumber(string.sub("$Revision: 35243 $", 12, -3))
Cartographer_Quests.version = "r" .. Cartographer.revision
Cartographer_Quests.date = string.sub("$Date: 2007-05-13 05:38:44 +0900 (일, 13 5 2007) $", 8, 17)

Cartographer_Quests:RegisterDB("Cartographer_QuestsDB", "Cartographer_QuestsDBPC")

local ICON_NAME = "Quest"
local DB_NAME = "Quests"
local DB_VERSION = 4
local DB_COMPAT_VERSION = 1

Cartographer_Quests.filter = {
	unavailable = L["Unavailable quests"],
	trivial     = L["Trivial quests"],
	available   = L["Available quests"],
	active      = L["Active quests"],
	complete    = L["Complete quests"],
	failed      = L["Failed quests"],
	done        = L["Done quests"],
	repeatable  = L["Repeatable quests"],
	obsolete		= L["Notes of previous version"],
}

Cartographer_Quests.icon = {
	[ICON_NAME] = {
		text = L["Quest"],
		path = "Interface\\AddOns\\Cartographer_Quests\\Artwork\\INV_Misc_Book_08",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-unavailable'] = { -- grey "!"
		text = L["Unavailable quest"],
		path = "Interface\\AddOns\\Cartographer_Quests\\Artwork\\UnavailableQuestIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-available'] = { -- yellow "!"
		text = L["Available quest"],
		path = "Interface\\GossipFrame\\AvailableQuestIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-active'] = {  -- gray "?"
		text = L["Active quest"],
		path = "Interface\\AddOns\\Cartographer_Quests\\Artwork\\ActiveQuestIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-complete'] = { -- yellow "?"
		text = L["Complete quest"],
		path = "Interface\\GossipFrame\\ActiveQuestIcon",
		width = 14,
		height = 14
	},
	[ICON_NAME..'-repeatable'] = { -- blue "?"
		text = L["Repeatable quest"],
		path = "Interface\\AddOns\\Cartographer_Quests\\Artwork\\RepeatableQuestIcon",
		width = 14,
		height = 14
	},
}

function Cartographer_Quests:OnInitialize()

	self:RegisterDefaults("profile", {
		filter = {
			unavailable = false,
			trivial     = false,
			available   = true,
			active      = true,
			complete    = true,
			failed      = true,
			done        = false,
			repeatable  = true,
			obsolete		= true,
		},
		iconAlpha = 1,
		iconScale = 1,
		minimapIcons = true,
	})

	self:RegisterDefaults("faction", {
		questCount = 0,
		quests = {},
		notes = {},
		givers = {
			['*'] = { -- zone
				['*'] = { -- giver
				},
			},
		},
	})

	self:RegisterDefaults("char", {
		questHistory = {}
	})

	local aceopts = {
		toggle = {
			name = AceLibrary("AceLocale-2.2"):new("Cartographer")["Enabled"],
			desc = AceLibrary("AceLocale-2.2"):new("Cartographer")["Suspend/resume this module."],
			type  = 'toggle',
			order = 10,
			get   = function() return Cartographer:IsModuleActive(self) end,
			set   = function() Cartographer:ToggleModuleActive(self) end,
		},
		alpha = {
			name = L["Icon alpha"],
			desc = L["Alpha transparency of the icon"],
			type = 'range',
			min = 0.1,
			max = 1,
			step = 0.01,
			bigStep = 0.05,
			isPercent = true,
			get = "GetIconAlpha",
			set = "SetIconAlpha",
			order = 20
		},
		scale = {
			name = L["Icon size"],
			desc = L["Size of the icons on the map"],
			type = 'range',
			min = 0.5,
			max = 2,
			step = 0.01,
			bigStep = 0.05,
			isPercent = true,
			get = "GetIconScale",
			set = "SetIconScale",
			order = 30
		},
		minimapicons = {
			name = L["Show minimap icons"],
			desc = L["Show quest icons on the minimap"],
			type = 'toggle',
			set = "ToggleShowingMinimapIcons",
			get = "IsShowingMinimapIcons",
			order = 40,
		},
		filter = {
			name = L["Filter"],
			desc = L["Filter out quests"],
			type = 'group',
			order = 50,
			args = {
				all = {
					name = L["Select all"],
					desc = L["Select all"],
					type = 'execute',
					func = function()
						for k in pairs(self.filter) do
							self:ToggleShowingQuests(k, true)
						end
					end,
					order = 1,
				},
				none = {
					name = L["Select none"],
					desc = L["Select none"],
					type = 'execute',
					func = function()
						for k in pairs(self.filter) do
							self:ToggleShowingQuests(k, false)
						end
					end,
					order = 2,
				},
				blank = {
					type = 'header',
					order = 3,
				}
			}
		}
	}

	local i = 1
	for k,v in pairs(self.filter) do
		local key,name = k,v
		aceopts.filter.args[key] = {
			name = name,
			desc = name,
			type = 'toggle',
			order = 100 + i,
			get = function()
				return self:IsShowingQuests(key)
			end,
			set = function(value)
				return self:ToggleShowingQuests(key, value)
			end,
		}
		i = i + 1
	end

	Cartographer.options.args["quests"] = {
		name = L["Quests"],
		desc = L["Module description"],
		type = 'group',
		args = aceopts,
		handler = self,
	}

end

function Cartographer_Quests:OnEnable(first)
	if not Cartographer_Notes then
		return Cartographer:ToggleModuleActive(self, false)
	end

	if first then
		self:UpgradeDatabase()
	end
	
	for name,data in pairs(self.icon) do
		Cartographer_Notes:RegisterIcon(name,data)
	end
	Cartographer_Notes:RegisterNotesDatabase(DB_NAME, self.db.faction.notes, self)

	self:RegisterEvent("GOSSIP_SHOW", "ScanGossip")
	self:RegisterEvent("QUEST_DETAIL", "RegisterQuestFromDetail")
	self:RegisterEvent("QUEST_PROGRESS", "RegisterQuestFromDetail")
	self:RegisterEvent("QUEST_LOG_UPDATE", "ScanQuestLog")
	self:RegisterEvent("QUEST_COMPLETE", "WatchQuestCompletion")

	self:Debug('Cartographer_Quests enabled')
	
	Cartographer_Notes:RefreshMap(true)
end

function Cartographer_Quests:OnDisable()
	Cartographer_Notes:UnregisterNotesDatabase(DB_NAME)
	for name in pairs(self.icon) do
		Cartographer_Notes:UnregisterIcon(name)
	end

	self:Debug('Cartographer_Quests disabled')

	Cartographer_Notes:RefreshMap(true)
end

--------------------------
-- Database opertations --
--------------------------

local questTable = setmetatable({}, {
	__index = function(table, key)
		local f = Cartographer_Quests.db.faction
		if type(key) == 'number' then
			for title,id in pairs(f.quests) do
				if key == title then
					table[key] = title
					return title
				end
			end
		elseif type(key) == 'string' then
			local id = f.quests[key]
			if not id then
				id = f.questCount + 1
				f.quests[key] = id
				f.questCount = id
			end
			table[key] = id
			return id
		end
	end
})
Cartographer_Quests.questTable = questTable

local function TidyNote(note)	
	if type(note) ~= 'table' or note.info == 'Quest Giver' or not note.title or note.title == "" then
		return
	end
	note.icon = note.icon or ICON_NAME
	if not note.quests then
		note.quests = {}
	end
	return note
end

local tidyNotes = setmetatable({}, {
	__mode = 'k',
	__index = function(t, note)
		t[note] = TidyNote(note) and true or false;
		return t[note]
	end
})
Cartographer_Quests.tidyNotes = tidyNotes

local function tidyXY(x, y)
	return x >= 0 and x <= 1 and y >= 0 and y <= 1
end

local function tidyId(id)
	return type(id) == 'number' and tidyXY(Cartographer_Notes.getXY(id))
end

local function doUpgrade(note, version)

	if version == 1 then
		local old_quests = note.quests
		note.quests = {}
		if old_quests and type(old_quests) == 'table' then
			if old_quests.available and type(old_quests.available) == 'table' then
				for i,quest in pairs(old_quests.available) do
					note.quests[quest] = true
				end
				old_quests.available = nil
			end
			if old_quests.active and type(old_quests.active) == 'table' then
				for i,quest in pairs(old_quests.active) do
					note.quests[quest] = true
				end
				old_quests.active = nil
			end
			for i,quest in pairs(old_quests) do
				note.quests[quest] = true
			end
		end
		note.title = note.title or note.info
		note.info = nil
		note.info2 = nil
		if note.title then
			if string.match(note.title, L["Quest Giver"], 1, true) then
				note.title = string.match(note.title, '^(.-) - '..L["Quest Giver"]..'$')
			elseif string.match(note.title, "Quest Giver", 1, true) then
				note.title = string.match(note.title, '^(.-) - Quest Giver$')
			end
		end
		version = 2

	end

	if version == 2 then
		for title,level in pairs(note.quests) do
			local _ = questTable[title]
		end
		version = 3
	end
	
	if version == 3 then
		for k,v in pairs(note.quests) do
			if type(k) == 'number' and type(v) == 'string' then
				note.quests[k] = nil
				note.quests[v] = true
			end
		end
		version = 4
	end
	
	return version
end

function Cartographer_Quests:UpgradeNote(note)
	if not tidyNotes[note] then
		return
	end
		
	local version = note.version or 1
	if version == DB_VERSION then
		return note, version
	elseif version < DB_COMPAT_VERSION then
		self:Print(L['Note %q dropped due to incompatble version (%q).'], tostring(note.title or '<untitled>'), version)
		return
	end
	
	version = doUpgrade(note, version)		

	if version ~= note.version then
		note.version = version
		note.info = self:BuildNoteInfo(note.quests)
		self:Debug('Note %q updated to version %q', note.title, version);
	end
	return note, version
end

function Cartographer_Quests:UpgradeDatabase()
	local f = self.db.faction
	local note_db = f.notes

	-- Very old database
	if not f.imported_old then
		local oldDB = Cartographer:AcquireDBNamespace(DB_NAME)
		if oldDB and oldDB.faction and oldDB.faction.notes then
			for k, v in pairs(oldDB.faction.notes) do
				if (k ~= "version") and (v ~= nil) then
					if (not f.notes[k]) then f.notes[k] = {} end
					for vk, vv in pairs(v) do
						if (vv ~= nil) then
							if (not f.notes[k][vk]) then
								-- self.db.faction.notes[k][vk] = {}
								f.notes[k][vk] = vv
							end
						end
					end
				end
			end
			oldDB.faction.notes = nil
			oldDB.faction = nil
		end
		oldDB = nil
		f.imported_old = true
	end

	-- Update current database
	if not f.db_version or (f.db_version < DB_VERSION and f.db_version >= DB_COMPAT_VERSION) then
		local note_version
	 	--self:Print(L['Upgrading quest database'])
	 	f.db_version = DB_VERSION
		for zone,notes in pairs(note_db) do
			if zone ~= 'version' and type(notes) == 'table' then
				for id, note in pairs(notes) do
					if type(note) == 'table' then
						notes[tonumber(id)],note_version = self:UpgradeNote(note)
						if note_version then
							f.db_version = math.min(f.db_version, note_version)
						end
					end
				end
			end
		end
		if f.db_version == DB_VERSION then
	 		self:Print(L['Quest database upgraded to current version.'])
	 	else
	 		self:Print(L['Quest database could not be upgraded to current version.'])
	 	end
	end

	for zone,notes in pairs(note_db) do
		if zone ~= 'version' then
			if BZ:HasTranslation(zone) and type(notes) == 'table' then
				for id, note in pairs(notes) do
					if not (tidyId(id) and tidyNotes[note]) then
						notes[id] = nil
					end
				end
				if not next(notes) then
					note_db[zone] = nil
				end
			else
				note_db[zone] = nil
			end
		end
	end

	--[[
	if f.givers then
		for zone,givers in pairs(f.givers) do
			local english_zone = BZ:HasReverseTranslation(zone) and BZ:GetReverseTranslation(zone) or zone
			for giver,data in pairs(givers) do
				if data.x and data.y then
					self:SetNote(english_zone, data.x, data.y, giver, {})
				end
			end
		end
	end
	--]]

end

local tmp = {}
function Cartographer_Quests:BuildNoteInfo(quests)
	if not next(quests) then return end
	
	while #tmp > 0 do table.remove(tmp) end

	tmp[#tmp+1] = L['Quests']..':'
	for title in pairs(quests) do
		tmp[#tmp+1] = title
	end
	return table.concat(tmp, "\n")
end

function Cartographer_Quests:SetNote(zone, x, y, giver, quests)
	if x == nil or x == 0 and y == 0 then return end

	-- Register quests globally
	for title in pairs(quests) do
		-- Throw id away
		local _ = questTable[title]
	end

	x, y = self:RegisterQuestGiver(zone, x, y, giver)

	-- Update existing quest giver
	for _zone,_x,_y,_icon,_db,data in Cartographer_Notes:IterateNearbyNotes(zone, x, y, 20, DB_NAME, nil, true) do
		if _db == DB_NAME and data.title == giver then
			local update = false
			if next(quests) then
				self:Debug('Checking %q for new quests', giver)
				for title,level in pairs(quests) do
					if not data.quests[title] or data.quests[title] == true then
						data.quests[title] = level
						self:Debug('Adding quest %q', title)
						update = true
					end
				end
			end
			if update then
				self:Debug('Updating note for %q', giver)
				data.info = self:BuildNoteInfo(data.quests)
				Cartographer_Notes:ShowNote(_zone, Cartographer_Notes.getID(_x,_y), DB_NAME)
			end
			return data
		end
	end
	
	-- Create a new quest giver
	self:Debug('New note for %q', giver)
	note_quests = {}
	for title,level in pairs(quests) do
		note_quests[title] = level
		self:Debug('Adding quest %q', title)
	end
	Cartographer_Notes:SetNote(zone, x, y, ICON_NAME, DB_NAME,
		'title', giver,
		'version', DB_VERSION,
		'quests', note_quests, 
		'info', self:BuildNoteInfo(note_quests)
	)
	local _,_,_,_,_db,_data = Cartographer_Notes:GetNote(zone,x,y) 
	if _db == DB_NAME and _data.title == giver then
		return data
	end
end

-----------------------
-- Quest registering --
-----------------------

-- Reduce hooking side effect
local GetTitleText = GetTitleText
local GetQuestLogTitle = GetQuestLogTitle
local GetNumQuestLogEntries = GetNumQuestLogEntries
local GetGossipActiveQuests = GetGossipActiveQuests
local GetGossipAvailableQuests = GetGossipAvailableQuests

function Cartographer_Quests:RegisterQuestGiver(zone, x, y, giver)
	local entry = self.db.faction.givers[zone][giver]
	if not entry then
		self:Debug('New questgiver: %q in %q', giver, zone)
		entry = {}
		self.db.faction.givers[zone][giver] = entry
	end
	entry.name		= giver
	entry.x       = entry.x or x
	entry.y       = entry.y or y
	
	local Tooltip = AceLibrary('Gratuity-2.0')
	Tooltip:SetUnit("npc")
	entry.faction = Tooltip:GetLine(2)
	
	return entry.x, entry.y
end

local function populateQuestList(quests, title, level, ...)
	if title then
		quests[title] = level
		return populateQuestList(quests, ...)
	end
end

function Cartographer_Quests:GetQuestGiverDetails()
	if UnitPlayerControlled('npc') or UnitIsPlayer('npc') or not UnitHealth('npc') or UnitHealth('npc') == 0 then
		self:Debug('Not registering quest from player or item')
		return
	end
	local giver = UnitName("npc")
	if not giver then return end
	local x, y = Cartographer:GetCurrentPlayerPosition()
	if x == 0 and y == 0 or x == nil then return end
	return GetRealZoneText(), x, y, giver
end

local quests = {}
function Cartographer_Quests:ScanGossip()
	local zone, x, y, giver = self:GetQuestGiverDetails()
	if not zone then return end
	self:Debug("ScanGossip")

	for k in pairs(quests) do quests[k] = nil end
	populateQuestList(quests, GetGossipActiveQuests())
	populateQuestList(quests, GetGossipAvailableQuests())
	if next(quests) then
		self:Debug("Registering quests for %q", giver)
		return self:SetNote(zone, x, y, giver, quests)
	end
end

function Cartographer_Quests:RegisterQuestFromDetail()
	local zone, x, y, giver = self:GetQuestGiverDetails()
	if not zone then return end

	self:Debug("RegisterQuestFromDetail")
	for k in pairs(quests) do quests[k] = nil end
	quests[GetTitleText()] = UnitLevel('player');
	return self:SetNote(zone, x, y, giver, quests)
end

------------------------
-- Quest log handling --
------------------------

local questlog = {}
local new_questlog = {}
local questlog_scanned = false

function Cartographer_Quests:ScanQuestLog()
	self:Debug("ScanQuestLog")

	local updated = false

	-- Rescan
	for i = 1, GetNumQuestLogEntries() do
		local title, _, _, _, isHeader, _, isComplete = GetQuestLogTitle(i)
		if not isHeader and not self.db.char.questHistory[questTable[title]] then

			local status = 'active'
			if isComplete == 1 then
				status = 'complete'
			elseif isComplete == -1 then
				status = 'failed'
			end
			new_questlog[title] = status

			-- check for new or updated quests
			if not questlog[title] or questlog[title] ~= status then
				self:Debug('Quest %q %s %q', title, questlog[title] and 'status changed to' or 'registered with status', status)
				changed = true
			end

			questlog[title] = nil
		end
	end

	-- Switch the two tables, so that new_questlog becomes questlog
	new_questlog, questlog = questlog, new_questlog
	self.questlog = questlog

	-- Clean up table
	for title in pairs(new_questlog) do
		updated = true
		new_questlog[title] = nil
		self:Debug('%q has been deleted from questlog', title)
	end

	-- Refresh notes if needed
	if updated then
		Cartographer_Notes:RefreshMap(true)
	end

	questlog_scanned = true

end

function Cartographer_Quests:GetQuestLogStatus(title)
	if not questlog_scanned then
		self:ScanQuestLog()
	end
	return title and questlog[title]
end

--------------------------
-- Quest frame watching --
--------------------------

local watched_quest

function Cartographer_Quests:GetQuestReward()
	if watched_quest then
		local id = questTable[watched_quest]
		local history = self.db.char.questHistory
		if history[id] ~= 'repeatable' then
			history[id] = 'done'
		elseif history[id] == 'done' then
			history[id] = 'repeatable'
		end
		self:Debug('Quest %q done, status set to %q', watched_quest, history[id]);
		watched_quest = nil
		self:ScanQuestLog()
	end
	self:UnwatchQuestCompletion()
end

function Cartographer_Quests:UnwatchQuestCompletion()
	if self:IsHooked('GetQuestReward') then
		self:Unhook('GetQuestReward')
	end
	if self:IsEventRegistered('QUEST_FINISHED') then
		self:UnregisterEvent('QUEST_FINISHED')
	end
	if watched_quests then
		self:Debug('Stop watching for completion of quest %q', watched_quests);
	end
	watched_quest = nil
end

function Cartographer_Quests:WatchQuestCompletion()
	self:RegisterQuestFromDetail();
	watched_quest = GetTitleText()
	self:Debug('Watching for completion of quest %q', watched_quest);
	self:RegisterEvent('QUEST_FINISHED', 'UnwatchQuestCompletion', true)
	self:SecureHook('GetQuestReward')
end

------------------------
-- Note API overrides --
------------------------

function Cartographer_Quests:OnNoteReceive(zone, x, y, icon, creator, data, sender, fullSender)
	if tidyXY(x, y) and self:UpgradeNote(data) then
		self:SetNote(zone, x, y, data.title, data.quests)
	end
	return true
end

function Cartographer_Quests:GetQuestStatus(title, level)
	local status = self:GetQuestLogStatus(title) or self.db.char.questHistory[questTable[title]] or 'available'
	local substatus
	if type(level) == 'number' then
		local pl = UnitLevel('player')
		if pl < level - 3 then
			substatus = 'unavailable'
		elseif pl > level + GetQuestGreenRange() then
			substatus = 'trivial'
		end
	end
	return status, substatus
end

function Cartographer_Quests:GetVisibleQuestStatus(title, level)
	local status, substatus = self:GetQuestStatus(title, level)
	if self.db.profile.filter[status] and (not substatus or (substatus and self.db.profile.filter[substatus])) then
		return status, substatus
	end
end

function Cartographer_Quests:IsNoteHidden(zone, id, data)
	if tidyNotes[data] then
		if type(data.quests) ~= 'table' or not next(data.quests) then
			return not self.db.profile.filter.obsolete
		end
		for title,level in pairs(data.quests) do
			if self:GetVisibleQuestStatus(title, level) then
				return false
			end
		end
	else
		-- Remove dirty note
		self.db.faction.notes[zone][id] = nil
		if not next(self.db.faction.notes[zone]) then
			self.db.faction.notes[zone] = nil
		end
	end
	return true
end

-- Status priorities
local icon_status_to_level = {
	unavailable = 1,
	available = 2,
	repeatable = 3,
	active = 4,
	failed = 4,
	complete = 5,
}

local icon_level_to_name = {
	[1] = ICON_NAME..'-unavailable',
	[2] = ICON_NAME..'-available',
	[3] = ICON_NAME..'-repeatable',
	[4] = ICON_NAME..'-active',
	[5] = ICON_NAME..'-complete'
}

function Cartographer_Quests:GetNoteIcon(zone, id, data)
	if type(data) == 'table' and data.quests and next(data.quests) then
		local icon_level = 0
		for title, level in pairs(data.quests) do
			local status, substatus = self:GetVisibleQuestStatus(title, level)
			local key = substatus or status
			if key and icon_status_to_level[key] then
				icon_level = math.max(icon_level, icon_status_to_level[key])
			end
		end
		return icon_level_to_name[icon_level] or ICON_NAME
	end
	return ICON_NAME
end

function Cartographer_Quests:OnNoteTooltipLineRequest(zone, id, data, inMinimap)
	return 'text', L['Quest Giver'] .. ': '.. (data.title or data.info or "?")
end

local yardString = GetLocale() == "enUS" and "%.0f yd" or "%.0f m"

function Cartographer_Quests:OnNoteTooltipRequest(zone, id, data, inMinimap)

	Tablet:SetTitle(data.title)

	if type(data.quests) == 'table' then
		local cat = Tablet:AddCategory(
			'text', L['Quests'],
			'columns', 2,
			'wrap', true,
			'justify2',
			'RIGHT'
		)

		local l = L["Statuses"]
		for title, level in pairs(data.quests) do
			local status, substatus = self:GetQuestStatus(title, level)
			cat:AddLine('text', title, 'text2', l[substatus or status])
		end
	end

	-- Riped from Cartograhper_Notes
	if not this.minimap and Cartographer_Notes:IsShowingYardsAway() then
		local x, y = Cartographer_Notes.getXY(tonumber(id))
		local dist = Cartographer:GetDistanceToPoint(x, y, zone)
		if dist then
			Tablet:AddCategory(
				'columns', 2,
				'hideBlankLine', true
			):AddLine(
				'text', AceLibrary("AceLocale-2.2"):new("Cartographer")["Distance:"],
				'text2', yardString:format(dist)
			)
		end
	end
	if not this.minimap and Cartographer_Notes:IsShowingCreator() then
		Tablet:AddCategory(
			'columns', 2,
			'hideBlankLine', true
		):AddLine(
			'text', AceLibrary("AceLocale-2.2"):new("Cartographer-Notes")["Created by"],
			'text2', L["Quests"]
		)
	end

end

local editable_status = {
	available  = true,
	done       = true,
	repeatable = true
}

function Cartographer_Quests:OnNoteMenuRequest(zone, id, data, level, value, level2, level3, level4, defaultMenu)
	if not tidyNotes[data] then
		return defaultMenu(level, value, level2, level3, level4)	
	end

	if level == 1 then
		Dewdrop:AddLine(
			'text', L['Quests'],
			'hasArrow', true,
			'value', 'quests',
			'disabled', not (data and data.quests and type(data.quests) == 'table' and next(data.quests))
		)
		Dewdrop:AddLine()
		defaultMenu(level, value, level2, level3, level4)	
		
	elseif level == 2 and value == 'quests' then
		
		for qtitle, qlevel in pairs(data.quests) do
			local qtitle = qtitle
			Dewdrop:AddLine(
				'text', qtitle,
				'hasArrow', true,
				'value', 'quest-'..qtitle
			)
		end

	elseif level == 3 and value:sub(1,6) == 'quest-' then
		
		local qtitle = value:sub(7)
		local qlevel = data.quests[qtitle]
		if not qtitle or not qlevel then
			return
		end
		local qstatus = self:GetQuestStatus(qtitle, qlevel)
		
		Dewdrop:AddLine('text', L['Quest status'], 'isTitle', true)
		if editable_status[qstatus] then
			
			for status in pairs(editable_status) do
				local status = status
				Dewdrop:AddLine(
					'text', L['Statuses'][status],
					'tooltipTitle' , L['Statuses'][status],
					'tooltipText', L['Change quest status to this new value.'],
					'isRadio', true,
					'checked', (qstatus == status),
					'func', function() 
						self.db.char.questHistory[questTable[qtitle]] = status
						Cartographer_Notes:RefreshMap(true)
					end
				)
			end
		else
			Dewdrop:AddLine(
				'text', L['Quest log based'],
				'tooltipTitle', L['Quest log based'],
				'tooltipText', L['The status of this quest can not be changed as it is directly related to your quest log.'],
				'disabled', true
			)
		end
		
		Dewdrop:AddLine()
		
		Dewdrop:AddLine(
			'text', L['Delete quest'],
			'textR', 1, 'textG', 0, 'textB', 0,
			'tooltipTitle', L['Delete quest'],
			'tooltipText', L['Delete the quest. WARNING: THIS IS NOT UNDOABLE.'],
			'func', function() 
				data.quests[qtitle] = nil
				Cartographer_Notes:RefreshMap(true)
			end
		)
		
	else
		defaultMenu(level, value, level2, level3, level4)	
	end
end

function Cartographer_Quests:IsTracking(zone, id, data)
	return true
end

--------------
-- Settings --
--------------

function Cartographer_Quests:IsShowingQuests(questtype)
	return self.db.profile.filter[questtype]
end

function Cartographer_Quests:ToggleShowingQuests(questtype, value)
	if value == nil then
		value = not self.db.profile.filter[questtype]
	end
	self.db.profile.filter[questtype] = value

	return Cartographer_Notes:RefreshMap(true)
end

function Cartographer_Quests:IsShowingMinimapIcons()
	return self.db.profile.minimapIcons
end

function Cartographer_Quests:ToggleShowingMinimapIcons()
	self.db.profile.minimapIcons = not self.db.profile.minimapIcons
end

function Cartographer_Quests:IsMiniNoteHidden(zone,id,data)
	return not self.db.profile.minimapIcons
end

function Cartographer_Quests:GetIconScale()
	return self.db.profile.iconScale
end

function Cartographer_Quests:SetIconScale(value)
	self.db.profile.iconScale = value
	Cartographer_Notes:RefreshMap(true)
end
function Cartographer_Quests:GetIconAlpha()
	return self.db.profile.iconAlpha
end

function Cartographer_Quests:SetIconAlpha(value)
	self.db.profile.iconAlpha = value
	Cartographer_Notes:RefreshMap(true)
end

function Cartographer_Quests:GetNoteTransparency(zone,id,data)
	return self.db.profile.iconAlpha
end

function Cartographer_Quests:GetNoteScaling(zone,id,data)
	return self.db.profile.iconScale
end
