BeneCast by Wintrow

____________
|INTENTIONS|
------------
My goals in keeping BeneCast up to date are (not in that order):
- fix bugs (naturally)
- add features needed due to patches (like new spells)
- add features that do not pervert the intention of BeneCast
  That means: No directly offensive spells!
  For instance: while 'Rapid Fire' or 'Rockbiter Weapon' improve your fighting abilities
  they do not directly damage anything. You still have to do that yourself.
_________
|WEBSITE|
---------
http://www.wowace.com/projects/benecast/

_______
|EMAIL|
-------
ex__inferis@hotmail.com  (Wintrow)
_________
|VERSION|
---------
2.1.2 BETA - 03/12/2006 (by Skurel)
2.1.2 BETA Wintrow 6 - 26th of april 2006
10 rev1 - 15th of october 2008
______
|TODO|
------
- Allow users to define custom buttons

________
|QUIRKS|
--------
none so far, still in alpha, so nothing is supposed to work. In that respect... some things DO work, so maybe those are quirks :p
______________________________
|THINGS I'D LIKE BUT WON'T DO|
------------------------------
Adding 'evil spells'
Maybe something for an addon called MalCaster, but the fact that you have, at most 2 targets, makes it pretty futile.

_____________________
|ADDON SUPPORT LISTS|
---------------------
Unit Frame AddOn Support list:
See SnapTo.lua

