--
-- ZubanLib Library Functions
-- Author: Zuban (chumpnet@hotmail.com)
--

-- 
-- class Unit
--

ZubanLib.Unit = ZubanLib.Object:New{
	UnitID = ZubanLib.Const.UnitID.Player;
	Attributes = {};
	DefaultOtherUnit = ZubanLib.Const.UnitID.Target;
};

function ZubanLib.Unit:ToString(object)
	return tostring(self.UnitID);
end

function ZubanLib.Unit:Write()
	ZubanLib.IO:Write("UnitID: "..tostring(self.UnitID));
	ZubanLib.IO:Write("Attributes:");
	ZubanLib.IO:WriteAttributes(self);
end

function ZubanLib.Unit:Load()
	self.Attributes.Name = self:Name();
	self.Attributes.LocalizedClass, self.Attributes.Class = self:Class();
	self.Attributes.Race = self:Race();
	self.Attributes.Sex = self:SexString();
	self.Attributes.Classification = self:Classification();
	self.Attributes.PowerType = self:PowerTypeString();
	self.Attributes.FactionGroup = self:FactionGroup();
	self.Attributes.CreatureFamily = self:CreatureFamily();
	self.Attributes.CreatureType = self:CreatureType();
	self.Attributes.FullName = self:FullName();
end

function ZubanLib.Unit:GetOtherUnit(otherUnit)
	if (otherUnit == nil) then
		return self.DefaultOtherUnit;
	end
	
	return otherUnit;
end

-- player actions

function ZubanLib.Unit:Assist()
	return UnitAssist(self.UnitID);
end

function ZubanLib.Unit:CheckInteractDistance(distIndex)
	return CheckInteractDistance(self.UnitID, distIndex);
end

function ZubanLib.Unit:DropItemOn()
	return DropItemOnUnit(self.UnitID);
end

function ZubanLib.Unit:Follow()
	return FollowUnit(self.UnitID);
end

function ZubanLib.Unit:StartDuel()
	return StartDuelUnit(self.UnitID);
end

function ZubanLib.Unit:Target()
	return TargetUnit(self.UnitID);
end

function ZubanLib.Unit:TargetPet()
	return TargetUnitsPet(self.UnitID);
end

-- unit info accessors

function ZubanLib.Unit:SpellTarget()
	return SpellTargetUnit(self.UnitID);
end

function ZubanLib.Unit:AffectingCombat()
	return UnitAffectingCombat(self.UnitID);
end

function ZubanLib.Unit:Armor()
	return UnitArmor(self.UnitID);
end

function ZubanLib.Unit:AttackBothHands()
	return UnitAttackBothHands(self.UnitID);
end

function ZubanLib.Unit:AttackPower()
	return UnitAttackPower(self.UnitID);
end

function ZubanLib.Unit:AttackSpeed()
	return UnitAttackSpeed(self.UnitID);
end

function ZubanLib.Unit:Buff(i)
	return UnitBuff(self.UnitID, i);
end

