local AceAddon = AceLibrary("AceAddon-2.0")
local bs = AceLibrary("Babble-Spell-2.2")
local L = AceLibrary("AceLocale-2.2"):new("Cartographer-Noteshare")
local Tourist = AceLibrary("Tourist-2.0")

L:RegisterTranslations("enUS", function() return {
	["Database sharing"] = "Database sharing",
	["Module Description"] = "Module to share your notes automatically.",
	["Guild"] = true,
	["Group"] = true,
	["General"] = true,
	["Sharing Channel"] = true,
	["What channel you broadcast notes on."] = true,
	["Shared Databases"] = true,
	["Databases to share automatically"] = true,
	["Treasure"] = true,
	["Broadcast Zone"] = true,
	["Broadcast your database on your selected channel (Current Zone)."] = true,
	["Broadcast Database"] = true,
	["Broadcast your entire database on your selected channel."] = true,
	["Receive filter"] = true,
	["Only accept broadcast notes for these databases."] = true,	
	-- Cart Trainer,Qeusts and Vendors note databases
	["Vendors"] = true,
	["Quests"] = true,
	["Trainers"] = true,
	-- debug message
	["Note received with bad data discarded."] = true,
	["Received note from "] = true,
	["Scanning for duplicate within 5 yards/meters, found "] = true,
	[" Note received from "] = true,
	[" discarded due to duplicate. "] = true,
	["Note received from %s discarded due to filter settings."] = true,
	-- no braodcast options
	["Builtin Channel"] = true,
	["Builtin channel you wish to braodcast your data."] = true,
	["Player"] = true,
	["Player your sending your notes."] = true,
	["Enter the name of the player you wish to send"] = true,
	["Sharing Complete"] = true,
} end)  

L:RegisterTranslations("deDE", function() return {
	["Database sharing"] = "Datenabgleich",
	["Module Description"] = "Notizen automatisch mit anderen abgleichen.",
	["Guild"] = "Gilde",
	["Group"] = "Gruppe",
	["General"] = "Allgemein",
	["Sharing Channel"] = "Kanal",
	["What channel you broadcast notes on."] = "\195\156ber diesen Kanal werden die Notizen gesendet.",
	["Shared Databases"] = "Datenbanken",
	["Databases to share automatically"] = "Datenbanken, die automatisch mit anderen abgeglichen werden.",
	["Treasure"] = "Sch\195\164tze",
    ["Broadcast Zone"] = "Zone senden",
	["Broadcast your database on your selected channel (Current Zone)."] = "Alle Daten der aktuellen Zone an den eingestellten Kanal senden.",
	["Broadcast Database"] = "Datenbank senden",
	["Broadcast your entire database on your selected channel."] = "Gesamte Datenbank an den eingestellten Kanal senden.",
	["Receive filter"] = "Eingangsfilter",
	["Only accept broadcast notes for these databases."] = "Nur eingehende Notizen f\195\188r diese Datenbanken akzeptieren.",
  
  -- Cart Trainer,Qeusts and Vendors note databases
	["Vendors"] = "H\195\164ndler",
	["Quests"] = "Quests",
	["Trainers"] = "Lehrer",
  
  	-- debug message
	["Note received with bad data discarded."] = "Notiz mit fehlerhaften Daten verworfen.",
	["Received note from "] = "Notiz empfangen von ",
	["Scanning for duplicate within 5 yards/meters, found "] = "Duplikat im Umkreis von 5 m gefunden: ",
	[" Note received from "] = " Notiz empfangen von ",
	[" discarded due to duplicate. "] = ", aber Du hast bereits eine Notiz an dieser Position. ",
	["Note received from %s discarded due to filter settings."] = "Notiz von %s aufgrund der Filtereinstellungen verworfen.",
	-- no braodcast options
	["Builtin Channel"] = "Eingestellter Kanal",
	["Builtin channel you wish to braodcast your data."] = "Kanal, an den die Daten gesendet werden.",
	["Player"] = "Spieler",
	["Player your sending your notes."] = "Spieler, an den die Notizen gesendet werden.",
	["Enter the name of the player you wish to send"] = "Namen des Spielers eingeben, an den Du die Daten senden willst.",
} end)