___________________________________________________
|ADDING SUPPORT FOR YOUR FAVORITE UNIT FRAME ADDON|
---------------------------------------------------
1. Add an entry for your unit frame in BeneCast.SnapTo
Example:
BeneCast.SnapTo.<Your addonname> = {
	name = 'Your addons pretty name',
	configtable = {
		player       = { point = "TOPLEFT", frame = "PlayerFrame", relativepoint = "BOTTOM", x = -10, y = 30 },
		party1       = { point = "TOPLEFT", frame = "PartyMemberFrame1", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		party2       = { point = "TOPLEFT", frame = "PartyMemberFrame2", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		party3       = { point = "TOPLEFT", frame = "PartyMemberFrame3", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		party4       = { point = "TOPLEFT", frame = "PartyMemberFrame4", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		pet          = { point = "", frame = "", relativepoint = "", x = 0, y = 0 },
		partypet1    = { point = "TOPLEFT", frame = "PartyMemberFrame1PetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		partypet2    = { point = "TOPLEFT", frame = "PartyMemberFrame2PetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		partypet3    = { point = "TOPLEFT", frame = "PartyMemberFrame3PetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		partypet4    = { point = "TOPLEFT", frame = "PartyMemberFrame4PetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		target       = { point = "TOPLEFT", frame = "TargetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		targettarget = { point = "TOPLEFT", frame = "TargetofTargetFrame", relativepoint = "TOPRIGHT", x = 0, y = 0 },
		focus        = { point = "TOPLEFT", frame = "PlayerFrame", relativepoint = "TOPRIGHT", x = 200, y = -20 },
	},
};

2. If you don't have a frame for say... focus then omit that line
If your unit frames have names put them in the frame nodes in the above table and set
BeneCast.SnapTo.<Your addonname>.GetUnitFrame = BeneCast.SnapTo.BeneCast.GetUnitFrame;

If they don't have names implement the following method
function BeneCast.SnapTo.<Your addonname>:GetUnitFrame(unit)
	-- Code that returns your unit frame using the unit-code
end

3. If you are doing this ingame (as opposed to editing BeneCast's lua files) do

BeneCast:VARIABLES_LOADED(); -- That should add your addon to BeneCast's 'found addons' dropdown.
BeneCast.SetSnapToOption(nil, '<Your addonname>'); -- Set the 'current snapto' and re-attach everything

________________________
|IMPLEMENTATION DETAILS|
------------------------
One day someone might wanna make some sense of my code. I hope that is someone smarter than me so he might have some suggestions on improvements.
To assist in reading my code this is a little overview of how things are done:

- If it wasn't clear from Init.lua already: EVERYTHING is part of the BeneCast monster variable. This enables me to have the contents of the
several lua files accessible from anywhere in the addon. Init.lua therefore provides an overview of the whole var so that I can keep variable
names and such straight. In that respect members often get initialized to nil (a futile act) just so I can remind myself I they are written.

- I keep my constants in one place, in BeneCast.Constants. Again, this is for handy reference. If some piece of code has to make a decision that
would simply look weird and with an ugly if - elseif - else - end construct I instead try to put the descision making in the constants and
just let the code follow that. A nice example of this is BeneCast.Constants.TargetTypes. It lists which configs are allowed for a certain targettype.
This lets me change the addon's behavior from one spot without having to change things everywhere ending up with x pieces of code that all do
different things.

- In BeneCast.WorkVars I keep all tables and variables that are created in the addon in one place. Again, this ensures that CurrentStance can be updated
in EventHandlers.lua and then used in Panel.lua. It also avoids wild growth of state-variables everywhere.

- I tried assigning every function to it's most appropriate place. I function that resizes ALL buttons on a panel is a method to the panel in Panel.lua.
It then calls the Resize() method for all it's buttons. That Resize() is on the button in Button.lua.

- I tried using BeneCast.Panel and BeneCast.Button as templates for creating panels and buttons so that making a button is simply
button = BeneCast.Button:NewButton(panel, previousbutton);
That button then gets ALL methods BeneCast.Button has.

- I used table recycling whereever I deemed it needed. That is, tables that never get dereferenced don't need to be made from recycled tables.
Defining a table like that is a lot more readable. Table recycling is provided by my own little library I call LibHandyHelper.

- Various often-used parts of the BeneCast variable are redefined as locals in each file with much shorter names:
BeneCast.WorkVars becomes wv
BeneCast.Constants becomes const
...
This helps readability and improves abstraction. I don't need to really KNOW where wv leads to. As long as it works. It is imperitive that these
variables are defined in Init.lua since they must exist when the shortcuts are made in each .lua-file.

- Accessing the saved variables was first attempted using AceDB-3.0. But this caused more hassle than it was worth. BeneCast does not need data saved
across characters so the 7 subtables were a complete waste. Eventually the saved data was consolidated into a single BeneCastDB var with two sub-tables:
Setup and Profiles.
Making direct local shortcuts turned out impractical as durin the loading process the DB might get cleared and overwritten. Shortcuts were instead added
to BeneCast.WorkVars (aka wv).

- Two profiles are made: ooc and combat. BeneCast switches between them automatically when combat is initiated and ended. Moments before UI-elements
are locked down by WoW the event PLAYER_REGEN_DISABLED is thrown. This is where BeneCast switches to the combat profile by enabling wv.ConsiderInCombat.
This then makes BeneCast:GetCurrentProfileID() return combat instead of ooc.

- Spells need to be parsed from the spellbook. Since the spellbook doesn't tell us certain things (without awkwardly difficul tooltip parsing anyway)
we keep a hardcoded table of all the spells in SpellList.lua. The table is built on spellids for language independance. Once the addon is initialized
the table is then translated to the current locale into wv.SpellInfo. After that, the spellbook is parsed and wv.SpellInfo is updated. Mostly
it's about 'does the player know spell xx'.

- BeneCast's buttons can do anything. They can cast a spell, assist a unit, and (eventually) use certain items, like bandages. For that the
'possible buttons' are kept in wv.ButtonInfo. This table is fed from wv.SpellInfo, BeneCast.PreloadButtons and eventually parsed items from bags.

- BeneCast's buttons can be faded out (or hidden, depending on settings) when the effect the button produces is already found on the unit.
This information is kept in a sister-table of wv.ButtonInfo called wv.EffectInfo. It is seperate because:
* Certain effects have different names than the spells that cause them (Weakened Soul, Forbearance, Recently Bandaged). The button of that spell
needs to be disabled (or overridden, as the addon calls it) when the effect is present.
* Other effects can enable a certain spell that is otherwise unavailable. Like Rejuvenation enabling Swiftmend or a disease enabling Cure Disease.
A member of wv.EffectInfo therefore contains (roughly speaking) the name of the buff/debuff it represents and the buttons it overrides and/or enables.

- Stances are added to wv.EffectInfo as a special case. It is not important what stance your target is in. But it's the player's stance that dictates
what spells are available and which are not. So when scanning a unit's buffs and debuffs stance-effects are ignored. At the end though, if the player's
class uses stances and a button is not listed in the enables-list of the player's current stance the button is marked as overridden as if it's
own buff was already active on the unit. Therefore, each spell in SpellList.lua has a stance-indicator (if that class uses stances). This is mostly
important for Druids and very minorly for Warriors (who are unlikely to even use this addon).

- There are five configs you can set up.
One for the buttons that show up at your own unit frame
One for your pet
One for your party members and manually targetted or focused raid members
One for their pets
One for non-group members
const.TargetTypes defines which configs can contain which spells. 'self' spells only apply to the 'player' config for instance.
'allonly' on the other hand apply to all BUT the 'player' profile. Mend Pet has the 'pet' targettype and will only show up in the 'pet' config.
And so on.

- Because I suck at designing a decent GUI I am using AceConfigDialog-3.0 to generate one for me.
* The ooc-profile tree is defined relatively hardcoded and then copied to the combat-profile tree.
* The tree is defined on startup in wv.DefaultOptions. This tree never changes from then on. It IS however copied to the REAL options-tree whenever
spell-changes are detected. The copy is then supplemented with checkboxes for every button in wv.ButtonInfo in every config that can show it.
* A GUI-subtree for messing with wv.ButtonInfo and wv.EffectInfo and then saving that in BeneCastDB is in the works but hidden atm.