function ZubanLib.Unit:CanAssist(otherUnit)
	return UnitCanAssist(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:CanAttack(otherUnit)
	return UnitCanAttack(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:CanCooperate(otherUnit)
	return UnitCanCooperate(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:CharacterPoints()
	return UnitCharacterPoints(self.UnitID);
end

function ZubanLib.Unit:Class()
	return UnitClass(self.UnitID);
end

function ZubanLib.Unit:Classification()
	return UnitClassification(self.UnitID);
end

function ZubanLib.Unit:CreatureFamily()
	return UnitCreatureFamily(self.UnitID);
end

function ZubanLib.Unit:CreatureType()
	return UnitCreatureType(self.UnitID);
end

function ZubanLib.Unit:Damage()
	return UnitDamage(self.UnitID);
end

function ZubanLib.Unit:Debuff(i)
	return UnitDebuff(self.UnitID, i);
end

function ZubanLib.Unit:Defense(i)
	return UnitDefense(self.UnitID, i);
end

function ZubanLib.Unit:Exists()
	return UnitExists(self.UnitID);
end

function ZubanLib.Unit:FactionGroup()
	return UnitFactionGroup(self.UnitID);
end

function ZubanLib.Unit:FullName()
	return tostring(self:Name()).." of "..tostring(ZubanLib.Const.Realm);
end

function ZubanLib.Unit:Health()
	return UnitHealth(self.UnitID);
end

function ZubanLib.Unit:HealthMax()
	return UnitHealthMax(self.UnitID);
end

function ZubanLib.Unit:InParty()
	return UnitInParty(self.UnitID);
end

function ZubanLib.Unit:IsCharmed()
	return UnitIsCharmed(self.UnitID);
end

function ZubanLib.Unit:IsConnected()
	return UnitIsConnected(self.UnitID);
end

function ZubanLib.Unit:IsCorpse()
	return UnitIsCorpse(self.UnitID);
end

function ZubanLib.Unit:IsDead()
	return UnitIsDead(self.UnitID);
end

function ZubanLib.Unit:IsDeadOrGhost()
	return UnitIsDeadOrGhost(self.UnitID);
end

function ZubanLib.Unit:IsEnemy(otherUnit)
	return UnitIsEnemy(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:IsFriend(otherUnit)
	return UnitIsFriend(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:IsGhost()
	return UnitIsGhost(self.UnitID);
end

function ZubanLib.Unit:IsPVP()
	return UnitIsPVP(self.UnitID);
end

function ZubanLib.Unit:IsPVPFreeForAll()
	return UnitIsPVPFreeForAll(self.UnitID);
end

function ZubanLib.Unit:IsPartyLeader()
	return UnitIsPartyLeader(self.UnitID);
end

function ZubanLib.Unit:IsPlayer()
	return UnitIsPlayer(self.UnitID);
end

function ZubanLib.Unit:IsPlusMob()
	return UnitIsPlusMob(self.UnitID);
end

function ZubanLib.Unit:IsTapped()
	return UnitIsTapped(self.UnitID);
end

function ZubanLib.Unit:IsTappedByPlayer()
	return UnitIsTappedByPlayer(self.UnitID);
end

function ZubanLib.Unit:IsTrivial()
	return UnitIsTrivial(self.UnitID);
end

function ZubanLib.Unit:IsUnit(otherUnit)
	return UnitIsUnit(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:Level()
	return UnitLevel(self.UnitID);
end

function ZubanLib.Unit:Mana()
	return UnitMana(self.UnitID);
end

function ZubanLib.Unit:ManaMax()
	return UnitManaMax(self.UnitID);
end

function ZubanLib.Unit:Name()
	return UnitName(self.UnitID);
end

function ZubanLib.Unit:PVPName()
	return UnitPVPName(self.UnitID);
end

function ZubanLib.Unit:PVPRank()
	return UnitPVPRank(self.UnitID);
end

function ZubanLib.Unit:PlayerControlled()
	return UnitPlayerControlled(self.UnitID);
end

function ZubanLib.Unit:PowerType()
	return UnitPowerType(self.UnitID);
end

function ZubanLib.Unit:PowerTypeString()
	local powerType = self:PowerType();
	
	if (powerType ~= nil) then
		return ZubanLib.Const.PowerType[powerType];
	end
	
	return nil;
end

function ZubanLib.Unit:Race()
	return UnitRace(self.UnitID);
end

function ZubanLib.Unit:RangedAttack()
	return UnitRangedAttack(self.UnitID);
end

function ZubanLib.Unit:RangedAttackPower()
	return UnitRangedAttackPower(self.UnitID);
end

function ZubanLib.Unit:RangedDamage()
	return UnitRangedDamage(self.UnitID);
end

function ZubanLib.Unit:Reaction(otherUnit)
	return UnitReaction(self.UnitID, self:GetOtherUnit(otherUnit));
end

function ZubanLib.Unit:Resistance(resistanceIndex)
	return UnitResistance(self.UnitID, resistanceIndex);
end

function ZubanLib.Unit:Sex()
	return UnitSex(self.UnitID);
end

function ZubanLib.Unit:SexString()
	local sex = self:Sex();
	
	if (sex ~= nil) then
		return ZubanLib.Const.Sex[sex];
	end
	
	return nil;
end

function ZubanLib.Unit:Stat(statIndex)
	return UnitStat(self.UnitID, statIndex);
end

function ZubanLib.Unit:XP()
	return UnitXP(self.UnitID);
end

function ZubanLib.Unit:XPMax()
	return UnitXPMax(self.UnitID);
end

function ZubanLib.Unit:FindBuffIDByName(name)
	local id = 1;
	local textName;
	ZubanLibBuffTip:SetOwner(WorldFrame,"ANCHOR_NONE");
	
	while (UnitBuff(self.UnitID, id)) do
		ZubanLibBuffTip:SetUnitBuff(self.UnitID, id);
		textName = ZubanLibBuffTipTextLeft1:GetText();
		
		if (name == textName) then
			return id;
		end
		
		id = id + 1;
	end
	
	return nil;
end

function ZubanLib.Unit:FindBuffIDBySubName(name)
	local id = 1;
	local textName;
	ZubanLibBuffTip:SetOwner(WorldFrame,"ANCHOR_NONE");
	
	while (UnitBuff(self.UnitID, id)) do
		ZubanLibBuffTip:SetUnitBuff(self.UnitID, id);
		textName = ZubanLibBuffTipTextLeft1:GetText();
		
		if (textName ~= nil and string.find(textName, name)) then
			return id;
		end
		
		id = id + 1;
	end
	
	return nil;
end

function ZubanLib.Unit:FindDebuffIDByName(name)
	local id = 1;
	local textName;
	ZubanLibDebuffTip:SetOwner(WorldFrame,"ANCHOR_NONE");
	
	while (UnitDebuff(self.UnitID, id)) do
		ZubanLibDebuffTip:SetUnitDebuff(self.UnitID, id);
		textName = ZubanLibDebuffTipTextLeft1:GetText();

		if (name == textName) then
			return id;
		end
		
		id = id + 1;
	end
	
	return nil;
end

function ZubanLib.Unit:FindDebuffIDBySubName(name)
	local id = 1;
	local textName;
	ZubanLibDebuffTip:SetOwner(WorldFrame,"ANCHOR_NONE");
	
	while (UnitDebuff(self.UnitID, id)) do
		ZubanLibDebuffTip:SetUnitDebuff(self.UnitID, id);
		textName = ZubanLibDebuffTipTextLeft1:GetText();

		if (textName ~= nil and string.find(textName, name)) then
			return id;
		end
		
		id = id + 1;
	end
	
	return nil;
end

-- Obsolete
function ZubanLib.Unit:FindBuffIDByTexture(name)
	local id = 1;
	local buff = UnitBuff(self.UnitID, id);

	while (buff) do
		if (buff == name) then
			return id;
		end
		
		id = id + 1;
		buff = UnitBuff(self.UnitID, id);
	end
	
	return nil;
end

function ZubanLib.Unit:IsClass(class)
	-- the English class, not the localized class
	local localizedClass, c = self:Class(self.UnitID);
	return c == class;
end

function ZubanLib.Unit:IsDruid()
	return self:IsClass(ZubanLib.Const.Class.Druid);
end

function ZubanLib.Unit:IsHunter()
	return self:IsClass(ZubanLib.Const.Class.Hunter);
end

function ZubanLib.Unit:IsMage()
	return self:IsClass(ZubanLib.Const.Class.Mage);
end

function ZubanLib.Unit:IsPaladin()
	return self:IsClass(ZubanLib.Const.Class.Paladin);
end

function ZubanLib.Unit:IsPriest()
	return self:IsClass(ZubanLib.Const.Class.Priest);
end

function ZubanLib.Unit:IsRogue()
	return self:IsClass(ZubanLib.Const.Class.Rogue);
end

function ZubanLib.Unit:IsShaman()
	return self:IsClass(ZubanLib.Const.Class.Shaman);
end

function ZubanLib.Unit:IsWarlock()
	return self:IsClass(ZubanLib.Const.Class.Warlock);
end

function ZubanLib.Unit:IsWarrior()
	return self:IsClass(ZubanLib.Const.Class.Warrior);
end

function ZubanLib.Unit:IsPetClass()
	return self:IsHunter() or self:IsWarlock();
end

function ZubanLib.Unit:IsAlive()
	local health = self:Health();
	return health ~= nil and health > 0;
end

--
-- class Player
--

ZubanLib.Player = ZubanLib.Unit:New{
	UnitID = ZubanLib.Const.UnitID.Player;
	Attributes = {};
};

function ZubanLib.Player:InCombat()
	if (MGplayer ~= nil) then
		-- compatibility with MiniGroup addon created by Kaitlin
		return MGplayer.inCombat;
	elseif (PlayerFrame ~= nil) then
		return PlayerFrame.inCombat;
	else
		return nil;
	end
end

function ZubanLib.Player:TargetIsHostile()
	return UnitExists("target") and UnitCanAttack("player", "target");
end

--
-- class Pet
--

ZubanLib.Pet = ZubanLib.Unit:New{
	UnitID = ZubanLib.Const.UnitID.Pet;
	Attributes = {};
};

function ZubanLib.Pet:IsFeeding()
	return self:FindBuffIDByName("Feed Pet Effect") ~= nil;
end

function ZubanLib.Pet:Happiness()
	return GetPetHappiness();
end

function ZubanLib.Pet:IsHappy()
	local happiness = GetPetHappiness();
	return happiness ~= nil and happiness >= 3;
end

function ZubanLib.Pet:Loyalty()
	return GetPetLoyalty();
end

-- pet commands

-- [Obsolete]
function ZubanLib.Pet:Feed(name)
	local bag, slot = ZubanLib.Container:FindBagSlotByName(name);
 
	if (bag and slot) then
		PickupContainerItem(bag, slot);
		-- do not record this pickup
		ZubanLib.Cursor:Clear();
		
		if (CursorHasItem()) then
			DropItemOnUnit(self.UnitID); -- function is protected in 2.0
		else
			-- error: could not pickup food
			return 2;
		end

		-- hack: if the food fails to drop on the pet and remains on the
		-- cursor, then drop it back into the container 
		if (CursorHasItem()) then
			PickupContainerItem(bag, slot);
			-- do not record this pickup
			ZubanLib.Cursor:Clear();
		else
			-- success
			return 0;
		end
	else
		-- error: food not found
		return 1;
	end
end

--
-- class Target
--

ZubanLib.Target = ZubanLib.Unit:New{
	UnitID = ZubanLib.Const.UnitID.Target;
	Attributes = {};
};

--
-- class MouseOver
--

ZubanLib.MouseOver = ZubanLib.Unit:New{
	UnitID = ZubanLib.Const.UnitID.MouseOver;
	Attributes = {};
};