L:RegisterTranslations("koKR", function() return {
	["Database sharing"] = "데이터베이스 공유",
	["Module Description"] = "당신의 노트를 자동으로 공유하는 모듈입니다.",
	["Guild"] = "길드",
	["Group"] = "그룹",
	["General"] = "공개",
	["Sharing Channel"] = "채널 공유",
	["What channel you broadcast notes on."] = "당신의 노트를 채널에 공유합니다.",
	["Shared Databases"] = "공유 데이터베이스",
	["Databases to share automatically"] = "자동적으로 데이터베이스를 공유합니다.",
	["Treasure"] = "보물",
	["Broadcast Zone"] = "공유할 지역",
	["Broadcast your database on your selected channel (Current Zone)."] = "당신이 선택한 채널에 당신의 데이버베이스를 알림니다.",
	["Broadcast Database"] = "데이터베이스 알림",
	["Broadcast your entire database on your selected channel."] = "선택한 채널에 모든 데이터베이스를 공유합니다.",
	["Receive filter"] = "필터 받기",
	["Only accept broadcast notes for these databases."] = "데이터베이스를 위해 노트 알림을 받습니다.",
	-- Cart Trainer,Qeusts and Vendors note databases
	["Vendors"] = "상인",
	["Quests"] = "퀘스트",
	["Trainers"] = "상급 기술자",
	-- debug message
	["Note received with bad data discarded."] = "잘못된 데이터가 있어 받기를 취소합니다.",
	["Received note from "] = " 으로부터 노트를 받았습니다.",
	["Scanning for duplicate within 5 yards/meters, found "] = "5미터 이내의 근접한 중복 정보를 찾았습니다.",
	[" Note received from "] = " 으로부터 노트를 받았습니다.",
	[" discarded due to duplicate. "] = "중복된 데이터를 취소합니다.",
--	["Note received from %s discarded due to filter settings."] = true,
	-- no braodcast options
	["Builtin Channel"] = "기존 채널",
	["Builtin channel you wish to braodcast your data."] = "데이터를 공유할 기존 채널을 설정합니다.",
	["Player"] = "플레이어",
	["Player your sending your notes."] = "플레이어에게 보낼 당신의 노트",
	["Enter the name of the player you wish to send"] = "보내고 싶은 플레이어 이름 입력",
	["Sharing Complete"] = "공유 완료",
} end)  

L:RegisterTranslations("esES", function() return {
	["Database sharing"] = "Compartir base de datos",
	["Module Description"] = "M\195\179dulo que comparte tus notas autom\195\161ticamente",
	["Guild"] = "Hermandad",
	["Group"] = "Grupo",
	["General"] = "General",
	["Sharing Channel"] = "Canal para Compartir",
	["What channel you broadcast notes on."] = "En qu\195\169 canal emitir\195\161s tus notas",
	["Shared Databases"] = "Bases de datos Compartidas",
	["Databases to share automatically"] = "Bases de datos que se compartir\195\161n autom\195\161ticamente",
	["Treasure"] = "Tesoro",
	["Broadcast Database"] = "Emitir Base de datos",
	["Broadcast your database on your selected channel (Current Zone)."] = "Emite tu base de datos en tu canal seleccionado",
	["Receive filter"] = "Recibir filtro",
	["Only accept broadcast notes for these databases."] = "Solo aceptar notas emitidas para estas bases de datos",
} end)  

