--[[
####################################################
Eva Framework extend handlers
simonw@cwowaddon.com last modify on 2008.5.18
Copyright GNU GPL

Doc: http://wiki.cwowaddon.com/EVA
Svn: http://woweva.googlecode.com
Site: http://sites.google.com/a/cwowaddon.com/eva
Publish: http://bbs.cwowaddon.com/thread-585-1-1.html
####################################################

blockN = {
	Name = "block name",
	Description = "Description of cmd",
	Enabled = true,
	Type = "Public"|"Private"|"System",
	RequestTypes = {"Event", "SlashCommand", "FrameEvent", "KeyBinding", "UserEvent", "EventChatCommand", "EventChatWords", ...},
	Events = {"eventNameN", ...},
	FrameEvents = {"frameNameN:eventNameN", ...},
	UserEvents = {"userEventNameN", ...},
	SlashCommands = {"slashCommandN", ...},
	KeyBindings = {"keyN", ...},
	CustomKeyBinding = customFunction,
	Permission = {
		AllowList = {"&Player",...},
		DenyList = {"&Everyone",...},
	},
	Commands = {
		GTimer = {Interval = N, Times =N},
		Timer = {Interval = N, Times =N},
		ThreadMode = "Single"|"Multi",
		ChatCommand = "xxx",
		ChatWords = {
			AllowList = {"xxx",...},
			DenyList = {"zzz",...},
		},
		{Description = "cmd notes", Function = customFunctionN, Timer = {Interval = N, Times =N},
			ChatWords = {AllowList = {"xxx",...}, DenyList = {"zzz",...}, }, ChatCommand = "xxx",
		}, ...
	}
}
addon = Eva.Addon:New()
addon:add(EVA.Block:New(block1))
addon:add(EVA.Block:New(block2))
...

Eva.AddonRegistry:Add(addon)
]]

-------------------------------------------------------------------------------
--Eva References
-------------------------------------------------------------------------------
local Block = Eva.Block
local Context = Eva.Context
local ContextManager = Eva.ContextManager
local Command = Eva.Command

-------------------------------------------------------------------------------
--Extend Handlers
-------------------------------------------------------------------------------
local EventChatCommandHandler = Eva.RequestHandler:New()
local EventChatWordsHandler = Eva.RequestHandler:New()
local User = {}

-------------------------------------------------------------------------------
--Register Handlers
-------------------------------------------------------------------------------
Eva.RequestRegistry:Add(Eva.RequestType.Event, "EventChatCommand", EventChatCommandHandler)
Eva.RequestRegistry:Add(Eva.RequestType.Event, "EventChatWords", EventChatWordsHandler)

-------------------------------------------------------------------------------
--Extend Block
-------------------------------------------------------------------------------
Block.Permission = nil

function Block:HasAccess(name)
	if (not self.Permission) then
		return true
	end

	if (User:InPermissionList(name, self.Permission.DenyList)) then
		return false
	end

	if (User:InPermissionList(name, self.Permission.AllowList)) then
		return true
	end

	return false
end

-------------------------------------------------------------------------------
--EventChatCommandHandler
-------------------------------------------------------------------------------
function EventChatCommandHandler:_SetContext()
	local chatArgs
	Context.Event_ChatMessage = Context.Event_Args[1]
	Context.Event_Sender = Context.Event_Args[2]
	Context.Event_ChatCommand, chatArgs = self:ParseChatMessage(Context.Event_ChatMessage)
	Context.Event_ChatArgs = ContextManager:SetClonable(chatArgs)
end

function EventChatCommandHandler:Process(context)
	local block = context.Block
	self:_SetContext()
	if (not Context.Event_ChatCommand or not block:HasAccess(Context.Event_Sender)) then
		return
	end

	if (block.Commands.ChatCommand) then
		if (block.Commands.ChatCommand == Context.Event_ChatCommand) then
			local cmds = Command:New(block.Commands)
			cmds:Schedule()
			return true
		end
	else
		for _, command in ipairs(block.Commands) do
			if (command.ChatCommand == Context.Event_ChatCommand) then
				local cmd = Command:New(command)
				cmd:Schedule()
				return true
			end
		end
	end
