--[[

Version 2.0 - Initial release of WotLK Branch to WowAce SVN

New Author : Levva of EU Khadgar - by kind Permission of Disquette

Renamed to ShockAndAwe (based on orginal DisqoDice by Disquette)

Completely overhauled for WotLK.
 - Updated to use Ace3
 - Removed totem twisting as not available in WotLK
 - Added bar for Maelstrom Weapon stacks
 - revamped bar timings so that talents taken into account
    - now uses Imp.SS talent to reduce SS cooldown
    - still manual config of 4 piece Arena bonus (on TODO list to automate this)
    - uses Maelstrom talents to determine whether to show maelstrom bar
    - now honors talents in Reverberation to adjust cooldown timer on Shock bar
    - added initial start at config window on blizzard config panel (well it has an about so far!!)

Version 2.01 -
	Enabled the /dqd & /disqodice config options 
	Added confirmation text when an option was used
	
Version 2.02 -
	Fixed display and moving bars options not showing frames after moved
	Fixed turning maelstrom on and off not comming back on
	
Version 2.10 - 
	Decided to change addon name to ShockAndAwe
	Added drycoded support for Lava Burst timer bar
	Refreshed WS code to be Shield code - added text support for Shields
	Added text support for Wind Shock
	Added check for Shamanistic Focus up
	Fixed respeccing issue
	Changed Maelstrom to show 15 sec cooldown - now hidden out of combat, pale in combat and lights up with 5 charges.
	Added text indicator on Maelstrom bar to show how many stacks
	Added text on shield indicator to show how many orbs
	Added icon to shock bar to show if Shamanistic Focus buff present - not working
	Fixed typo preventing SavedVariables actually saving between sessions
	Added text on shock bar to show if Shamanistic Focus has procced
	Altered bar height so that if you choose to show less bars then the spacing changes - eliminates gaps for non shown bars
        - this may need code to check if spacing is still valid if user turns on or off showing a bar during session
	
Version 2.11
	Changed width of SS to be full frame width and adjusted Shock & WFProc to proportional widths
	Fixed issue of maelstrom bar not showing after having moved frame
	
Version 2.12
	Added config tab for Uptime 
	Radical overhaul of the shield frame so that it consistently updates after zoning/reloading etc.
	
Version 2.13 
	Added version info
	Added Uptime Frame 
	Changed display to moveframes and updated background when in moving mode to make it more obvious
	Uptime Frames now show initial attempt at uptimes of various buffs - lots of testing still required
		- session time bars displaying 
		- last fight ones go wrong after second fight though - TODO
		- no icons displaying - TODO
		
Version 2.14 
	Fixed icon files for uptime frames and Shamanistic Focus
	Fixed last fight uptimes showing >100%
	Added tooptip to uptime frame
	
Version 2.15
	added startup to disable addon if not a shaman
	
Version 2.20 
	Removed Shamanistic Focus icon as build 8926 has it as passive ability 
	Added earth shock/flame shock rotation display icon
	Added wind shock threat threshold warning - tested with help from Isbeorn on Coldarra beta server
	Fixed issue with lastfight buff times being summed incorrectly (was a cut n paste error)
	Lots and lots of tweaking of config options for bars - still needs idiot proof testing though
	TODO - Reset option - make sure it resets all bar values
	
Version 2.21 
	Fixed debug info for windshear spamming chat when in a party
	Added config option to disable showing of uptime frame
	Added config option to disable showing text on bars
	Fixed Maelstrom weapon & Imp SS talents which had moved in build 8970
	
Version 2.22
	Localised more strings
	
Version 2.30
	Added Lava Lash CD bar
	Added Lava Burst CD bar
	Changed check for Flame Shock on target to check that its mine
	Added AceGUI-3.0 dependency
	
Version 2.40
	Fixed Wind Shock colour to dark gray similar to WS icon
	Added icon on Maelstrom Weapon bar to show LB or LvB depending on cooldowns etc.
	Added temp fix for Maelstrom Talents not being seen on login
	
Version 2.41
	Upped Windshock alpha so its easier to see
	
Version 2.50 
	Added support for SharedMedia
	
Version 2.51
	Fixed Lava Lash not showing bug
	
Version 2.52 
	Updated MW cooldown time to 30 sec as per build 9014
	Fixed bug if bar was not showing on load it would display in wrong place when activated during game
	
Version 2.60 
	Added Options to pick your own colour scheme for all the bars
	
Version 2.61
	Removed Lava Burst icon display from 5 stack of MW
	
Version 2.62
	Finally worked out syntax to have project work on new Curseforge.com SVN so revision now uses CF revision numbers
	this also means I can simply tag a version as release and it automatically appears on Curse.com website.
	
Version 2.63 
	Swapped order of Shock and Lava Lash bar so order is Shield, MW, SS, Shock, LL - which pretty much matches priority queue
	Added option to hide shield bar if its active - so that you only see it if it needs refreshing.
	
Version 2.64
	Added no-lib stripping and optionaldeps

Version 2.70 
	Added option to set border textures
	Added option to set font on frames
	Moved various options around and re-ordered the menus
	Massive overhaul of the Uptime frame - fixed a couple of memory leaks - should run a lot faster and a lot less memory
	Added option to configure uptime frame colours
	
Version 2.71
	Added German translations thanks to Bekeon on wowinterface.com
	Fixed rescaling issue
	
Version 2.80
	Added a global cooldown bar which auto-adjusts for any haste effects

Version 2.81
	Fixed spark point to no longer be offset by its width on GCD bar
	
Version 2.82 
	Fixed GCD bar visible by default on entering world
	Fixed missing French localisation entries (still needing translation)
	
Version 2.90 
	Added optional sound to play when 5 stacks of Maelstrom Weapon are achieved
	Uses any sound registered with SharedMediaLib
	Add option to flash Maelstrom Weapon frame when you get 5 stacks
	
Version 2.91
	Fixed lava lash bar bug when you turn the option on
	Added additional sound options
	Added option to play sound on 4 stacks of MW
	Added option to vary time between sounds of 5 MW stacks
	
Version 2.92
	Fixed some French translations thanks to Phops Illidan(EU) 
	Should now fully work on French Client
	
Version 2.93
	Fixed bug with turning on and off MW4 sound option
	
Version 3.00
	Remove Lava Burst bar
	Tidy up command line config menus and add a help message to direct to Blizzard config options
	Clarified how scaling works by updating help message
	Fixed typo in setting bar textures
	Split options, uptime & stats off into separate lua files for easier maintenance
	Add support for recording WF & SS total dmg and displaying in Scrolling Combat Text (if installed)
	
Version 3.01
	Fixed sparkpoint for gcdbar being wrong place if bar width changed
	Fix width of bar frame when bar width changed
	
Version 3.02 
	Stopped mw5 stack sound playing if you are no longer in combat
	Removed rotation and maelstrom weapon icons options
	
Version 3.10
	Add priority frame
	Added options to select priorities - doesnt actually get used yet
	Using fixed MW5_LB, SS, ES, LL rotation hardcoded at present
	Changed GCD bar to narrower one so its easier to see how its timeout relates to other bars
	Fixed Maelstrom bar not showing sometimes after LB cast at 5 stacks
	Fixed Alpha of Maelstrom bar wrong after 5 stacks if you have flashing on
	Added option to disable Windfury bar
	Added display of Windshock icon in priority if threat is above threshold 
	Moved Windshock option & threat option to priority section
	
Version 3.11
	Added option to control when priority shows ie: within X seconds of cooldown expiry
	Allow priority to show when time left on cooldown is less than the user set cooldown period
	The priority options menu now works - you can now set your own priorities
	
Version 3.20
	Added option to keybind Watershield and Lightning Shield
	
Version 3.21
	Priority frame does actually hide now if you choose to disable it
	Priority frame now hides when out of combat
	Fixed an issue with DE translations that would have crashed the addon on using config options
	Added options to warn if shield or weapon imbues are down
	NB. Anyone asking for Rockbiter to be included will have their name added to the list of people the addon will refuse to work for
	Fixed issue with DE & FR localisations where Stormstrike, Lava Lash, Earth Shock & Flame Shock were listed twice in 
		localisation file once in local language and once in English - thus random as to whether which it used and if it broke
	Fixed bug on priority frame if it couldn't understand spell name now forces none to prevent error messages
	Fixed chain lightning priority to check if it is off cooldown
	Fixed show of uptime & priority frames for moving and rehiding when using /saa moveframes
	Added option to rebuff weapons with selected main hand/off hand buffs (still needs work - disabled in release version for now)
	Added options for warnings if shield down or weapon buffs expire - code not implemented yet
	
Version 3.30beta1
	Added sound for shield expiry - needs proper testing and more sounds
	Added keybinds for mh & oh enchants
	Added option to change font effects
	Added option to hide priority frame title
	Added msg frame to use for wf combos if no sct installed - not working but does print in chat for now
	Added command to display paper doll stats for export to EnhSim 
		- very early version - no cut n paste yet - limited data - no warnings about buffs 
	Added News frame to show important changes from one version to another.
		- first news article is only Hello World
	Fixed moving frames showing priority and uptime frames despite option to disable them
	Since the msg frame isn't working the loss of a weapon buff only reports to chat at present
	Warning when enchants expire - not working
	Warning when enter combat without weapon buffs not working
	
Version 3.30beta2
	Fixed export routine to export EnhSim data (first pass at this - I need to know of problems)
	Added warning if you have active buffs that MIGHT affect stats and thus the sim
	
Version 3.30beta3
	Fixed MW stacks sometimes not showing
	
Version 3.30
	Added Russian Localisations
	Fixed Weapon Rebuffs keybindings - still asks for confirmation if you overwrite one though
	Fixed playing sound if shield expires
	Added a few more sound choices
	Fixed Warning of missing weapon buff on entering combat 
	Fixed Message Frame - now visible and moveable
	Added options to set timeout for text on for message frame
	Added option to set colour for text on message frame
	
Version 3.31
	Fixed msgFrame not being movable using the moveframes option
	Added option to hide timer bars out of combat
	Export to EnhSim now adds the 1% heroic presence buff if you are Draenai to save you having to remember
	Fixed having accidentally undone the MW not showing after 5 fix
	Replaced code dealing with trinkets & totems to use an itemID lookup to get string - fixes localised names
	
Version 3.40
	Removed leftover debug code from export routine
	Fixed error msg bug if you clicked Accept on export 
	New option to show Shamanistic Rage icon when mana below a configurable percentage (10% by default)
	Added option to show Windshock icon for World Bosses only
	Updated Export routine to include Spirit, Max_mana, MP5, race, and weapon type - for sim v1.4.2 onwards
	Removed bonus on export stats if player alliance as sim now handles this
	Added command /saa config to open graphical config window
	
Version 3.41
	Fixed localisation issues with Russian and French locale files thanks to cranium_dc and Phops - Illidan (EU)
		- can users who use locale's outside enUS please check these files so that I know they work, thanks.
		- I am unable to check them myself because I have no non english client and I wouldn't understand the 
		- language anyway. Je m' comprende le Francaise peu t'etre. 
		- (I know thats probably wrongly spelt my French is limited to spoken, and a limited vocabulary at that.) 
	Fixed bug that priority wouldn't show Maelstrom weapon if the maelstrom weapon bar was switched off
	
Version 3.50
	Fixed priority bug where Wind Shock & Shamanistic Rage showed even when on cooldown
	Fixed export bug where MP5 value was not exporting as an integer
	Added detection for meta gems in export routine
	Added detection for weapon dps using LibGratuity in export routine
	Added a combo point frame to the Priority point frame to show MW stacks
	Priorty Frame shows blue border if Feral Spirits available
	
Version 3.60
	Fixed export missing out unrelenting storm
	Fixed weapon rebuff warning that buff has expired when rebuffing weapon
	Added option to display an icon on each bar to make it easier to work out which bar is which
	Added button to uptime frame to reset session values
	Fixed bug with uptime frame crashing if you reset its position
	Added a Wall of Text to the news frame 
	
Version 3.61
	Added Scrollbar to News frame so it should be visible even on the most pathetic of screen resolutions
	-  Seriously folks tick the box in video settings called Use UI Scale and move the bar towards low end.
	-  You are significantly penalising your screen size by not doing this
	
Version 3.62
	Removed testing setup which always showed News Frame
	Fixed icons always showing on timer bars
	
Version 3.63	
	News frame now closes on pressing ESC
	Weapon DPS export will now give zero if it doesn't find a numeric match - should fix localisation issues
	Added glyph detection to Export routine
	
Version 3.64
	Modified DPS check for German & French clients to use 100,3 dps instead of 100.3 dps (ie: comma not dot)
	Added extra checks to priority display to check if player has Wind Shock, Shamanistic Rage & Feral Spirit
	
Version 3.65
	Added a check to GCD bar to ensure that being unable to find Lightning Shield doesn't throw error
	
Version 3.70
	Added a Feral Spirit Bar with dual cooldowns - 3 min CD for ability and 45 second CD for wolves being out
	
Version 3.71
	Added a check on all priorities to catch situation where player has added an item to priority but hasn't
	learned that skill!!
	
Version 3.72
	Small fix to initialise Export routine & check for missing glyphs
	Leave Feral Spirit active bar visible outside combat if they are still active.	
	
Version 3.80
	Added readme.txt file as cut n paste of news.
	New features coded but not working 
	-	Added totem as option to priority list
	-	It will show generic totem icon if you select totem and time left < configured time (default 20 sec) and have no totems active
	-	Otherwise it will show icon of last totem dropped for that element
	-	Added macros for weapon rebuffing instead of just casting buff. Trying to get rid of "do you want to replace" messages
	Forced MsgFrame to be background should fix non click through issue
	Added explicit check when weapon enchant event fires to check the enchant status to prevent supurious expiry messages
	Fixed export routine's weapon dps bug - in doing so removed dependency on LibGratuity-3.0
	Updated export routine to match trinkets/totems/metagems/enchants used in EnhSim v1.4.8
	Fixed Shamanistic Rage option setting which was just crashing if you attempted to change the default
	
Version 3.81
	Fixed the tooltip help message displayed when setting Maelstrom Alpha & Full Alpha 
	Showing Shamanistic Rage or Wind Shock icon should no longer "lock" in place even when mana returned or threat reduced
	
Version 3.82
	Added Spanish Localisation provided by roMZell
	
Version 3.83
	Added Traditional Chinese Localisation provided by aletheia301 on Curse.com
	
Version 3.90
	Added Earth Shock only if Stormstrike debuff on target priority option 
	- Exisiting users will need to change their settings to include this option. New default is set to mw5_lb, es_ss, ss, es, ll
	
Version 3.91 
	Added out of range/too far away warning
	removed single use local variables for spell names
	added DebugPrint function
	
Version 4.00
	Welcomed Wraithan as a contributor to the project he will be assisting in fixing known issues and adding new features
	Please make sure you add any new feature requests using the ticketing system on Curse.com
	Incorporated Wraithan's code for priority warnings for healing wave, watershield & lightning shield
	Incorporated Wraithan's code for localisations which should remove the requirement to localise spell names
	Fix to prevent errors if for some unexplicable reason you are dense enough to have the addon turned on when you are not on a shaman
	Fixed missing sounds/priorities if maelstrom bar hidden - needs testing if this fixes missing priorities for other bars hidden
	Added Earthliving Weapon & none to imbue choices
	Change defaults on Healing wave/water shield recommendation/shamanistic rage recommendation to realistic levels
	Alter max shield orbs to 9 - should really use Static Shock Talent Wind Shock Glyph values for max
	Fix Shield priority logic - not convinced its right. Why recommend water shield at 70% when LS is more dmg. Also even if 10% if mana 
		regen from SR at 5% is available soon and would take you back to 100% should only recommend water shield if regen rate needs boost
		have set default to zero for now until better logic can be established
	Fixed bug where SR priority wouldn't show if it recommended something else immediately before mana went low
	Fixed bug where MH & OH bindings weren't updated after a config change
	
Version 4.01
	Fixed missing Priority reset locale string
	Fixed flickering MW 5 bar even when disabled
	
Version 4.02
	Added sound option when weapon buffs expire
	Fixed disabling of MW Flash giving error
	Fixed using priority reset option will now reset priorities to default as well as resetting priority frame
	Moved the priority update code to be attached to the priority frame so if the bars frames are all disabled then the priorities should still work
	
Version 4.10
	Fix for localised Uptime bars
	Add support for patch 3.1 talent tree
          Added support for mw4 stack priority options
	 Fix priority for searing & magma totems so it only recommends if there is a GCD available
	 Fix for priority combo points it will now always check how many combo points you have when displaying the bar
	 
Version 4.11
	Dropped LibAboutPanel as since it moved to GIT my SVN client does nothing but complain it cant update this library.
	
Version 4.12
	Added an enable/disable option
	Added a keybind for enable/disable option
	Added a popup box to ask when you swap specs if you want to enable/disable ShockAndAwe (box not displaying properly in this version)
	Fixed an issue with moving priority frame in combat was disabling the priority frame display this is due to the fact that 
		Blizzard prevents addons updating scripts when in combat - it will still be disabled whilst you are in combat when you move it
		However it will start working again when you exit combat and re-enter.
		
Version 4.13
	Added function to force Feral Spirits Pet tab to be visible - useful for seeing what damage they do
	
Version 4.20
	Updated toc for patch 3.1
	
Version 4.21
	Remove tests for patch 3.1 as 3.1 is now live
	Fix stormstrike length
	Change Arena set bonus to 2 seconds for SS
	
Version 4.22
	Disable spec change question until I get it working right its firing entering combat = wrong.
	
Version 4.30
	Fix shield bar showing when disable out of combat selected
	Fix for MW Bar disappearing after flashing when 5 stacks. This was due to Blizzard bug in the code to disable flash frames. 
		In patch 3.0 disabling flash frames always made sure the frame was enabled in 3.1 the frame can end in a random state.
	Fixed timeout of shockbar not observing Reverberation setting, priority was bar wasn't.
	Fixed offhand weapon imbue warning when you didn't have an off hand weapon equipped - needs locale checked for DE, FR, TW, RU
	Updated haste to melee_haste & spell_haste in EnhSim export
	Updated all trinkets, totems and metagems in EnhSim export to use id's so should work for any item if EnhSim supports it
	Should now correctly export to EnhSim v1.6.8 and above everything bar EnhSim buffs
	
Version 4.31
	Added Magma totem bar
	
Version 4.32
	Added Export to EnhSim config_source flag
	
Version 4.33
	Fixed Shield & Magma bar not showing in combat if hide out of combat ticked
	Added Feral Spirits to priority option list
	Fixed totemic call not zeroing magma bar timeout
	
Version 4.34
	Fixed Magma bar - now disappears if destroyed or removed by right click on totem icon (player portrait)
	
Version 4.35
	Fixed end tree elemental talents in export to EnhSim
	
Version 4.36
	Fixed disabled Shield bar out of combat
	
Version 4.37
	Updated toc for patch 3.2
	ES_SS Priority no longer activates based on other people's Stormstrike debuffs
	
Version 4.40
	Add support for disabling priority frame and bars when in vehicle
	Fixed SS, ES, LL not showing in priorities bug introduced in v4.37
	
Version 4.41
	Fix for Spanish locale not having weapon entry and missing magma options
	Fix for inaccurate weapon speed exports when hasted
	Added time left on Magma Bar if showing text on bars
	Added separate Windshear bar - default is off
	GCD bar now has option to show it as a full width bar
	
Version 4.42
	Fix for Vehicle Exiting disabling priority frame
	
Version 4.43
	Fix for bindings taint bug
	
Version 4.50
	Added warning option if your grounding totem grounds a spell 
	Added warning option if you purge a spell
	Added warning option if you interrupt a spell
	Added spell casting icon to priority frame to show you when an enemy is casting a spell that might be interrupted
	Added purge icon to priority frame to show you when the enemy has a purgeable buff
	
Version 5.00
	Expanded priorities to have 16 options
	Renamed all occurrences of Wind Shock to Wind Shear
	Added red border to interrupt frame if Wind Shear on cooldown - thanks to Naxino of EU Khadgar for assisting testing
	Added LL_QE to priority options
	Added option to show cooldown "clock" on priority frame - excellent suggestion by Aramis on MMO-Champion forums
		Recommend turning GCD bar off and using cooldown clock and setting priority cooldown time to 0.5 seconds up from 0.25
	Fixed incorrect speed export to EnhSim
	Added check for missing Priority in case priority list gets corrupted
	Moved default location of priority frame to avoid icon overlaps
	Added optional Flameshock dot bar
	Fixed priority when target changing
	
Version 5.01
	Made Flameshot dot an independent bar and put it above stormstrike
	Shortened WF messages output to Scrolling Combat Text
	Turning off Purge or Interrupt frames now actually hides the frame
	Added belt and braces check for Flameshock and Stormstike buffs being players and no one elses
	Fixed bug where priority frame was disappearing if ANYONE in party went into a vehicle during a fight. 
		Now correctly disappears if PLAYER enters vehicle (as you can't use your own abilities in vehicle)
		
Version 5.10
	Added MW3_LB, MW3_CL priorities to the possiblities.
	Also added Fire Nova (FN) and Fire Elemental (FE) priorities
	Searing Totem, Magma Totem & Fire Elemental Totem now share a fire totem bar
	Altered default priority list
	Added test for fire totem being destroyed early removing the fire totem bar - thanks to Holls on Brill EU PTR for testing
	Fixed export of Feral Spirits glyph not showing in EnhSim Export
	Fix for feral spirit icon sometimes remaining visible outside combat
	
Version 5.20
	Fixed Russian Localisation
	Added extra localisations from Curseforge localisation setup
	Changed all localisations to use Curseforge.com automated localisations
	Added feature to hide spells from the priority list that the target is immune to
	Added option to turn hide immunity on and off
	Added SS_0 option to use SS if no debuff on target
	Added FS_Boss option to only use Feral Spirits on Boss
	Added priority frame scaling
	Fixed bar scaling
	
Version 5.21
	Updated Localisations on Curseforge.com should fix muliple locale errors from missing locale values in v5.20
	
Version 5.22
	Fixed typo in "Stormstrike if no debuff"
	
Version 5.23
	Force update to Curse.com
	
Version 5.24
	Force all non English localisations to use English phrases if no localisation has been added to the site 
	at http://wow.curseforge.com/addons/shockandawe/localization/ for that phrase
	
Version 5.25
	Default options now are patch 3.2 vs patch 3.3 aware so it doesnt turn on patch 3.3 versions when running on patch 3.2
	Added Booming Echoes shortens Flame Shock & Frost Shock bar length
	Shield bar now changes colour when shield orbs reach the minimum user selected level

Version 5.30
	You can now set up to five different priority sets for use in different circumstances
	Added five possible key bindings for selecting five possible priority groups
	
Version 5.40
	Added export support for necrotic touch (Black Bruise's proc) and mixology if you are an alchemist
	Fix for altering bar width causing crash
	Add dual spec support - now asks if you want to enable/disable addon on switching specs.
	
Version 5.41
	Added FE_boss option to only recommend Fire Elemental when on a boss
	Added query about enabling/disabling addon based on spec when addon initialises (eg: to turn off if login in Resto spec after a DC)
	
Version 5.42
	Added set number display above priority box if text shown
	Fix for setting priorities not sticking between reloads
	Added default AoE priority list
	Fix for trying to scale or set width whilst moving frames
	
Version 5.50
	Added support for Fire Nova bar
	
Version 5.51
	Fixed problem where default options were reset on relog
	
Version 5.52
	Fixed missing locale value when changing priorities
	Added Stormstrike debuff count on bar if showing bar text
	Added extra locale values
	
Version 5.53
	Added check if options are empty to warn user
	Reworked Maelstrom weapon bar display to hopefully fix issue with the alpha being zero after a flash
	
Version 5.60
	Added additional checks on loading options if options are empty to warn user
	Added option to output to MikScrollingBattleText if installed. This requires selecting an output frame in the warnings options section
	Refactored Fire totems to check if other fire totem is down before recommending new one.
	Force load of priority options on zoning to ensure that options aren't lost
	
Version 5.61
	Added FlameShock on Boss option
	Default prioirty options were not getting set for clean install
	Added feature to refresh Magma totem X ticks before it expires
	FS Dot bar should no longer require Shock bar to be visible
	Renamed locales that had Magma Bar to Fire Bar
	
Version 5.62
	Missed a locale setting for Magma Bar -> Fire Bar
	
Version 5.63
	Make priority for refreshing Magma totem no longer reliant on showing Fire totem bar
	
Version 5.70
	Added Improved Fire Nova to EnhSim export
	Added Ashen verdict ring proc to EnhSim export
	Added glove & cloak enchants to EnhSim export
	Added SR & SR_Boss priorities to work with T10 set bonus
	Added set bonuses to EnhSim export
	
Version 5.71
	Added LS_0 and MT_0
	
Version 5.72
	Fixed missing localisation for LS_0
	added check when showing purge & interrupt frames that the frames have been created
	
Version 5.73
	Added check to see if player is level 60 or higher before asking to disable addon
	Added check to stop displaying priority frame if addon disabled
	Added option verification check to replace nils with "none"
	Priority Frame should no longer be moveable in combat
	
Version 5.80
	Fix fire totem timer bars for duration of magma totem being not quite exactly 20 seconds 
	Add text if barstext on to FlameShock Dot Bar
	Affect FlameShock Dot Bar by haste
	Remove Unleashed Rage uptime as its now a 100% aura
	Properly Implemented FSTicksLeft option now advises to refresh FS if less than X ticks lefts
	Altered single target priority defaults
	
Version 5.81
	Fix big lag when lighting shield expires out of combat
	Fix magma totem priority if dropped via Call of the XXXX
	
Version 5.82
	Fix TOC file to 30300 from 30303 as that wasn't being recognised as up to date
	
--]]

if select(2, UnitClass('player')) ~= "SHAMAN" then
	DisableAddOn("ShockAndAwe")
	return
end

local L = LibStub("AceLocale-3.0"):GetLocale("ShockAndAwe")
local AceAddon = LibStub("AceAddon-3.0")
local media = LibStub:GetLibrary("LibSharedMedia-3.0")
ShockAndAwe = AceAddon:NewAddon("ShockAndAwe", "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0")
local SCT = SCT
local REVISION = tonumber(("$Revision: 327 $"):match("%d+"))
local _, _, _, clientVersion = GetBuildInfo()
ShockAndAwe.constants = {}
local C = ShockAndAwe.constants -- Defined in ShockAndAwe LUA no locale needed.
local queryDisable = false

C["Stormstrike"], _, C["Stormstrike Icon"] = GetSpellInfo(32176)
C["Windfury Attack"], _, C["Windfury Attack Icon"] = GetSpellInfo(25584)
C["Frost Shock"], _, C["Frost Shock Icon"] = GetSpellInfo(49236)
C["Earth Shock"], _, C["Earth Shock Icon"] = GetSpellInfo(49231)
C["Flame Shock"], _, C["Flame Shock Icon"] = GetSpellInfo(49233)
C["Wind Shear"], _, C["Wind Shear Icon"] = GetSpellInfo(57994)
C["Lava Lash"], _, C["Lava Lash Icon"] = GetSpellInfo(60103)
C["Maelstrom Weapon"], _, C["Maelstrom Weapon Icon"] = GetSpellInfo(51532)
C["Water Shield"], _, C["Water Shield Icon"] = GetSpellInfo(33736)
C["Lightning Shield"], _, C["Lightning Shield Icon"] = GetSpellInfo(49281)
C["Earth Shield"], _, C["Earth Shield Icon"] = GetSpellInfo(49284)
C["Elemental Devastation"], _, C["Elemental Devastation Icon"] = GetSpellInfo(29178)
C["Flurry"], _, C["Flurry Icon"] = GetSpellInfo(16284)
C["Unleashed Rage"], _, C["Unleashed Rage Icon"] = GetSpellInfo(30809)
C["Windfury Weapon"], _, C["Windfury Weapon Icon"] = GetSpellInfo(58804)
C["Flametongue Weapon"], _, C["Flametongue Weapon Icon"] = GetSpellInfo(58790)
C["Frostbrand Weapon"], _, C["Frostbrand Weapon Icon"] = GetSpellInfo(58796)
C["Earthliving Weapon"], _, C["Earthliving Weapon Icon"] = GetSpellInfo(51994)
C["Lightning Bolt"], _, C["Lightning Bolt Icon"] = GetSpellInfo(49238)
C["Chain Lightning"], _, C["Chain Lightning Icon"] = GetSpellInfo(49271)
C["Heroic Presence"], _, _ = GetSpellInfo(28878)
C["Champion of the Kirin Tor"], _, _ = GetSpellInfo(57821)
C["Shamanistic Rage"], _, C["Shamanistic Rage Icon"] = GetSpellInfo(30823)
C["Feral Spirit"], _, C["Feral Spirit Icon"] = GetSpellInfo(51533)
C["Healing Wave"], _, C["Healing Wave Icon"] = GetSpellInfo(49273)
C["Chain Heal"], _, C["Chain Heal Icon"] = GetSpellInfo(55459)
C["Searing Totem"], _, C["Searing Totem Icon"] = GetSpellInfo(58704)
C["Magma Totem"], _, C["Magma Totem Icon"] = GetSpellInfo(58734)
C["Feral Spirit"], _, C["Feral Spirit Icon"] = GetSpellInfo(51533)
C["Totemic Call"], _, C["Totemic Call Icon"] = GetSpellInfo(36936)
C["Grounding Totem"], _, _ = GetSpellInfo(8177)
C["Purge"], _, C["Purge Icon"] = GetSpellInfo(8012)
C["Volcanic Fury"], _, C["Volcanic Fury"] = GetSpellInfo(67391)
C["Flametongue Totem"], _, C["Flametongue Totem Icon"] = GetSpellInfo(8227)
C["Frost Resistance Totem"], _, C["Frost Resistance Totem Icon"] = GetSpellInfo(8181)
C["Fire Nova"], _, C["Fire Nova Icon"] = GetSpellInfo(1535)
C["Fire Elemental Totem"], _, C["Fire Elemental Totem Icon"] = GetSpellInfo(32982)


ShockAndAwe.frames = {}

ShockAndAwe.BaseFrame = CreateFrame("Frame","ShockAndAweBase",UIParent)
ShockAndAwe.frames["Maelstrom"] = CreateFrame("Frame","SAA_Bar1_Status", ShockAndAwe.BaseFrame) 
ShockAndAwe.frames["Maelstrom"].icon = CreateFrame("Frame","SAA_Bar1_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["fireTotem"] = CreateFrame("Frame","SAA_Bar9_Status", ShockAndAwe.BaseFrame) 
ShockAndAwe.frames["fireTotem"].icon = CreateFrame("Frame","SAA_Bar9_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Stormstrike"] = CreateFrame("Frame","SAA_Bar2_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Stormstrike"].icon = CreateFrame("Frame","SAA_Bar2_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shock"] = CreateFrame("Frame","SAA_Bar3_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shock"].icon = CreateFrame("Frame","SAA_Bar3_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shear"] = CreateFrame("Frame","SAA_Bar3a_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shear"].icon = CreateFrame("Frame","SAA_Bar3a_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Windfury"] = CreateFrame("Frame","SAA_Bar4_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shield"] = CreateFrame("Frame","SAA_Bar5_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["Shield"].icon = CreateFrame("Frame","SAA_Bar5_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["LavaLash"] = CreateFrame("Frame","SAA_Bar6_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["LavaLash"].icon = CreateFrame("Frame","SAA_Bar6_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FeralSpirit"] = CreateFrame("Frame","SAA_Bar7_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FeralSpiritCD"] = CreateFrame("Frame","SAA_Bar7a_Status",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FeralSpirit"].icon = CreateFrame("Frame","SAA_Bar7_StatusIcon",ShockAndAwe.BaseFrame)
ShockAndAwe.frames["GCD"] = CreateFrame("Frame", "SAA_Bar8_Status", ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FS_DOT"] = CreateFrame("Frame", "SAA_Bar9_Status", ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FS_DOT"].icon = CreateFrame("Frame", "SAA_Bar9_StatusIcon", ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FireNova"] = CreateFrame("Frame", "SAA_Bar10_Status", ShockAndAwe.BaseFrame)
ShockAndAwe.frames["FireNova"].icon = CreateFrame("Frame", "SAA_Bar10_StatusIcon", ShockAndAwe.BaseFrame)
ShockAndAwe.msgFrame = CreateFrame("MessageFrame","ShockAndAweMsg",UIParent)
ShockAndAwe.questionFrame = CreateFrame("Frame","ShockAndAweQuestion",UIParent)

ShockAndAwe.textures = {}
ShockAndAwe.borders = {}
ShockAndAwe.fonts = {}
ShockAndAwe.sounds = {}
ShockAndAwe.barBackdrop = {
		bgFile = "Interface/Tooltips/UI-Tooltip-Background",
		edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = false, tileSize = 0, edgeSize = 12,
		insets = { left = 2, right = 2, top = 2, bottom = 2 }
	}
ShockAndAwe.frameBackdrop ={
		bgFile = "Interface/Tooltips/UI-Tooltip-Background",
		--edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = false, tileSize = 0, edgeSize = 12,
		insets = { left = 0, right = 0, top = 0, bottom = 0 }
	}
ShockAndAwe.GCDMin = 0
ShockAndAwe.GCDMax = 0
ShockAndAwe.GCDWidth = 0
	
local SSmin, SSmax, ShockMin, ShockMax, ShearMin, ShearMax, WFPMin, WFPMax, ShieldMin, ShieldMax, MaelstromMin, MaelstromMax
local LLMin, LLMax, FSMin, FSMax, FSCDMin, FSCDMax, FireTotemMin, FireTotemMax, GCDPercent, FSDotTime, FNmin, FNmax
local updateActiveSS = false
local updateActiveFireTotem = false
local updateActiveMaelstrom = false
local updateActiveLavaLash = false
local updateActiveShock = false
local updateActiveFSDot = false
local updateActiveShear = false
local updateActiveShamanistic = false
local updateActiveWFProc = false
local updateActiveShield = false
local updateActiveFeralSpiritCD = false
local updateActiveGCD = false
local updateActiveFN = false
local WFProcTime = 0
local SSTime = 0
local FireTotemTime = 0
local FNTime = 0
local GCDTime = 0
local LLTime = 0
local FSTime = 0
local FSCDTime = 0
local ShockTime = 0
local FSDotTime = 0
local ShearTime = 0
local ShieldTime = 0
local lastSound = 0
local mw4played = false
local mwflashing = false
local fireTotemGUID = 0

-----------------------------------------
-- Initialisation & Startup Routines
-----------------------------------------

function ShockAndAwe:OnInitialize()
	local AceConfigReg = LibStub("AceConfigRegistry-3.0")
	local AceConfigDialog = LibStub("AceConfigDialog-3.0")

	self.db = LibStub("AceDB-3.0"):New("ShockAndAweDBPC", ShockAndAwe.defaults, "char")
	self:GetMSBTAreaDefaults()
	LibStub("AceConfig-3.0"):RegisterOptionsTable("ShockAndAwe", self:GetOptions(), {"shockandawe", "saa"} )
	media.RegisterCallback(self, "LibSharedMedia_Registered")
	
	-- Add the options to blizzard frame (add them backwards so they show up in the proper order
	self.optionsFrame = AceConfigDialog:AddToBlizOptions("ShockAndAwe", "ShockAndAwe")
	self.db:RegisterDefaults(self.defaults)
	if not self.db.char.immuneTargets then
		self.db.char.immuneTargets = {}
	end
	self:InitialiseUptime()
	self:InitialiseBindings()
	self:CreateUptimeFrame()
	self:CreatePriorityFrame()
	self:CreateMsgFrame()
	self:News()
	self:EnablePetFrame()
	self:VerifyOptions()
	local version = GetAddOnMetadata("ShockAndAwe","Version")
	self.version = ("ShockAndAwe v%s (r%s)"):format(version, REVISION)
	self:Print(self.version.." Loaded.")
end

function ShockAndAwe:OnDisable()
    -- Called when the addon is disabled
	self:UnregisterEvent("PLAYER_ENTERING_WORLD")
	self:UnregisterEvent("PLAYER_LOGIN")
	self:UnregisterEvent("PLAYER_ALIVE")
	self:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	self:UnregisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
	self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	self:UnregisterEvent("UNIT_AURA")
	self:UnregisterEvent("UNIT_MANA")
	self:UnregisterEvent("CHARACTER_POINTS_CHANGED")
	self:UnregisterEvent("PLAYER_REGEN_DISABLED")
	self:UnregisterEvent("PLAYER_REGEN_ENABLED")
	self:UnregisterEvent("PLAYER_TARGET_CHANGED")
	self:UnregisterEvent("SPELL_UPDATE_COOLDOWN")
	self:UnregisterEvent("UPDATE_BINDINGS")
	self:UnregisterEvent("UI_ERROR_MESSAGE")
-- we must still look out for talent changes to fire change of spec to re-enable
--	self:UnregisterEvent("PLAYER_TALENT_UPDATE")
--	self:UnregisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
	self:UnregisterEvent("UNIT_EXITED_VEHICLE")
	self:UnregisterEvent("UNIT_ENTERED_VEHICLE")
end

function ShockAndAwe:OnEnable()
	self:LibSharedMedia_Registered()
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("PLAYER_LOGIN")
	self:RegisterEvent("PLAYER_ALIVE")
	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	self:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE")
	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")
	self:RegisterEvent("UNIT_AURA")
	self:RegisterEvent("UNIT_MANA")
	self:RegisterEvent("CHARACTER_POINTS_CHANGED")
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_TARGET_CHANGED")
	self:RegisterEvent("SPELL_UPDATE_COOLDOWN")
	self:RegisterEvent("UPDATE_BINDINGS")
	self:RegisterEvent("UI_ERROR_MESSAGE")
	self:RegisterEvent("PLAYER_TALENT_UPDATE")
	self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
	self:RegisterEvent("UNIT_ENTERED_VEHICLE")
	self:RegisterEvent("UNIT_EXITED_VEHICLE")
end

function ShockAndAwe:LibSharedMedia_Registered()
	media:Register("sound", "SAA Maelstrom 1", "Sound\\Spells\\ShootWandLaunchLightning.wav")
	media:Register("sound", "SAA Maelstrom 2", "Sound\\Spells\\DynamiteExplode.wav")
	media:Register("sound", "SAA Maelstrom 3", "Sound\\Spells\\ArmorKitBuffSound.wav")
	media:Register("sound", "SAA Maelstrom 4", "Sound\\Spells\\Fizzle\\FizzleShadowA.wav")
	media:Register("sound", "SAA Maelstrom 5", "Sound\\Spells\\LevelUp.wav")
	media:Register("sound", "SAA Maelstrom 6", "Sound\\Spells\\Tradeskills\\FishBite.wav")
	media:Register("sound", "SAA Maelstrom 7", "Sound\\Spells\\Tradeskills\\MiningHitA.wav")
	media:Register("sound", "SAA Maelstrom 8", "Sound\\Spells\\AspectofTheSnake.wav")
	media:Register("sound", "SAA Maelstrom 9", "Sound\\Spells\\bind2_Impact_Base.wav")
	media:Register("sound", "SAA Shield 1", "Sound\\Doodad\\BellowIn.wav")
	media:Register("sound", "SAA Shield 2", "Sound\\Doodad\\BellowOut.wav")
	media:Register("sound", "SAA Shield 3", "Sound\\Doodad\\PVP_Lordaeron_Door_Open.wav")
	media:Register("sound", "SAA Shield 4", "Sound\\Spells\\ShaysBell.wav")

	for k, v in pairs(media:List("statusbar")) do
		self.textures[v] = v
	end
	for k, v in pairs(media:List("border")) do
		self.borders[v] = v
	end
	for k, v in pairs(media:List("font")) do
		self.fonts[v] = v
	end
	for k, v in pairs(media:List("sound")) do
		self.sounds[v] = v
	end
end

----------------------
-- Event Routines
----------------------

function ShockAndAwe:UNIT_ENTERED_VEHICLE()
	if UnitInVehicle("player") then
		self:TidyUpAfterCombat() -- on entering vehicle treat as if out of combat ie: disable incombat displays
	end
end

function ShockAndAwe:UNIT_EXITED_VEHICLE()
	if not UnitInVehicle("player") and InCombatLockdown() then
		self:EnteredCombat()  -- if in combat when exit vehichle enable ShockAndAwe combat effects
	end
end

function ShockAndAwe:UNIT_MANA()
	self:UpdateShieldBar()
end

function ShockAndAwe:PLAYER_ENTERING_WORLD()
	self:SetBorderTexture(nil, self.db.char.border)
	self:SetBarBorderTexture(nil, self.db.char.barborder)
	self:SetTalentEffects()
	self:RedrawFrames()
	self:UpdateBindings()
	self.db.char.priority.option = self.db.char.priority.options[self.db.char.priority.groupnumber]
end

function ShockAndAwe:PLAYER_LOGIN()
	self:SetBorderTexture(nil, self.db.char.border)
	self:SetBarBorderTexture(nil, self.db.char.barborder)
	queryDisable = false -- when player first logs in set test for talents in Enh Spec to false
end

function ShockAndAwe:PLAYER_ALIVE()
	self:SetTalentEffects()
	self:RedrawFrames()
	self:UpdateBindings()
	if not queryDisable then -- only ask if not in Enh and addon active if this is fired immediately after first login
		self:QueryDisableAddon()
		queryDisable = true
	end
end

function ShockAndAwe:UNIT_AURA()
	if (arg1 == "player") then
		self:UpdateShieldBar()
		if self.db.char.maelstromTalents > 0 then
			updateActiveMaelstrom = true
			self.db.char.msstacks = self:GetMaelstromInfo()
			if self.db.char.barstext and self.db.char.msshow then
				self.frames["Maelstrom"].text:SetText(self.db.char.msstacks.." stacks")
			else 
				self.frames["Maelstrom"].text:SetText("")
			end
			self:MaelstromBar()
		end
	end
end

function ShockAndAwe:CHAT_MSG_SPELL_SELF_DAMAGE()
	if self.db.char.wfshow then
		if strfind(arg1, L["WF_Attack"]) then
			self:WFProcBar()
		end
	end
end

function ShockAndAwe:UI_ERROR_MESSAGE()
	if self.db.char.warning.range then
		if strfind(arg1, L["Out of range"]) or strfind(arg1, L["too far away"]) then
			self:PrintMsg(arg1, self.db.char.warning.colour, 0.5)
		end
	end
end

function ShockAndAwe:COMBAT_LOG_EVENT_UNFILTERED(_, timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
	if sourceGUID == UnitGUID("player") then
		local spellID = select(1,...) or 0
		if spellID == self.combat.wf_mh or spellID == self.combat.wf_oh then 
			if self.db.char.wfshow then
				self:WFProcBar()
			end
		end
		if self.db.char.stats.wfcalc then
			if event == "SWING_DAMAGE" then
				self:WFCalc("melee", select(1,...), select(7,...), event, dstName, destFlags, destGUID)
			elseif event == "SWING_MISSED" then
				self:WFCalc("melee", select(5,...), nil, event)
			elseif event == "SPELL_DAMAGE" then
				self:WFCalc(spellID, select(4,...), select(10,...), event, dstName, destFlags, destGUID)
			elseif event == "SPELL_MISSED" then
				self:WFCalc(spellID, select(5,...), nil, event, dstName, destFlags, destGUID)
			end
		end
		if event == "SPELL_AURA_REMOVED" then
			if GetSpellInfo(spellID) == C["Lightning Shield"] or GetSpellInfo(spellID) == C["Water Shield"] then
				if self.db.char.warning.shield then
					self:PrintMsg(GetSpellInfo(spellID).." "..L["Expired"], self.db.char.warning.colour, self.db.char.warning.duration)
					PlaySoundFile(self.db.char.shieldsound)
				end
				if not InCombatLockdown() then
					collectgarbage()
				end
			end
		end
		if self.db.char.fsdotshow and (event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REFRESH") then
			if GetSpellInfo(spellID) == C["Flame Shock"] then
				self:FlameShockDotBar(true) -- debuff applied so setup bar
			end
		end
		if self.db.char.warning.interrupt and event == "SPELL_INTERRUPT" then
			local spellName = select(5,...)
			if spellName then
				self:PrintMsg(L["Interrupted: "] .. spellName, self.db.char.warning.colour, self.db.char.warning.duration)
			end
		end
		if self.db.char.warning.purge and event == "SPELL_DISPEL"  and (spellID == 370 or spellID == 8012) then
			local spellName = select(5,...)
			if spellName then
				self:PrintMsg(L["Purged: "] .. spellName, self.db.char.warning.colour, self.db.char.warning.duration)
			end
		end
		if event == "SPELL_SUMMON" and self:IsFireTotem(spellID) then
			fireTotemGUID = destGUID
		end
		if event == "SPELL_MISSED" then
			local missType = select(4, ...) or ""
			if missType == "IMMUNE" then
				local spellName = select(2, ...) or ""
				self.db.char.immuneTargets[destName.."_"..spellName] = true
			end
		end
		if event == "SPELL_DAMAGE" then
			local spellName = select(2, ...) or ""
			if self.db.char.immuneTargets[destName.."_"..spellName] then
				-- clear immunity if we managed to damage target with this spell - ie: it was a temporary immunity
				self.db.char.immuneTargets[destName.."_"..spellName] = nil
			end
		end
	else -- here its not the player who cast the spell so we are looking at grounding totem doing its job
		if self.db.char.warning.grounding then
			if math.fmod(destFlags,65536) == 8465 and destName == C["Grounding Totem"] then
				local spellname = select(2,...)
				local damage = select(4,...) or "0"
				if spellname and damage ~= "0" then
					self:DebugPrint("grounded "..spellname.." damage:"..damage)
					self:PrintMsg(L["Grounded: "] .. spellname .. string.format(" (%s)",strlower(damage)), self.db.char.warning.colour, self.db.char.warning.duration)
				end
			end
		end
	end
	if destGUID == UnitGUID("player") and self.db.char.warning.weapon and not self.db.char.castweaponrebuff then
		if event == "ENCHANT_REMOVED" then
			if self:MainHandBuffMissing() or self:OffHandBuffMissing() then
				self:PrintMsg(L["Weapon Buff Expired"], self.db.char.warning.colour, self.db.char.warning.duration)
				PlaySoundFile(self.db.char.weaponsound)
			end
		end
	end
	if event == "UNIT_DIED" and destGUID == fireTotemGUID then
		self.frames["fireTotem"]:Hide()
		self.frames["fireTotem"].icon:Hide()
		FireTotemTime = GetTime()
		self.db.char.priority.magmatime = FireTotemTime
	end
end

function ShockAndAwe:SPELL_UPDATE_COOLDOWN()
	if self.db.char.gcdshow then
		self:GCDBar()
	end
end

function ShockAndAwe:UNIT_SPELLCAST_SUCCEEDED()
	if arg1 == "player" then -- skip if someone else casting
		if self.db.char.ssshow then
			if arg2 == C["Stormstrike"] then
				self:StormstrikeBar()
			end
		end
		if self.db.char.fnshow then
			if arg2 == C["Fire Nova"] then
				self:FireNovaBar()
			end
		end
		if self.db.char.shieldshow then
			self:SetShieldType(arg2)
			self:UpdateShieldBar()
		end	
		if arg2 == C["Earth Shock"] then
			local colours = self.db.char.colours.earthshock
			self.db.char.lastshock = C["Earth Shock"]
			self:SetBarIcon(self.frames["Shock"].icon, 8042)
			if self.db.char.shockshow then
				self:ShockBar(colours)
			end
		elseif arg2 == C["Flame Shock"] then
			local colours = self.db.char.colours.flameshock
			self.db.char.lastshock = C["Flame Shock"]
			self:SetBarIcon(self.frames["Shock"].icon, 8050)
			if self.db.char.shockshow then
				self:ShockBar(colours)
			end
		elseif arg2 == C["Frost Shock"] then
			local colours = self.db.char.colours.frostshock
			self.db.char.lastshock = C["Frost Shock"]
			self:SetBarIcon(self.frames["Shock"].icon, 8056)
			if self.db.char.shockshow then
				self:ShockBar(colours)
			end
		end
		if self.db.char.shearshow and arg2 == C["Wind Shear"] then
				self:SetBarIcon(self.frames["Shear"].icon, 57994)
				self:ShearBar()
		end
		if arg2 == C["Magma Totem"] or arg2 == C["Searing Totem"] or 
		   arg2 == C["Fire Elemental Totem"]  or arg2 == C["Frost Resistance Totem"]  or arg2 == C["Flametongue Totem"] then 
			self:FireTotemBar(arg2)
		end
		if arg2 == C["Totemic Call"] then
			FireTotemTime = GetTime()
			self.db.char.priority.magmatime = FireTotemTime
		end
		if self.db.char.llshow then
			if arg2 == C["Lava Lash"] then 
				self:LavaLashBar()
			end
		end
		if self.db.char.fsshow then
			if arg2 == C["Feral Spirit"] then 
				self:FeralSpiritBar()
			end
		end
		if arg2 == C["Windfury Weapon"] or arg2 == C["Flametongue Weapon"] or arg2 == C["Frostbrand Weapon"] or arg2 == C["Earthliving Weapon"] then
			self.db.char.castweaponrebuff = true
		else
			self.db.char.castweaponrebuff = false
		end
	end
end

function ShockAndAwe:CHARACTER_POINTS_CHANGED()
	self:SetTalentEffects()
	self:CreateBaseFrame()
end

function ShockAndAwe:PLAYER_REGEN_DISABLED() -- Entering Combat
	self:EnteredCombat()
end

function ShockAndAwe:PLAYER_REGEN_ENABLED() -- Leaving Combat
	self:TidyUpAfterCombat()
end

function ShockAndAwe:PLAYER_TARGET_CHANGED()
	if self.db.char.priority.show and InCombatLockdown() then
		self:FlameShockDotBar(false) -- force update on FS dot bar after target change
		self:SetNextPriority()
	end
end

function ShockAndAwe:UPDATE_BINDINGS()
	if not InCombatLockdown() then
		self:UpdateBindings()
	end
end

function ShockAndAwe:PLAYER_TALENT_UPDATE()
	self:SetTalentEffects()
	self:RedrawFrames()
end

function ShockAndAwe:ACTIVE_TALENT_GROUP_CHANGED()
	self:QuerySpecChanged()
end

----------------------------
-- Combat start and stop
----------------------------

function ShockAndAwe:EnteredCombat()
	if UnitInVehicle("player") then -- don't enable priorities & bars if we enter combat in a vehicle
		return
	end
	if self.db.char.disablebars then
		self.BaseFrame:Show()
	end
	if self.db.char.msshow then
		self:SetMaelstromAlpha(self.db.char.colours.msalpha) -- set maelstrom frame to in combat alpha
	end
	if self.db.char.fsshow then
		FSMin, FSMax = self.frames["FeralSpirit"].statusbar:GetMinMaxValues()
		updateActiveFeralSpirit = true -- forces an update to check if puppies still available on re-entering combat
		self:FeralSpiritCDBar()
	end
	if self.db.char.uptime.show then
		if not self.uptime.incombat then
			self.uptime.incombat = true
			-- reset last fight data on entering combat
			self:InitialiseUptimeBuffs(self.uptime.lastfight)
			self.uptime.currentTime = GetTime()
			self:UpdateUptime()
			self:UpdateUptimeFrames(true)
			self.uptime.TimerEvent = self:ScheduleRepeatingTimer("UpdateUptime", 0.1, nil);
		end
	end
	if self.db.char.maelstromTalents == 0 then -- check MW talents again to counter Player_Entering_World bug
		self:SetTalentEffects()
		self:CreateBaseFrame()
	end
	if self.db.char.priority.show and not self.db.char.disabled then
		self.db.char.priority.next = "none"
		self:SetPriorityIcon(self.db.char.priority.next)
		self.updatePriority = true
		self.PriorityFrame:Show()
	end
	if self.db.char.warning.weapon then
		if self:MainHandBuffMissing() or self:OffHandBuffMissing() then
			self:PrintMsg(L["Missing Weapon Buffs"], self.db.char.warning.colour, self.db.char.warning.duration)
			PlaySoundFile(self.db.char.weaponsound)
		end
	end
	lastshock = ""
end

function ShockAndAwe:TidyUpAfterCombat()
	self.frames["Maelstrom"]:Hide()
	self.frames["Maelstrom"].icon:Hide()
	self.frames["Shield"].icon:Hide()
	self.frames["Shock"].icon:Hide()
	self.frames["Shear"].icon:Hide()
	self.frames["Stormstrike"].icon:Hide()
	self.frames["LavaLash"].icon:Hide()
	self:SetPriorityIcon("none")
	self.updatePriority = false
	self.PriorityFrame:Hide()
	if self.db.char.uptime.show then
		if self.uptime.incombat then
			self:UpdateUptime()
			self.uptime.incombat = false
			self:UpdateUptimeFrames(true)
			self:CancelTimer(self.uptime.TimerEvent , false)
		end
	end
	if self.db.char.fsshow then
		self.frames["FeralSpirit"].icon:Hide() 
		self.frames["FeralSpiritCD"]:Hide()
	end
	if self.db.char.disablebars then
		self.BaseFrame:Hide()
	end
	if not self.db.char.binding.macroset then
		-- call update Bindings to set macro keys if we were in combat when addon initialised
		self:UpdateBindings()
	end
	collectgarbage()
end

----------------------------
-- Question box handler
----------------------------

function ShockAndAwe:QuerySpecChanged()
	if self.db.char.maelstromTalents == 0 and not self.db.char.disabled then
		-- addon is enabled but we have changed to a non Enhance Spec ask if we should disable addon
		self:DisplayQuestionFrame(false, true)
	elseif self.db.char.maelstromTalents > 0 and self.db.char.disabled then
		-- addon is disabled and we have changed to an Enhance Spec ask if we should enable addon
		self:DisplayQuestionFrame(true, true)
	end
end

function ShockAndAwe:QueryDisableAddon()
	if self.db.char.maelstromTalents == 0 then -- check MW talents again to counter Player_Entering_World bug
		self:SetTalentEffects()
	end
	if UnitLevel("player") >= 60 then -- don't bother asking to disable addon if player under level 60.
		if self.db.char.maelstromTalents == 0 and not self.db.char.disabled then
			-- addon is enabled but we have changed to a non Enhance Spec ask if we should disable addon
			self:DisplayQuestionFrame(false, false)
		elseif self.db.char.maelstromTalents > 0 and self.db.char.disabled then
			-- addon is disabled and we have changed to an Enhance Spec ask if we should enable addon
			self:DisplayQuestionFrame(true, false)
		end
	end
end

StaticPopupDialogs["SAA_QUESTION_FRAME"] = {
	text = L["You have changed to a new talent spec do you want to enable ShockAndAwe?"],
	button1 = "Yes",
	button2 = "No",
	OnAccept = function()
		ShockAndAwe:EnableDisable()
	end,
	timeout = 0,
	hideOnEscape = 1,
}

function ShockAndAwe:DisplayQuestionFrame(enable, spec)
	if spec then
		if enable then 
			StaticPopupDialogs["SAA_QUESTION_FRAME"].text = L["You have changed to a new talent spec do you want to enable ShockAndAwe?"]
		else
			StaticPopupDialogs["SAA_QUESTION_FRAME"].text = L["You have changed to a new talent spec do you want to disable ShockAndAwe?"]
		end
	else
		if enable then 
			StaticPopupDialogs["SAA_QUESTION_FRAME"].text = L["You are in Enhancement spec do you want to enable ShockAndAwe?"]
		else
			StaticPopupDialogs["SAA_QUESTION_FRAME"].text = L["You are NOT in Enhancement spec do you want to disable ShockAndAwe?"]
		end
	end
	self:DebugPrint("entered DisplayQuestionFrame, text is :"..StaticPopupDialogs["SAA_QUESTION_FRAME"].text)
	StaticPopup_Show("SAA_QUESTION_FRAME")
end
	
-------------------------
-- Shield bar routines
-------------------------

function ShockAndAwe:GetShieldInfo()
	local index = 1
	ShieldTime = 0
	while UnitBuff("PLAYER", index) do
		local name, _, _, count, _, _, shieldExpires = UnitBuff("PLAYER", index)
		ShieldTime = shieldExpires
		if self:SetShieldType(name) then
			return count, name, shieldExpires
		end
		index = index + 1
	end
	return 0, "", 0
end

function ShockAndAwe:SetShieldType(name)
	local colours = self.db.char.colours;
	if name == C["Water Shield"] then
		self:ShieldBar(colours.watershield.r, colours.watershield.g, colours.watershield.b, colours.watershield.a)
		self:SetBarIcon(self.frames["Shield"].icon, 52127)
		return true
	elseif name == C["Lightning Shield"] then
		self:ShieldBar(colours.lightningshield.r, colours.lightningshield.g, colours.lightningshield.b, colours.lightningshield.a)
		self:SetBarIcon(self.frames["Shield"].icon, 324)
		return true
	elseif name == C["Earth Shield"] then
		self:ShieldBar(colours.earthshield.r, colours.earthshield.g, colours.earthshield.b, colours.earthshield.a)
		self:SetBarIcon(self.frames["Shield"].icon, 974)
		return true
	end
	return false
end	

function ShockAndAwe:UpdateShieldBar()
	if self.db.char.shieldshow and not self.db.char.disabled then
		local orbs, shieldType = ShockAndAwe:GetShieldInfo()
		if orbs == 0 then
			updateActiveShield = false
			self.frames["Shield"].spark:Hide()
			self.frames["Shield"].statusbar:SetValue(600)
			if self.db.char.barstext then
				self.frames["Shield"].text:SetText(L["No Shield Active"])
			else
				self.frames["Shield"].text:SetText("")
			end
		else
			updateActiveShield = true
			self.frames["Shield"].spark:Show()
			self.frames["Shield"].statusbar:SetValue(ShieldTime - GetTime())
			if self.db.char.barstext then
				local orbstext = string.format(L["%s orbs remaining"], orbs)
				self.frames["Shield"].text:SetText(orbstext)
			else
				self.frames["Shield"].text:SetText("")
			end
			self.frames["Shield"]:Show()
		end
		if not updateActiveShield then
			local colours = self.db.char.colours
			if UnitMana("player") == UnitManaMax("player") then
				-- shield down but at max mana
				self.frames["Shield"].statusbar:SetStatusBarColor(colours.noshield.r, colours.noshield.g, colours.noshield.b, .2)
				self.frames["Shield"]:SetBackdropBorderColor(1, 1, 1, .2);
			else 
				-- shield down but not at max mana
				self.frames["Shield"].statusbar:SetStatusBarColor(colours.noshield.r, colours.noshield.g, colours.noshield.b, 1)
				self.frames["Shield"]:SetBackdropBorderColor(1, 1, 1, 1);
			end
		end
		self.frames["Shield"].text:Show()
		self:SetShieldType(shieldType)
	else
		self.frames["Shield"]:Hide()
	end
	if self.db.char.disablebars and not InCombatLockdown() then
		self.BaseFrame:Hide()
	end
end

---------------------------
-- Buff Info functions
---------------------------

function ShockAndAwe:GetMaelstromInfo()
	local index = 1
	while UnitBuff("PLAYER", index) do
		local name, _, _, count, _, _, maelstromTime = UnitBuff("PLAYER", index)
		if name == C["Maelstrom Weapon"] then
			return count, maelstromTime
		end
		index = index + 1
	end
	return 0, 0 
end

---------------------------
-- functions
---------------------------

function ShockAndAwe:IsFireTotem(spellID)
	if spellID == 8227 or spellID == 8249 or spellID == 10526 or spellID == 16387 or spellID == 25557 or spellID == 58649 or spellID == 58652 or spellID == 58656 then
		return true
	elseif spellID == 8181 or spellID == 10478 or spellID == 10479 or spellID == 25560 or spellID == 58741 or spellID == 58574 then
		return true
	elseif spellID == 3599 or spellID == 6363 or spellID == 6364 or spellID == 6365 or spellID == 10437 or spellID == 10438 or spellID == 25533 or spellID == 58699 or spellID == 58703 or spellID == 58704 then
		return true
	elseif spellID == 8190 or spellID == 10585 or spellID == 10586 or spellID == 10587 or spellID == 25552 or spellID == 58731 or spellID == 58734 or spellID == 2894 then
		return true
	else
		return false
	end
end

function ShockAndAwe:FireNovaGlyph()
	local numglyphs = GetNumGlyphSockets()
	local fnGlyph = false
	for index = 1, numglyphs do
		local _, _, spellID = GetGlyphSocketInfo(index)
		if spellID == 55544 then
			fnGlyph = true
		end
	end
	if fnGlyph then 
		return 3
	else
		return 0
	end
end

function ShockAndAwe:EnablePetFrame()
	if not oldHasPetUI then 
		oldHasPetUI = HasPetUI; 
		HasPetUI = function() 
				return true, false; 
			end
	end
end

function ShockAndAwe:RedrawFrames()
	self:CreateBaseFrame()
	self:CreateUptimeFrame()
end

function ShockAndAwe:SetTalentEffects()
	local currRank, maxRank
	_, _, _, _, currRank, maxRank = GetTalentInfo(2,28)
	self.db.char.maelstromTalents = currRank
	_, _, _, _, currRank, maxRank = GetTalentInfo(2,23) -- lava lash
	if currRank == 0 then
		self.db.char.lavaLashTalented = false
	else
		self.db.char.lavaLashTalented = true	
	end
	_, _, _, _, currRank, maxRank = GetTalentInfo(1,6) 
	local reverberation = currRank
	_, _, _, _, currRank, maxRank = GetTalentInfo(1,18)
	self.db.char.boomingEchoes = currRank
	if self.db.char.maelstromTalents == 0 then
		updateActiveMaelstrom = false
	end
	_, _, _, _, currRank, maxRank = GetTalentInfo(2,29)
	if currRank == 0 then
		self.db.char.feralSpiritTalented = false
	else
		self.db.char.feralSpiritTalented = true
	end
	_, _, _, _, currRank, maxRank = GetTalentInfo(1,9)
	self.db.char.FNlen = 10 - 2 * currRank - self:FireNovaGlyph()
	-- TODO replace this with programatic gear check if person has arena gear
	if self.db.char.arena then
		self.db.char.SSlen = 6 -- arena bonus reduces by 2 sec.
	else
		self.db.char.SSlen = 8
	end
	if self.db.char.SSlen > self.db.char.FNlen then
		self.db.char.maxLen = self.db.char.SSlen
	else
		self.db.char.maxLen = self.db.char.FNlen
	end
	self.db.char.SSPercent = self.db.char.SSlen /  self.db.char.maxLen
	self.db.char.LLPercent = self.db.char.LLlen / self.db.char.maxLen
	self.db.char.FNPercent = self.db.char.FNlen / self.db.char.maxLen
	self.db.char.ShockLen = 6 - reverberation * 0.2 - self.db.char.boomingEchoes
	self.db.char.EarthShockLen = 6 - reverberation * 0.2
	self.db.char.ShearLen = 6
	self.db.char.ShockPercent = self.db.char.ShockLen / self.db.char.maxLen
	self.db.char.EarthShockPercent = self.db.char.EarthShockLen / self.db.char.maxLen
	self.db.char.ShearPercent = self.db.char.ShearLen / self.db.char.maxLen
	self.db.char.WFProcPercent = 3 / self.db.char.maxLen
	if self.db.char.gcdfullwidth then
		GCDPercent = 1
	else
		GCDPercent = 1.5 / self.db.char.maxLen
	end
end

function ShockAndAwe:DisplayVersion()
	self:Print(self.version)
end

function ShockAndAwe:CreateBaseFrame()
	if not self.db.char.SSPercent or not self.db.char.WFProcPercent or not self.db.char.ShockPercent or not self.db.char.ShearPercent or not self.db.char.LLPercent or not self.db.char.FNPercent or not GCDPercent then
		self:SetTalentEffects()
	end
	self.BaseFrame:SetScale(self.db.char.scale)
	self.BaseFrame:SetFrameStrata("BACKGROUND")
	self.BaseFrame:SetWidth(self.db.char.fWidth + self.db.char.fHeight / 7)
	self.BaseFrame:SetHeight(self.db.char.fHeight)
	self.BaseFrame:SetBackdrop(self.frameBackdrop)
	self.BaseFrame:SetBackdropColor(1, 1, 1, 0)
	self.BaseFrame:SetMovable(true)
	self.BaseFrame:RegisterForDrag("LeftButton")
	self.BaseFrame:SetPoint(self.db.char.point, self.db.char.relativeTo, self.db.char.relativePoint, self.db.char.xOffset, self.db.char.yOffset)
	self.BaseFrame:SetScript("OnDragStart", 
		function()
			self.BaseFrame:StartMoving();
		end );
	self.BaseFrame:SetScript("OnDragStop",
		function()
			self.BaseFrame:StopMovingOrSizing();
			self.BaseFrame:SetScript("OnUpdate", nil);
			self:FinishedMoving(self.db.char, self.BaseFrame);
		end );
	self.BaseFrame:Show()
	self.db.char.movingframes = false
	
	local barHeight = self.db.char.fHeight / 7
	local baseOffset = (-1 * barHeight) + 3
	local barCount = 0
	local colours = self.db.char.colours.feralspiritCD
	ShockAndAwe:SetBarFrame(self.frames["FeralSpiritCD"], 
					self.db.char.fWidth, barHeight,
					barCount * baseOffset, 1,
					0, 180, 
					180, self.db.char.fWidth - 6,
					colours.r, colours.g, colours.b, colours.a,
					false)
	local colours = self.db.char.colours.feralspirit
	ShockAndAwe:SetBarFrame(self.frames["FeralSpirit"], 
					45/180 * self.db.char.fWidth, barHeight,
					barCount * baseOffset, 2,
					0, 45, 
					45, 1,
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.fsshow then
		barCount = barCount + 1 -- we will use feral spirit frame 
	end
	local colours = self.db.char.colours.noshield
	ShockAndAwe:SetBarFrame(self.frames["Shield"], 
					self.db.char.fWidth, barHeight,
					barCount * baseOffset, 1,
					0, 600, 
					600, self.db.char.fWidth - 6,
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.shieldshow then
		barCount = barCount + 1 -- we will use shield frame 
	end
	local colours = self.db.char.colours.magma
	ShockAndAwe:SetBarFrame(self.frames["fireTotem"], 
					self.db.char.fWidth, barHeight,
					barCount * baseOffset, 1,
					0, 20, 
					20, self.db.char.fWidth - 6,
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.firetotemshow then
		barCount = barCount + 1 -- we will use firetotem frame 
	end
	ShockAndAwe:SetBarFrame(self.frames["GCD"], 
					self.db.char.fWidth * GCDPercent, barHeight,
					barCount * baseOffset, 1,
					0, 1.5, 
					6, 1, 
					.6, .6, .6, .6,
					false)
	self.GCDWidth = self.frames["GCD"].statusbar:GetWidth() -- to account for spark width
	if self.db.char.gcdshow then
		barCount = barCount + 1 -- we will use gcd frame 
	end
	colours = self.db.char.colours.maelstrom
	ShockAndAwe:SetBarFrame(self.frames["Maelstrom"], 
					self.db.char.fWidth, barHeight,
					barCount * baseOffset, 1,
					0, 30, 
					6, 1, 
					colours.r, colours.g, colours.b, self.db.char.colours.msalpha,
					true)
	if self.db.char.msshow then
		barCount = barCount + 1 -- we will use maelstrom frame 
	end
	colours = self.db.char.colours.flameshockDot
	ShockAndAwe:SetBarFrame(self.frames["FS_DOT"], 
					self.db.char.fWidth, barHeight, 
					barCount * baseOffset, 1,
					0, 18, 
					1, 0.8, 
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.fsdotshow then
		barCount = barCount + 1
	end
	colours = self.db.char.colours.stormstrike
	ShockAndAwe:SetBarFrame(self.frames["Stormstrike"], 
					self.db.char.fWidth * self.db.char.SSPercent, barHeight, 
					barCount * baseOffset, 1,
					0, self.db.char.SSlen, 
					0.4, 0.4, 
					colours.r, colours.g, colours.b, colours.a,
					true)
	colours = self.db.char.colours.windfury
	ShockAndAwe:SetBarFrame(self.frames["Windfury"], 
					self.db.char.fWidth * self.db.char.WFProcPercent, barHeight, 
					barCount * baseOffset, 2,
					0, 3, 
					3, (self.db.char.fWidth * self.db.char.WFProcPercent - 6),
					colours.r, colours.g, colours.b, colours.a,
					false)
	if self.db.char.ssshow or self.db.char.wfshow then
		barCount = barCount + 1 
	end
	ShockAndAwe:SetBarFrame(self.frames["Shock"], 
					self.db.char.fWidth * self.db.char.ShockPercent, barHeight, 
					barCount * baseOffset, 1,
					0, self.db.char.ShockLen, 
					1, 0.8, 
					0, 1, .3, .9,
					true)
	if self.db.char.shockshow then
		barCount = barCount + 1
	end
	ShockAndAwe:SetBarFrame(self.frames["LavaLash"], 
					self.db.char.fWidth * self.db.char.LLPercent, barHeight, 
					barCount * baseOffset, 1,
					0, self.db.char.LLlen, 
					6, 1, 
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.llshow and self.db.char.lavaLashTalented then
		barCount = barCount + 1 -- we will use LavaLash frame 
	end
	colours = self.db.char.colours.firenova
	ShockAndAwe:SetBarFrame(self.frames["FireNova"], 
					self.db.char.fWidth * self.db.char.FNPercent, barHeight, 
					barCount * baseOffset, 1,
					0, self.db.char.FNlen, 
					0.4, 0.4, 
					colours.r, colours.g, colours.b, colours.a,
					true)
	if self.db.char.fnshow then
		barCount = barCount + 1
	end
	ShockAndAwe:SetBarFrame(self.frames["Shear"], 
					self.db.char.fWidth * self.db.char.ShearPercent, barHeight, 
					barCount * baseOffset, 1,
					0, self.db.char.ShearLen, 
					1, 0.8, 
					0, 1, .3, .9,
					true)
	if self.db.char.shearshow then
		barCount = barCount + 1
	end
	self:SetBarIcon(self.frames["Stormstrike"].icon, 17364)
	self:SetBarIcon(self.frames["FeralSpirit"].icon, 51533)
	self:SetBarIcon(self.frames["LavaLash"].icon, 60103)
	self:SetBarIcon(self.frames["Maelstrom"].icon, 51528)
	self:UpdateShieldBar()
end

function ShockAndAwe:SetBarFrame(frameName, barWidth, barHeight, frameOffset, frameLevel, minValue, maxValue, frameValue, frameSpark, frameR, frameG, frameB, frameAlpha, icon)
	frameName:SetFrameStrata("LOW")
	frameName:SetWidth(barWidth)
	frameName:SetHeight(barHeight)
	frameName:ClearAllPoints()
	frameName:SetPoint("TOPLEFT", self.BaseFrame, "TOPLEFT", barHeight, frameOffset)
	frameName:SetBackdrop(self.barBackdrop);
	frameName:SetBackdropColor(0, 0, 0, .2);
	frameName:SetBackdropBorderColor( 1, 1, 1, 1);
	frameName:EnableMouse(false)
	if not frameName.statusbar then
		frameName.statusbar = CreateFrame("StatusBar", nil, frameName)
	end
	frameName.statusbar:SetFrameLevel(frameLevel)
	frameName.statusbar:ClearAllPoints()
	frameName.statusbar:SetHeight(barHeight - 6)
	frameName.statusbar:SetWidth(barWidth - 6)
	frameName.statusbar:SetPoint("TOPLEFT", frameName, "TOPLEFT", 3, -3)
	frameName.statusbar:SetStatusBarTexture(media:Fetch("statusbar", self.db.char.texture))
	frameName.statusbar:SetStatusBarColor(frameR, frameG, frameB, frameAlpha)
	frameName.statusbar:SetMinMaxValues(minValue,maxValue)
	frameName.statusbar:SetValue(frameValue)
	
	if not frameName.spark then
		frameName.spark = frameName.statusbar:CreateTexture(nil, "OVERLAY")
	end
	frameName.spark:SetTexture("Interface\\CastingBar\\UI-CastingBar-Spark")
	frameName.spark:SetWidth(16)
	frameName.spark:SetHeight(barHeight + 16)
	frameName.spark:SetBlendMode("ADD")
	frameName.spark:SetPoint("CENTER",frameName.statusbar,"BOTTOMLEFT",(barWidth - 6)* frameSpark, -1)
	frameName.spark:Show()
	
	if not frameName.text then
		frameName.text = frameName:CreateFontString(nil,"OVERLAY")
	end
	local barfont = media:Fetch("font", self.db.char.barfont)
	frameName.text:SetFont(barfont, self.db.char.barfontsize, self.db.char.barfonteffect)
	frameName.text:ClearAllPoints()
	frameName.text:SetTextColor(1, 1, 1, 1)
	frameName.text:SetPoint("CENTER", frameName, "CENTER");
	frameName.text:SetText("")

	frameName:SetScript("OnUpdate", 
		function()
			ShockAndAwe:OnBarUpdate();
		end );
	if icon then
		frameName.icon:SetWidth(barHeight - 3) -- same as height to get square box
		frameName.icon:SetHeight(barHeight - 3)
		frameName.icon:SetPoint("TOPRIGHT", frameName, "TOPLEFT", 0 , -2)
		frameName.icon:Hide()
	end	
	frameName:Hide()
end

function ShockAndAwe:SetBarIcon(iconFrame, spellID)
	local _, _, icon = GetSpellInfo(spellID)
	iconFrame:SetBackdrop({
		bgFile = icon,
		--edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = false, tileSize = 0, edgeSize = 12,
		insets = { left = 0, right = 0, top = 0, bottom = 0 } })
end

function ShockAndAwe:ResetBars()
	self.BaseFrame:ClearAllPoints()
	self.db.char.point = self.defaults.char.point
	self.db.char.relativeTo = self.defaults.char.relativeTo 
	self.db.char.relativePoint = self.defaults.char.relativePoint
	self.db.char.xOffset = self.defaults.char.xOffset
	self.db.char.yOffset = self.defaults.char.yOffset
	self.db.char.fWidth = self.defaults.char.fWidth
	self.db.char.fHeight = self.defaults.char.fHeight
	self.db.char.scale = self.defaults.char.scale
	self.db.char.barfont = self.defaults.char.barfont
	self.db.char.barfontsize = self.defaults.char.barfontsize
	self.db.char.bartexture = self.defaults.char.bartexture
	self.db.char.texture = self.defaults.char.texture
	self.BaseFrame:SetPoint(self.db.char.point, self.db.char.relativeTo, self.db.char.relativePoint, self.db.char.xOffset, self.db.char.yOffset)
	ShockAndAwe:SetTalentEffects()
	self:RedrawFrames()
	self.db.char.movingframes = true -- so that call to ShowHideBars resets to false
	self:ShowHideBars()
	self:Print(L["config_reset"])
end

function ShockAndAwe:DebugTalents()
	local numTabs = GetNumTalentTabs();
	for t=1, numTabs do
		DEFAULT_CHAT_FRAME:AddMessage(GetTalentTabInfo(t)..":");
		local numTalents = GetNumTalents(t);
		for i=1, numTalents do
			nameTalent, icon, tier, column, currRank, maxRank= GetTalentInfo(t,i);
			DEFAULT_CHAT_FRAME:AddMessage("- "..i..":"..nameTalent..": "..currRank.."/"..maxRank);
		end
	end
end

function ShockAndAwe:DebugFrameValues()
	self:Print("SSlen : "..self.db.char.SSlen)
	self:Print("SSPercent : "..self.db.char.SSPercent )
	self:Print("ShockLen : "..self.db.char.ShockLen)
	self:Print("ShockPercent : "..self.db.char.ShockPercent )
	self:Print("WFProcPercent : "..self.db.char.WFProcPercent)
end

function ShockAndAwe:WFProcBar()
	local colours = self.db.char.colours.windfury
	self.frames["Windfury"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["Windfury"]:Show()
	updateActiveWFProc = true
	WFProcTime = GetTime() + 3
	WFPMin, WFPMax = self.frames["Windfury"].statusbar:GetMinMaxValues()
end

function ShockAndAwe:ShieldBar(shieldR, shieldB, shieldG, shieldalpha)
	self.frames["Shield"].statusbar:SetStatusBarColor(shieldR, shieldB, shieldG, shieldalpha)
	self.frames["Shield"]:SetBackdropBorderColor( 1, 1, 1, shieldalpha);
	self.frames["Shield"].spark:Show()
	updateActiveShield = true
	ShieldMin, ShieldMax = self.frames["Shield"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["Shield"].icon:Show()
	else
		self.frames["Shield"].icon:Hide()
	end
end

function ShockAndAwe:MaelstromBar()
	if self.db.char.msshow and not self.db.char.disabled then
		local colours = self.db.char.colours.maelstrom
		self.frames["Maelstrom"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, self.db.char.colours.msalpha)
		self.frames["Maelstrom"]:SetBackdropBorderColor( 1, 1, 1, self.db.char.colours.msalpha);
		self.frames["Maelstrom"].spark:Show()
		self.frames["Maelstrom"]:Show()
		if self.db.char.showicons then
			self.frames["Maelstrom"].icon:Show()
		else
			self.frames["Maelstrom"].icon:Hide()
		end
	end
	updateActiveMaelstrom = true
	MaelstromMin, MaelstromMax = self.frames["Maelstrom"].statusbar:GetMinMaxValues()
end

function ShockAndAwe:StormstrikeBar()
	local colours = self.db.char.colours.stormstrike
	self.frames["Stormstrike"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["Stormstrike"]:Show()
	updateActiveSS = true
	SSTime = GetTime() + self.db.char.SSlen
	SSmin, SSmax = self.frames["Stormstrike"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["Stormstrike"].icon:Show()
	else
		self.frames["Stormstrike"].icon:Hide()
	end
end

function ShockAndAwe:FireNovaBar()
	local colours = self.db.char.colours.firenova
	self.frames["FireNova"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["FireNova"]:Show()
	updateActiveFN = true
	FNTime = GetTime() + self.db.char.FNlen
	FNmin, FNmax = self.frames["FireNova"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["FireNova"].icon:Show()
	else
		self.frames["FireNova"].icon:Hide()
	end
end

function ShockAndAwe:FireTotemBar(totemName)
	local _, _, startTime, maxDuration = GetTotemInfo(1)
	if (totemName == C["Magma Totem"]) then 
		self:SetBarIcon(self.frames["fireTotem"].icon, 58734)
	elseif (totemName == C["Searing Totem"]) then
		self:SetBarIcon(self.frames["fireTotem"].icon, 58704)
	elseif (totemName == C["Fire Elemental Totem"]) then
		self:SetBarIcon(self.frames["fireTotem"].icon, 32982)
	elseif (totemName == C["Flametongue Totem"]) then
		self:SetBarIcon(self.frames["fireTotem"].icon, 8227)
	elseif (totemName == C["Frost Resistance Totem"]) then
		self:SetBarIcon(self.frames["fireTotem"].icon, 8181)
	else
		totemName= "nothing"
	end
	FireTotemTime = startTime + maxDuration
	self.db.char.priority.magmatime = FireTotemTime
	if self.db.char.firetotemshow then
		updateActiveFireTotem = true
		local colours = self.db.char.colours.magma
		self.frames["fireTotem"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
		self.frames["fireTotem"].statusbar:SetMinMaxValues(0, maxDuration)
		self.frames["fireTotem"]:Show()
		FireTotemMin, FireTotemMax = self.frames["fireTotem"].statusbar:GetMinMaxValues()
		if self.db.char.showicons then
			self.frames["fireTotem"].icon:Show()
		else
			self.frames["fireTotem"].icon:Hide()
		end
	end
end

function ShockAndAwe:LavaLashBar()
	local colours = self.db.char.colours.lavalash
	self.frames["LavaLash"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["LavaLash"]:Show()
	updateActiveLavaLash = true
	LLTime = GetTime() + self.db.char.LLlen
	LLMin, LLMax = self.frames["LavaLash"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["LavaLash"].icon:Show()
	else
		self.frames["LavaLash"].icon:Hide()
	end
end

function ShockAndAwe:FeralSpiritBar()
	local colours = self.db.char.colours.feralspirit
	self.frames["FeralSpirit"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["FeralSpirit"]:Show()
	updateActiveFeralSpirit = true
	FSTime = GetTime() + 45
	FSMin, FSMax = self.frames["FeralSpirit"].statusbar:GetMinMaxValues()	
	self:FeralSpiritCDBar()
end

function ShockAndAwe:FeralSpiritCDBar()
	local colours = self.db.char.colours.feralspiritCD
	self.frames["FeralSpiritCD"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["FeralSpiritCD"]:Show()
	FSCDMin, FSCDMax = self.frames["FeralSpiritCD"].statusbar:GetMinMaxValues()
	updateActiveFeralSpiritCD = true  
	if self.db.char.showicons then
		self.frames["FeralSpirit"].icon:Show()
	else
		self.frames["FeralSpirit"].icon:Hide()
	end
end

function ShockAndAwe:ShockBar(colours)
	self.frames["Shock"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["Shock"]:Show()
	updateActiveShock = true
	if self.db.char.lastshock == C["Earth Shock"] then
		ShockTime = GetTime() + self.db.char.EarthShockLen
		self.frames["Shock"].statusbar:SetMinMaxValues(0, self.db.char.EarthShockLen)
		self.frames["Shock"]:SetWidth(self.db.char.fWidth * self.db.char.EarthShockPercent)
		self.frames["Shock"].statusbar:SetWidth(self.db.char.fWidth * self.db.char.EarthShockPercent - 6)
	else
		ShockTime = GetTime() + self.db.char.ShockLen
		self.frames["Shock"].statusbar:SetMinMaxValues(0, self.db.char.ShockLen)
		self.frames["Shock"]:SetWidth(self.db.char.fWidth * self.db.char.ShockPercent)
		self.frames["Shock"].statusbar:SetWidth(self.db.char.fWidth * self.db.char.ShockPercent - 6)
	end
	ShockMin, ShockMax = self.frames["Shock"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["Shock"].icon:Show()
	else
		self.frames["Shock"].icon:Hide()
	end
end

function ShockAndAwe:DebugDebuffInfo()
	local index = 1
	while UnitDebuff("target", index) do
		local name, _, _, count, _, _, debuffExpires, unitCaster = UnitDebuff("target", index)
		local isMine = unitCaster == "player" 
		local expires = debuffExpires-GetTime()
		if isMine then
			self:DebugPrint("Debuff :"..name.." expires:"..expires)
		end
		index = index + 1
	end
end

function ShockAndAwe:FlameShockDotBar(shockCast)
	if shockCast then
		local fsDotPresent, duration, _, expiryTime = self:GetDebuffInfo(C["Flame Shock"])
		FSDotTime = expiryTime
		self.db.char.priority.FSDotMax = duration
		self.frames["FS_DOT"].statusbar:SetMinMaxValues(0, self.db.char.priority.FSDotMax)
		self.frames["FS_DOT"]:Show()
		updateActiveFSDot = true
	else 
		self.frames["FS_DOT"]:Hide()
		updateActiveFSDot = false	
	end
end

function ShockAndAwe:ShearBar()
	local colours = self.db.char.colours.windshear
	self.frames["Shear"].statusbar:SetStatusBarColor(colours.r, colours.g, colours.b, colours.a)
	self.frames["Shear"]:Show()
	updateActiveShear = true
	ShearTime = GetTime() + self.db.char.ShearLen
	ShearMin, ShearMax = self.frames["Shear"].statusbar:GetMinMaxValues()
	if self.db.char.showicons then
		self.frames["Shear"].icon:Show()
	else
		self.frames["Shear"].icon:Hide()
	end
end

function ShockAndAwe:GCDBar()
	local startTime, duration, enabled = GetSpellCooldown(C["Lightning Shield"]) -- Lightning Shield chosen because it has no other cooldown and all shammys will have it
	duration = duration or 0 -- force nil to 0 if for some bizzare reason no LS available.
	if duration > 0 then 
		self.frames["GCD"]:Show()
		updateActiveGCD = true
		GCDTime = startTime + duration
		self.GCDMax = duration
	end
end

function ShockAndAwe:DurationString(duration)
    local string = (("%1.1f"):format(duration % 60)) .. "s";
    
    if (duration >= 60) then
        duration = floor(duration - (duration % 60)) / 60; -- minutes
        
        string = (duration % 60) .."m " .. string;
        
        if (duration >= 60) then
            duration = (duration - (duration % 60)) / 60; -- hours
            string = duration .. "h " .. string;
        end
    end
    return string
end

function ShockAndAwe:CheckPurgeableBuff()
	local index = 1
	while UnitBuff("target", index) do
		local _, _, _, _, buffType, _, _, _, purgeable = UnitBuff("target", index)
		if purgeable or buffType == "Magic" then 
			return true
		end
		index = index + 1
	end
	return false
end

oldThreat = 0
oldThreatTime = GetTime()

function ShockAndAwe:OnBarUpdate()
	if self.db.char.disabled then
		return
	end
	if self.db.char.debug then
		local isTanking, state, scaledPercent, rawPercent, threatValue = UnitDetailedThreatSituation("player", "target")
		if not state then state = 0 end
		if not scalePercent then scaledPercent = 0 end
		if not rawPercent then rawPercent = 0 end
		if not threatValue then threatValue = 0 end
		if threatValue ~= oldThreat then
			--self:Print(("%1.2f"):format(GetTime() - oldThreatTime).."s - state :"..state.." scaled :"..("%1.2f"):format(100*scaledPercent).."% raw : "..rawPercent.."% - value :"..threatValue)
			oldThreat = threatValue
		end
	end
	
	local width = self.db.char.fWidth - 6
	local timeLeft = 0
	if updateActiveMaelstrom then
		local maelstromTime
		self.db.char.msstacks, maelstromTime = self:GetMaelstromInfo()
		timeLeft = maelstromTime - GetTime()
		if self.db.char.msstacks ~= 4 then
			mw4played = false
		end
		if self.db.char.msstacks == 5 then
			if self.db.char.mw5soundplay and InCombatLockdown() then
				if self.db.char.mw5sound and lastSound < GetTime() - self.db.char.mw5repeat then
					PlaySoundFile(self.db.char.mw5sound)
					lastSound = GetTime()
				end
			end
		else
			if self.db.char.msstacks == 4 and self.db.char.mw4soundplay and not mw4played and InCombatLockdown() then
				PlaySoundFile(self.db.char.mw4sound)
				mw4played = true
			end
		end		
		if self.db.char.msshow then
			if self.db.char.msstacks == 5 then
				self:SetMaelstromAlpha(self.db.char.colours.msalphaFull)
				if self.db.char.mw5flash then
					UIFrameFlash(self.frames["Maelstrom"], 0.25, 0.25, 30, true, 0.25, 0.25)
					mwflashing = true
				end
			else
				if mwflashing then
					mwflashing = false
				end
				UIFrameFlashRemoveFrame(self.frames["Maelstrom"])
				self:SetMaelstromAlpha(self.db.char.colours.msalpha)
			end
			self.frames["Maelstrom"].statusbar:SetValue(timeLeft)
			self.frames["Maelstrom"].spark:SetPoint("CENTER",self.frames["Maelstrom"].statusbar,"LEFT", timeLeft/30 * width,-1)
			if maelstromTime < GetTime() then
				self.frames["Maelstrom"]:Hide()
				self.frames["Maelstrom"].icon:Hide()
			else
				self.frames["Maelstrom"]:Show()
				if self.db.char.showicons then
					self.frames["Maelstrom"].icon:Show()
				end
			end
		else
			self.frames["Maelstrom"]:Hide()
			self.frames["Maelstrom"].icon:Hide()
		end
		if maelstromTime < GetTime() then
			if mwflashing then
				UIFrameFlashRemoveFrame(self.frames["Maelstrom"])
				self:SetMaelstromAlpha(self.db.char.colours.msalpha)
				mwflashing = false
			end
			updateActiveMaelstrom = false
		end
	end
	if updateActiveSS then
		timeLeft = SSTime - GetTime()
		self.frames["Stormstrike"].statusbar:SetValue(timeLeft)
		self.frames["Stormstrike"].spark:SetPoint("CENTER",self.frames["Stormstrike"].statusbar,"LEFT", timeLeft/SSmax * width * self.db.char.SSPercent,-1)
		if self.db.char.barstext then
			local _, _, debuffs = self:GetDebuffInfo(C["Stormstrike"])
			self.frames["Stormstrike"].text:SetText(string.format(L["%s debuffs remaining"], debuffs))
		else
			self.frames["Stormstrike"].text:SetText("")
		end
		if SSTime < GetTime() then
			self.frames["Stormstrike"]:Hide()
			self.frames["Stormstrike"].icon:Hide()
			updateActiveSS = false
		end
	end
	if updateActiveFN then
		timeLeft = FNTime - GetTime()
		self.frames["FireNova"].statusbar:SetValue(timeLeft)
		self.frames["FireNova"].spark:SetPoint("CENTER",self.frames["FireNova"].statusbar,"LEFT", timeLeft/FNmax * width * self.db.char.FNPercent,-1)
		if FNTime < GetTime() then
			self.frames["FireNova"]:Hide()
			self.frames["FireNova"].icon:Hide()
			updateActiveFN = false
		end
	end
	if updateActiveGCD then
		timeLeft = GCDTime - GetTime()
		self.frames["GCD"].statusbar:SetValue(timeLeft)
		local sparkpoint = timeLeft / 1.5 * self.GCDWidth
		if sparkpoint > self.GCDWidth then
			sparkpoint = self.GCDWidth
		end
		self.frames["GCD"].spark:SetPoint("CENTER",self.frames["GCD"].statusbar,"LEFT", sparkpoint,-1)
		if GCDTime < GetTime() then
			self.frames["GCD"]:Hide()
			updateActiveGCD = false
		end
	end
	if updateActiveFireTotem then
		timeLeft = FireTotemTime - GetTime()
		self.frames["fireTotem"].statusbar:SetValue(timeLeft)
		self.frames["fireTotem"].spark:SetPoint("CENTER",self.frames["fireTotem"].statusbar,"LEFT", timeLeft/FireTotemMax * width ,-1)
		local _, _, start, _ = GetTotemInfo(1)
		if self.db.char.barstext then
			self.frames["fireTotem"].text:SetText(format("%.1f",timeLeft).." sec")
		else
			self.frames["fireTotem"].text:SetText("")
		end
		if FireTotemTime < GetTime() or (FireTotemTime > 0 and (not start or start == 0)) then
			self.frames["fireTotem"]:Hide()
			self.frames["fireTotem"].icon:Hide()
			updateActiveFireTotem = false
			FireTotemTime = 0
		end
	end
	if updateActiveLavaLash then
		timeLeft = LLTime - GetTime()
		self.frames["LavaLash"].statusbar:SetValue(timeLeft)
		self.frames["LavaLash"].spark:SetPoint("CENTER",self.frames["LavaLash"].statusbar,"LEFT", timeLeft/LLMax * width * self.db.char.LLPercent ,-1)
		if LLTime < GetTime() then
			self.frames["LavaLash"]:Hide()
			self.frames["LavaLash"].icon:Hide()
			updateActiveLavaLash = false
		end
	end
	if updateActiveShock then
		timeLeft = ShockTime - GetTime()
		self.frames["Shock"].statusbar:SetValue(timeLeft)
		self.frames["Shock"].statusbar:SetValue(timeLeft)
		if self.db.char.lastshock == C["Earth Shock"] then
			self.frames["Shock"].spark:SetPoint("CENTER",self.frames["Shock"].statusbar,"LEFT", timeLeft/ShockMax * width * self.db.char.EarthShockPercent ,-1)
		else
			self.frames["Shock"].spark:SetPoint("CENTER",self.frames["Shock"].statusbar,"LEFT", timeLeft/ShockMax * width * self.db.char.ShockPercent ,-1)
		end
		if ShockTime < GetTime() then
			self.frames["Shock"]:Hide()
			self.frames["Shock"].icon:Hide()
			updateActiveShock = false
		end
	end
	if updateActiveFSDot then
		timeLeft = FSDotTime - GetTime()
		local maxTime = 18
		if self.db.char.priority.FSDotMax < maxTime and self.db.char.priority.FSDotMax > 0 then
			maxTime = self.db.char.priority.FSDotMax
		end
		self.frames["FS_DOT"].statusbar:SetValue(timeLeft)
		self.frames["FS_DOT"].spark:SetPoint("CENTER",self.frames["FS_DOT"].statusbar,"LEFT", timeLeft/maxTime * width ,-1)
		if self.db.char.barstext then
			self.frames["FS_DOT"].text:SetText(format("%.1f",timeLeft).." sec")
		else
			self.frames["FS_DOT"].text:SetText("")
		end
		if FSDotTime < GetTime() then
			self.frames["FS_DOT"]:Hide()
			self.frames["FS_DOT"].icon:Hide()
			updateActiveFSDot = false
		end
	end
	if updateActiveShear then
		timeLeft = ShearTime - GetTime()
		self.frames["Shear"].statusbar:SetValue(timeLeft)
		self.frames["Shear"].spark:SetPoint("CENTER",self.frames["Shear"].statusbar,"LEFT", timeLeft/ShearMax * width * self.db.char.ShearPercent ,-1)
		if ShearTime < GetTime() then
			self.frames["Shear"]:Hide()
			self.frames["Shear"].icon:Hide()
			updateActiveShear = false
		end
	end
	if updateActiveShield then
		timeLeft = ShieldTime - GetTime()
		self.frames["Shield"].statusbar:SetValue(timeLeft)
		self.frames["Shield"].spark:SetPoint("CENTER",self.frames["Shield"].statusbar,"LEFT", timeLeft/ShieldMax * width,-1)
		local orbs, shieldType = ShockAndAwe:GetShieldInfo()
		if orbs <= self.db.char.priority.shieldorbs then
			local colours = self.db.char.colours
			self.frames["Shield"].statusbar:SetStatusBarColor(colours.noshield.r, colours.noshield.g, colours.noshield.b, 1)
			self.frames["Shield"]:SetBackdropBorderColor(1, 1, 1, 1);
		end
		if ShieldTime < GetTime() then
			updateActiveShield = false
		end
	end
	if updateActiveFeralSpirit then
		timeLeft = FSTime - GetTime()
		self.frames["FeralSpirit"].statusbar:SetValue(timeLeft)
		self.frames["FeralSpirit"].spark:SetPoint("CENTER",self.frames["FeralSpirit"].statusbar,"LEFT", timeLeft/FSMax * 45/180 * width,-1)
		if FSTime < GetTime() then
			self.frames["FeralSpirit"]:Hide()
			if not InCombatLockdown() then
				self.frames["FeralSpirit"].icon:Hide() -- hide icon if feral spirits expire and out of combat.
			end
			updateActiveFeralSpirit = false
		end
	end
	if updateActiveFeralSpiritCD then
		local startTime, duration, enabled = GetSpellCooldown(GetSpellInfo(51533)) 
		duration = duration or 0 -- force nil to 0 
		if duration > 0 then
			timeLeft = startTime + duration - GetTime()
			self.frames["FeralSpiritCD"].statusbar:SetValue(timeLeft)
			self.frames["FeralSpiritCD"].spark:SetPoint("CENTER",self.frames["FeralSpiritCD"].statusbar,"LEFT", timeLeft/FSCDMax * width,-1)
		else
			-- set to full bar if expires
			self.frames["FeralSpiritCD"].statusbar:SetValue(180)
			self.frames["FeralSpiritCD"].spark:SetPoint("CENTER",self.frames["FeralSpiritCD"].statusbar,"LEFT", 180/FSCDMax * width,-1)
			updateActiveFeralSpiritCD = false
		end
	end
	if updateActiveWFProc then
		timeLeft = WFProcTime - GetTime()
		self.frames["Windfury"].statusbar:SetValue(timeLeft)
		self.frames["Windfury"].spark:SetPoint("CENTER",self.frames["Windfury"].statusbar,"LEFT", timeLeft/WFPMax * width * self.db.char.WFProcPercent ,-1)
		if WFProcTime < GetTime() then
			self.frames["Windfury"]:Hide()
			updateActiveWFProc = false
		end
	end
	if self.db.char.priority.show and not self.db.char.disabled then
		if self.db.char.priority.showinterrupt and self.PriorityFrame.interrupt then
			local EnemySpell, _, _, EnemySpellIcon = UnitCastingInfo("target")
			if not EnemySpell then
				EnemySpellIcon = "Interface/Tooltips/UI-Tooltip-Background"
			end
			if self:SpellAvailable(C["Wind Shear"]) then
				self:SetSubFrameBackdrop(self.PriorityFrame.interrupt.frame, EnemySpellIcon, 4)
				self.PriorityFrame.interrupt.frame:SetBackdropBorderColor(1, 1, 1, 1);
			else
				self:SetSubFrameBackdrop(self.PriorityFrame.interrupt.frame, EnemySpellIcon, 20)
				self.PriorityFrame.interrupt.frame:SetBackdropBorderColor(1, 0, 0, 1); -- set border colour to Red if Wind Shear not available
			end
			if not EnemySpell then
				self.PriorityFrame.interrupt.frame:SetBackdropColor(0, 0, 0, 0);
			end
		end
		if self.db.char.priority.showpurge and self.PriorityFrame.purge then
			local purgeable = self:CheckPurgeableBuff()
			if purgeable and not self.db.char.priority.purgeiconset then
				self.db.char.priority.purgeiconset = true
				self:SetSubFrameBackdrop(self.PriorityFrame.purge.frame, C["Purge Icon"], 4)
			elseif not purgeable and self.db.char.priority.purgeiconset then
				self.db.char.priority.purgeiconset = false
				self:SetSubFrameBackdrop(self.PriorityFrame.purge.frame, "Interface/Tooltips/UI-Tooltip-Background", 4)
				self.PriorityFrame.purge.frame:SetBackdropColor(0, 0, 0, 0);
			end
		end
	end
end

function ShockAndAwe:CreateMsgFrame()
	self.msgFrame:ClearAllPoints()
	self.msgFrame:SetWidth(400)
	self.msgFrame:SetHeight(75)
	self.msgFrame:SetFrameStrata("BACKGROUND")
	self.msgFrame:SetBackdrop({
		bgFile = "Interface/Tooltips/UI-Tooltip-Background",
		--edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
		tile = false, tileSize = 0, edgeSize = 12,
		insets = { left = 2, right = 2, top = 2, bottom = 2 }
	})
	self.msgFrame:SetBackdropColor(1, 1, 1, 0)
	self.msgFrame:SetMovable(true)
	self.msgFrame:RegisterForDrag("LeftButton")
	self.msgFrame:SetScript("OnDragStart", 
		function()
			self.msgFrame:StartMoving();
		end );
	self.msgFrame:SetScript("OnDragStop",
		function()
			self.msgFrame:StopMovingOrSizing();
			self.msgFrame:SetScript("OnUpdate", nil);
			self:FinishedMoving(self.db.char.warning, self.msgFrame);
		end );
	self.msgFrame:SetPoint(self.db.char.warning.point, self.db.char.warning.relativeTo, self.db.char.warning.relativePoint, self.db.char.warning.xOffset, self.db.char.warning.yOffset)
	self.msgFrame:SetInsertMode("TOP")
	self.msgFrame:SetFrameStrata("HIGH")
	self.msgFrame:SetToplevel(true)
	local font = media:Fetch("font", self.db.char.msgfont)
	self.msgFrame:SetFont(font, self.db.char.msgfontsize, self.db.char.msgfonteffect)
		
	self.msgFrame:Show()
end

function ShockAndAwe:PrintMsg(msg, col, time)
	if self.db.char.warning.show and not self.db.char.disabled then
		if col == nil then
			col = { r=1, b=1, g=1, a=1 }
		end
		if time == nil then 
			time = 3
		end
		if time ~= 5 then
			self.msgFrame:SetTimeVisible(time)
		end
		self.msgFrame:AddMessage(msg, col.r, col.g, col.b, 1, col.time)
	end
end

function ShockAndAwe:DebugPrint(msg)
	if self.db.char.debug then
		self:Print(msg)
	end
end