L:RegisterTranslations("frFR", function() return {
	["Database sharing"] = "Partage de base de donn\195\169es",
	["Module Description"] = "Module permettant de partager vos notes automatiquement.",
	["Guild"] = "Guilde",
	["Group"] = "Groupe",
	["General"] = "G\195\169n\195\169ral",
	["Sharing Channel"] = "Canal de partage",
	["What channel you broadcast notes on."] = "D\195\169termine le canal dans lequel les notes seront diffus\195\169es.",
	["Shared Databases"] = "Bases de donn\195\169es partag\195\169es",
	["Databases to share automatically"] = "D\195\169termine les bases de donn\195\169es \195\160 partager automatiquement.",
	["Treasure"] = "Tr\195\169sors",
	["Broadcast Zone"] = "Diffuser les donn\195\169es de la zone",
	["Broadcast your database on your selected channel (Current Zone)."] = "Diffuse votre base de donn\195\169es dans le canal s\195\169lectionn\195\169 (zone actuelle).",
	["Broadcast Database"] = "Diffuser toute la base de donn\195\169es",
	["Broadcast your entire database on your selected channel."] = "Diffuse l'enti\195\168ret\195\169 de votre base de données sur le canal s\195\169lectionn\195\169.",
	["Receive filter"] = "Filtre de r\195\169ception",
	["Only accept broadcast notes for these databases."] = "Accepte uniquement les notes de ces bases de donn\195\169es.",
	-- Cart Trainer,Quests and Vendors note databases
	["Vendors"] = "Vendeurs",
	["Quests"] = "Qu\195\170tes",
	["Trainers"] = "Entra\195\174neurs",
	-- debug message
	["Note received with bad data discarded."] = "Note reçue ignor\195\169e (mauvaises donn\195\169es).",
	["Received note from "] = "R\195\169ception d'une note de ",
	["Scanning for duplicate within 5 yards/meters, found "] = "Analyse des doublons \195\160 moins de 5 mètres, trouv\195\169 ",
	[" Note received from "] = " Note re\195\167ue de ",
	[" discarded due to duplicate. "] = " ignoré pour cause de doublon.",
	["Note received from %s discarded due to filter settings."] = "Note re\195\167ue de %s ignor\195\169e dû aux param\195\168tres du filtre.",
	-- no braodcast options
	["Builtin Channel"] = "Canal int\195\169gr\195\169",
	["Builtin channel you wish to braodcast your data."] = "Canal int\195\169gr\195\169 dans lequel vous souhaitez diffuser vos donn\195\169es.",
	["Player"] = "Joueur",
	["Player your sending your notes."] = "Le joueur \195\160 qui envoyer vos notes.",
	["Enter the name of the player you wish to send"] = "Entrez le nom du joueur \195\160 qui vous souhaitez envoyer vos notes",
} end)

local Cartographer_Noteshare = Cartographer:NewModule("Noteshare","AceEvent-2.0", "AceConsole-2.0","AceHook-2.1")
local cartNoteHook = nil
local hasInstanceMaps = false

local dblist = {
	["Mining"] = bs["Mining"],
	["Herbalism"] = bs["Herbalism"],
	["Treasure"] = L["Treasure"],
	["POI"] = AceLibrary("AceLocale-2.2"):new("Cartographer_POI")["POI"],
	["General"] = L["General"],
	["Fishing"] = bs["Fishing"],
	["Vendors"] = L["Vendors"],
	["Quests"] = L["Quests"],
	["Trainers"] = L["Trainers"],
}
-- Al lthe addons I know about right now for Cart
local registered_addon_databases = {
	["Mining"] = true,
	["POI"] = true,
	["Fishing"] = true,
	["Vendors"] = true,
	["Quests"] = true,
	["QuestObjectives"] = true,
	["Trainers"] = true,
	["Herbalism"] = true,
	["Treasure"] = true,
	["Waypoints"] = true,
	["InstanceNotes"] = true,
}
table.sort(dblist)