end

function EventChatCommandHandler:ParseChatMessage(chatMessage)
	local _, _, cmd, argsLine = string.find(chatMessage, "^%*(%S+)%s*(%S*.*)$")

	if (cmd and string.len(cmd) > 0) then
		if (argsLine) then
			local args = {}
			for arg in string.gmatch(argsLine, "(%S+)") do
				table.insert(args, arg)
			end
			return cmd, args
		else
			return cmd, nil
		end
	else
		return nil, nil
	end
end

-------------------------------------------------------------------------------
--EventChatWordsHandler
-------------------------------------------------------------------------------
function EventChatWordsHandler:_SetContext()
	Context.Event_ChatMessage = Context.Event_Args[1]
	Context.Event_Sender = Context.Event_Args[2]
end

function EventChatWordsHandler:Process(context)
	local block = context.Block
	self:_SetContext()
	if (not block:HasAccess(Context.Event_Sender)) then
		return
	end

	if (block.Commands.ChatWords) then
		if (self:MatchChatMessage(Context.Event_ChatMessage, block.Commands.ChatWords)) then
			local cmds = Command:New(block.Commands)
			cmds:Schedule()
			return true
		end
	else
		for _, command in ipairs(block.Commands) do
			if (self:MatchChatMessage(Context.Event_ChatMessage, command.ChatWords)) then
				local cmd = Command:New(command)
				cmd:Schedule()
				return true
			end
		end
	end
end

function EventChatWordsHandler:MatchChatMessage(chatMessage, wordsList)
	if (not wordsList) then
		return false
	end

	for _, dword in ipairs(wordsList.DenyList or {}) do
		if (string.find(chatMessage, dword)) then
			return false
		end
	end

	for _, aword in ipairs(wordsList.AllowList or {}) do
		if (string.find(chatMessage, aword)) then
			return true
		end
	end

	return false
end

-------------------------------------------------------------------------------
--User
-------------------------------------------------------------------------------
function User:InPermissionList(name, pList)
	if (not pList) then
		return false
	end

	for _, user in ipairs(pList) do
		if (name == user) then
			return true
		end

		local isUserFunction = User.Items[user]
		if (isUserFunction and isUserFunction(name)) then
			return true
		end
	end

	return false
end

function User.IsPlayer(name)
	if ( name == UnitName("player") ) then
		return true
	end
	return false
end

function User.IsFriend(name)
	local friend
	for i = 1, GetNumFriends() do
		friend = GetFriendInfo( i )
		if ( friend == name ) then
			return true
		end
	end
	return false
end

function User.IsRaidMember(name)
	for i = 1, 40 do
		local player = "raid"..i
		if ( name == UnitName(player) ) then
			return true
		end
	end
	return false
end

function User.IsRaidLeader(name)
	for i = 1, 40 do
		local player = "raid"..i
		if (UnitExists(player) and UnitIsPartyLeader(player) ) then
			if ( name == UnitName(player) ) then
				return true
			else
				return false
			end
		end
	end
	return false
end

function User.IsPartyMember(name)
	for i = 1, 4 do
		local player = "party"..i
		if ( name == UnitName(player) ) then
			return true
		end
	end
	return false
end

function User.IsPartyLeader(name)
	for i = 1, 4 do
		local player = "party"..i
		if (UnitExists(player) and UnitIsPartyLeader(player) ) then
			if ( name == UnitName(player) ) then
				return true
			else
				return false
			end
		end
	end
	return false
end

function User.IsEveryone(name)
	return true
end

User.Items = {
	["&Player"] = User.IsPlayer,
	["&Friend"] = User.IsFriend,
	["&RaidLeader"] = User.IsRaidLeader,
	["&PartyLeader"] = User.IsPartyLeader,
	["&RaidMember"] = User.IsRaidMember,
	["&PartyMember"] = User.IsPartyMember,
	["&Everyone"] = User.IsEveryone,
}