function Cartographer_Noteshare:OnInitialize()
	self.db = Cartographer:AcquireDBNamespace("Noteshare")
	Cartographer:RegisterDefaults("Noteshare", "profile", {
		broadcastChannel = "GUILD",
		shareDB = {},
		filterDB = {},
		shareProf = false,
		shareInst = false,
		sharePOI = false,
		["target"] = "",
	})
	self.title   = L["Database sharing"]
	self.name    = L["Database sharing"]
	self.author  = "Kagaro on Ysera"
	self.notes   = L["Module Description"]
	self.email   = "sal.scotto@gmail.com"
	self.version = "1.0"
	self.website = nil
	if Cartographer_InstanceMaps then
		hasInstanceMaps = true
	end
	Cartographer.options.args.Noteshare = {
		name = L["Database sharing"],
		desc = self.notes,
		handler = self,
		type = 'group',
		args = {
			toggle = {
				name = AceLibrary("AceLocale-2.2"):new("Cartographer")["Enabled"],
				desc = AceLibrary("AceLocale-2.2"):new("Cartographer")["Suspend/resume this module."],
				type  = "toggle",
				order = -1,
				get   = function() return Cartographer:IsModuleActive(self) end,
				set   = function() Cartographer:ToggleModuleActive(self) end,				
			},
			-- share channel
			channel = {
				name = L["Sharing Channel"],
				desc = L["What channel you broadcast notes on."],
				type = "group",
				args = {
					prechan = {
						name = L["Builtin Channel"],
						desc = L["Builtin channel you wish to braodcast your data."],
						type = "text",
						order = 1,
						get = "GetBroadcastChannel",
						set = "SetBroadcastChannel",
						validate = {["GUILD"] = L["Guild"], ["GROUP"] = L["Group"], ["WHISPER"] = L["Player"]},
						disabled = function() return not Cartographer:IsModuleActive(self) end,
					},
					custchan = {
						name = L["Player"],
						desc = L["Player your sending your notes."],
						usage = L["Enter the name of the player you wish to send"],
						type = "text",
						order = 2,
						get = function() return self.db.profile.target end,
						set = function(v) self.db.profile.target = v end,
						validate = "CustomChannel",
						disabled = function() return self.db.profile.broadcastChannel ~= "WHISPER" end
					},
				},
				order = 1,
				disabled = function() return not Cartographer:IsModuleActive(self) end,
			},
			-- databases to share
			shared_db = {
				name = L["Shared Databases"],
				desc = L["Databases to share automatically"],
				type = "group",
				order = 2,
				args = {},
				disabled = function() return not Cartographer:IsModuleActive(self) end
			},
			dump_zone = {
				name = L["Broadcast Zone"],
				desc = L["Broadcast your database on your selected channel (Current Zone)."],
				type = "group",
				order = 4,
				args = {},
				disabled = function() return not Cartographer:IsModuleActive(self) end,
			},
			dump_database = {
				name = L["Broadcast Database"],
				desc = L["Broadcast your entire database on your selected channel."],
				type = "group",
				order = 5,
				args = {},
				disabled = function() return not Cartographer:IsModuleActive(self) end,
			},
			ignored_databases = {
				name = L["Receive filter"],
				desc = L["Only accept broadcast notes for these databases."],
				type = "group",
				order = 3,
				args = {},
				disabled = function() return not Cartographer:IsModuleActive(self) end,
			}
		},
	}
	-- setup sub groups
	for k,v in pairs(dblist) do
		local k = k
		Cartographer.options.args.Noteshare.args.shared_db.args[k] = {
			name = v,
			desc = v,
			type = 'toggle',
			get = function() return self:IsSharingDatabase(k) end,
			set = function() return self:ToggleSharingDatabase(k) end,
			disabled = function() 
				if k == "General" then
					return false
				end
				if k == "Trainers" and TrainerFu then
					return false
				end
				return not Cartographer:HasModule(k) 
			end,
		}
		Cartographer.options.args.Noteshare.args.dump_zone.args[k] = {
			name = v,
			desc = v,
			type = 'execute',
			func = function() self:DumpZone(k, Cartographer:GetCurrentEnglishZoneName()) end,
			disabled = function() 
				if k == "General" then
					return false
				end
				if k == "Trainers" and TrainerFu then
					return false
				end
				return not Cartographer:HasModule(k) 
			end,
		}
		Cartographer.options.args.Noteshare.args.dump_database.args[k] = {
			name = v,
			desc = v,
			type = 'execute',
			func = function() self:DumpDatabase(k) end,
			disabled = function() 
				if k == "General" then
					return false
				end
				if k == "Trainers" and TrainerFu then
					return false
				end
				return not Cartographer:HasModule(k) 
			end,
		}
		Cartographer.options.args.Noteshare.args.ignored_databases.args[k] = {
			name = v,
			desc = v,
			type = 'toggle',
			get = function() return self:IsFilteringDatabase(k) end,
			set = function() return self:ToggleFilteringDatabase(k) end,			
			disabled = function() 
				if k == "General" then
					return false
				end
				if k == "Trainers" and TrainerFu then
					return false
				end
				return not Cartographer:HasModule(k) 
			end,
		}
	end
	AceLibrary("AceConsole-2.0"):InjectAceOptionsTable(self, Cartographer.options.args.Noteshare)
	
end

function Cartographer_Noteshare:CustomChannel(player)
	return player:find("^[A-Za-z][A-Za-z]+$")
end

function Cartographer_Noteshare:OnEnable()
	if Cartographer_Notes then
		-- register our listener
		self:StartEvents()
	else
		-- if the Notes module not active we dont do anything
		Cartographer:ToggleModuleActive(self,false)
	end
end

function Cartographer_Noteshare:OnDisable()
	self:StopEvents()
end

function Cartographer_Noteshare:StartEvents()
	self:RegisterEvent("CartographerNotes_NoteSet", function(zone,x,y,icon,creator,comm) 
		if not comm then 
			self:NoteAdded(zone,x,y,icon,creator)
		end 
	end)
	-- hook Cartographer.OnCommReceive
	self:Hook(Cartographer_Notes,"AcceptIncomingNote")
	self:Hook(Cartographer_Notes,"OnNoteReceive")
end

function Cartographer_Noteshare:AcceptIncomingNote(cart_note_ref, zone, x, y, icon, creator, data, sender, fullSender)
	local database = Cartographer_Notes.externalDBs[creator] and creator
	local known_db  = registered_addon_databases[creator] and creator
	-- database is a registered and active DB for Cart, now see if we allow it
	if database and self.db.profile.filterDB[database] then
		return true
	end
	-- Here we see if General is allowed and the note ISNT any of the know note databases
	-- we DONT share waypoints or instance notes
	if self.db.profile.filterDB["General"] and not known_db then
		return true
	end
	return false
	-- OLD CODE BELOW
		--local database = (Cartographer_Notes.externalDBs[creator] and creator) or (dblist[creator] and creator) or "General"
		--if self.db.profile.filterDB[database] then
		--	return true
		--end
end
function Cartographer_Noteshare:OnNoteReceive(cart_note_ref, zone, x, y, receive_icon, creator, data, sender, fullSender)
	if Cartographer_Notes.externalDBs[creator] then 
		if Cartographer_Notes.db.profile.showNotifications and fullSender then
			self:Print(L["Received note from "]..fullSender)
		end
		local _,p_x,p_y,p_icon,_,p_data = Cartographer_Notes:GetNearbyNote(zone,x,y,5,creator,true) -- if there is already a ntoe within 5 yards of this one
		if Cartographer_Notes.db.profile.showNotifications and p_icon then
			self:Print(L["Scanning for duplicate within 5 yards/meters, found "]..p_icon)
		end
		if p_icon == receive_icon then
			if Cartographer_Notes.db.profile.showNotifications and receive_icon and fullSender then
				self:Print(p_icon..L[" Note received from "]..fullSender..L[" discarded due to duplicate. "]..receive_icon)
			end
			-- duplicate so lets bail
			return true
		end
	end
	return self.hooks[Cartographer_Notes].OnNoteReceive(Cartographer_Notes, zone, x, y, receive_icon, creator, data, sender, fullSender)		
end

function Cartographer_Noteshare:StopEvents()
	self:UnregisterAllEvents()
	self:UnhookAll()
end

-- Prefeneces setup
function Cartographer_Noteshare:GetBroadcastChannel()
	return self.db.profile.broadcastChannel
end
function Cartographer_Noteshare:SetBroadcastChannel(value)
	self.db.profile.broadcastChannel = value
end

function Cartographer_Noteshare:ToggleSharingDatabase(v)
	self.db.profile.shareDB[v] = not self.db.profile.shareDB[v]
end

function Cartographer_Noteshare:IsSharingDatabase(v)
	if self.db.profile.shareDB[v] == nil then
		if v == "General" then
			self.db.profile.shareDB[v] = false
		else
			self.db.profile.shareDB[v] = true
		end
	end
	return self.db.profile.shareDB[v]
end

function Cartographer_Noteshare:ToggleFilteringDatabase(v)
	self.db.profile.filterDB[v] = not self.db.profile.filterDB[v]
end
function Cartographer_Noteshare:IsFilteringDatabase(v)
	if self.db.profile.filterDB[v] == nil then
		if v == "General" then
			self.db.profile.shareDB[v] = false
		else
			self.db.profile.shareDB[v] = true
		end
	end
	return self.db.profile.filterDB[v]
end

local fullDump = false
function Cartographer_Noteshare:DumpDatabase(v)
	fullDump = true
	for zone in Tourist:IterateZones() do
		self:DumpZone(v, zone)
	end
	self:Print(L["Sharing Complete"])
end

function Cartographer_Noteshare:DumpZone(v, zone)
	if not zone then 
		return 
	end
	if v == "General" then
		for zone,x,y,icon,creator,data in Cartographer_Notes:IterateNearbyNotes(zone,1,1,10000,nil,nil,true) do
			if not registered_addon_databases[creator] then
					self:BroadcastNote(zone,x,y)
			end
		end
		if not fullDump then
			self:Print(L["Sharing Complete"])
		end
	else
		-- ocheck that we have this db before trying to send it
		if Cartographer_Notes.externalDBs[v] then
			for zone,x,y,icon,creator,data in Cartographer_Notes:IterateNearbyNotes(zone,1,1,10000,v,nil,true) do
				self:BroadcastNote(zone,x,y)
			end
		end
		if not fullDump then
			self:Print(L["Sharing Complete"])
		end
	end
end

-- fire the note of on our broadcast channel
function Cartographer_Noteshare:BroadcastNote(zone,x,y)
	if self.db.profile.broadcastChannel == "GROUP" then
		Cartographer_Notes:SendNoteToGroup(zone,x,y)
	elseif self.db.profile.broadcastChannel == "GUILD" then
		Cartographer_Notes:SendNoteToGuild(zone,x,y)
	elseif self.db.profile.broadcastChannel == "WHISPER" then
		Cartographer_Notes:SendNoteToPlayer(zone,x,y,self.db.profile.target)
	end
end

function Cartographer_Noteshare:IsNoteManual(creator)
	return not (creator and Cartographer_Notes.externalDBs[creator])
end

-- note add callback
function Cartographer_Noteshare:NoteAdded(zone,x,y,icon,creator)
	if self.db.profile.shareDB[creator] then
		self:BroadcastNote(zone,x,y)
	elseif self.db.profile.shareDB["General"] and not registered_addon_databases[creator] then
		self:BroadcastNote(zone,x,y)	
	end
end

                                         