--[[
BossTactics by Sorontur
Version 2.14
Homepage www.bosstactics.net
License: LGPL v2.1
]]


BossTactics = LibStub("AceAddon-3.0"):NewAddon("BossTactics","AceConsole-3.0", "AceEvent-3.0","AceComm-3.0");
local L = LibStub("AceLocale-3.0"):GetLocale("BossTactics")
local BabbleClass = LibStub("LibBabble-Class-3.0"):GetLookupTable();

-- Binding Variables
BINDING_HEADER_BTHEADER = "BossTactics";
BINDING_NAME_BOSSTACTICS_D = L["druid channel"];
BINDING_NAME_BOSSTACTICS_DK = L["deathknight channel"];
BINDING_NAME_BOSSTACTICS_H = L["hunter channel"];
BINDING_NAME_BOSSTACTICS_M = L["mage channel"];
BINDING_NAME_BOSSTACTICS_P = L["paladin channel"];
BINDING_NAME_BOSSTACTICS_PR = L["priest channel"];
BINDING_NAME_BOSSTACTICS_R = L["rogue channel"];
BINDING_NAME_BOSSTACTICS_S = L["shaman channel"];
BINDING_NAME_BOSSTACTICS_W = L["warlock channel"];
BINDING_NAME_BOSSTACTICS_WA = L["warrior channel"];
BINDING_NAME_BOSSTACTICS_T = L["tank channel"];
BINDING_NAME_BOSSTACTICS_DD = L["range dd channel"];
BINDING_NAME_BOSSTACTICS_ME = L["melee channel"];
BINDING_NAME_BOSSTACTICS_HE = L["healer channel"];


-- menu functions
local options = {
    name = "BossTactics",
    handler = BossTactics,
    type = "group",
    args = {
        --[[options = {
            type = "execute",
            name = "options Tab",
            desc = L["menu options tab"],
            func = "showOptions",
        },]]--
        [L["dk"]] = {
    		type = "input",
            name = "short deathknight channel",
            guiHidden = true,
            desc = L["shortcut for deathknight channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Deathknight"]] = {
    		type = "input",
            name = "deathknight channel",
            desc = L["deathknight channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
        [L["d"]] = {
    		type = "input",
            name = "short druid channel",
            guiHidden = true,
            desc = L["shortcut for druid channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Druid"]] = {
    		type = "input",
            name = "druid channel",
            desc = L["druid channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["h"]] = {
    		type = "input",
            name = "short hunter channel",
            guiHidden = true,
            desc = L["shortcut for hunter channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Hunter"]] = {
    		type = "input",
            name = "hunter channel",
            desc = L["hunter channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["m"]] = {
    		type = "input",
            name = "short mage channel",
            guiHidden = true,
            desc = L["shortcut for mage channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Mage"]] = {
    		type = "input",
            name = "mage channel",
            desc = L["mage channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["p"]] = {
    		type = "input",
            name = "short paladin channel",
            guiHidden = true,
            desc = L["shortcut for paladin channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Paladin"]] = {
    		type = "input",
            name = "paladin channel",
            desc = L["paladin channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["pr"]] = {
    		type = "input",
            name = "short priest channel",
            guiHidden = true,
            desc = L["shortcut for priest channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Priest"]] = {
    		type = "input",
            name = "priest channel",
            desc = L["priest channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["r"]] = {
    		type = "input",
            name = "short rogue channel",
            guiHidden = true,
            desc = L["shortcut for rogue channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Rogue"]] = {
    		type = "input",
            name = "rogue channel",
            desc = L["rogue channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["s"]] = {
    		type = "input",
            name = "short shaman channel",
            guiHidden = true,
            desc = L["shortcut for shaman channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Shaman"]] = {
    		type = "input",
            name = "shaman channel",
            desc = L["shaman channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["w"]] = {
    		type = "input",
            name = "short warlock channel",
            guiHidden = true,
            desc = L["shortcut for warlock channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Warlock"]] = {
    		type = "input",
            name = "warlock channel",
            desc = L["warlock channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["wa"]] = {
    		type = "input",
            name = "short warrior channel",
            guiHidden = true,
            desc = L["shortcut for warrior channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[BabbleClass["Warrior"]] = {
    		type = "input",
            name = "warrior channel",
            desc = L["warrior channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["he"]] = {
    		type = "input",
            name = "short healer channel",
            guiHidden = true,
            desc = L["shortcut for healer channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["healer"]] = {
    		type = "input",
            name = "healer channel",
            desc = L["healer channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["dd"]] = {
    		type = "input",
            name = "short range DD channel",
            guiHidden = true,
            desc = L["shortcut for range DD channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["ranged DPS"]] = {
    		type = "input",
            name = "range dd channel",
            desc = L["range dd channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["me"]] = {
    		type = "input",
            name = "short melee channel",
            guiHidden = true,
            desc = L["shortcut for melee channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["melee"]] = {
    		type = "input",
            name = "melee channel",
            desc = L["melee channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["t"]] = {
    		type = "input",
            name = "short tank channel",
            guiHidden = true,
            desc = L["shortcut for tank channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
    	[L["tank"]] = {
    		type = "input",
            name = "tank channel",
            desc = L["tank channel"],
            set = "SendMessageToChannel",
            get = function () end,
    	},
        show = {
            type = "execute",
            name = "main frame",
            desc = L["menu main frame"],
            func = "openBossFrame",
        },
        chaninfo = {
            type = "execute",
            name = "channel info",
            desc = L["menu chaninfo"],
            func = "ChannelInfo",
        },
        chatconfig = {
            type = "execute",
            name = "chat config",
            desc = L["menu chatconfig"],
            func = "ChatConfig",
        },
        chatinfo = {
            type = "input",
            name = "chat info",
            desc = L["menu chatinfo"],
            set = "ChatInfo",
            get = function () end,
        },
        fontsize = {
            type = "input",
            name = "fontsize",
            desc = L["menu fontsize"],
            set = "ChangeFontSize",
            get = function () return BossTactics.db.profile.tacticFontSize end,
        },
        cMax = {
            type = "execute",
            name = "camdistmax",
            desc = L["menu cameramax"],
            func = "CameraDistanceMax",
        },
        join = {
            type = "input",
            name = "join channel",
            desc = L["menu join"],
            set = "JoinChannel",
            get = function () end,
        },
    	range = {
            type = "execute",
            name = "rangecheck",
            desc = L["menu rangecheck"],
            func = function()
            	if BossTactics.rangeCheck:IsShown() then
		            BossTactics.rangeCheck:Hide()
                else
                    BossTactics.rangeCheck:Show(10)
                end
            end,
        },
        quit = {
            type = "input",
            name = "quit channel",
            desc = L["menu quit"],
            set = "QuitChannel",
            get = function () end,
        },
        itemId = {
            type = "input",
            name = "itemId",
            desc = L["menu itemId"],
            set = function(arg1, itemlink)
            		local regex = "|c(%x+)|Hitem:([^|]-)|h%[([^%]]-)%]|h|r";
					local code = "%2";
                    if (itemlink) then
                        local itemId = string.gsub(itemlink,regex,code);
                        itemId = strsplit(":",itemId)
                        if(tonumber(itemId))then
                        	BossTactics:Print("ItemId: "..itemId)
                        	BossTactics:ShowInputBoxFrame("ItemId",itemId)
                        else
                        	BossTactics:Print(L["usage ItemId"])
                        end
                    else
                    	BossTactics:Print(L["usage ItemId"])
                    end
             end,
            get = function () end,
        },
        [L["hide"]] = {
            type = "execute",
            name = "close main frame",
            desc = L["menu main frame hide"],
            func = "HandleCloseMainWindow",
        },
        info = {
            type = "execute",
            name = "Info",
            desc = L["menu info"],
            func = "ShowInfoFrame",
        },
        minimap = {
            type = "toggle",
            name = "minimap",
            desc = L["menu minimap"],
            get = "IsMinimap",
            set = "ToggleMinimap"
        },
        debug = {
            type = "toggle",
            name = "debug",
            desc = L["menu debug"],
            get = "IsDebug",
            set = "ToggleDebug"
        },
        sessionAbort = {
            type = "execute",
            name = "sessionAbort",
            desc = L["menu SessionAbort"],
            func = function()  if(BossTactics:IsRaidLeader()) then
                if(BossTactics:IsSessionLeader())then
                    BossTactics:EndSession()
                else
                    BossTactics:EndUserSession()
                    BossTactics:BT_SendDataMessage("{LSEND}")
                end
                else BossTactics:Print(L["SessAbortPermitted"])
              end end,
        },
    },
}

--db profile defaults
local defaults = {
    profile = {
        settingsVersion = 4,
        anzMsgRLChat = 50,
        minimapShow = true,
        minimapX = -28,
        minimapY = -78,
        saveRaidleaders = true,
        raidleaderList = {},
        queryList = {
        -- be sure to change the update process, if you add queries
        	[1] = {
        		["type"] = "Addons",
				["name"] = "Raid",
				["query"] = "(\"DBM-Core\" or  \"BigWigs\") and \"Omen3\"",
				["std"] = true,
        	},
        	[2] = {
        		["type"] = "Items",
				["name"] = "Flask",
				["query"] = "46376 > 0 or 46379 > 0 or 46378 > 0 or 46377 > 0",
				["std"] = true,
        	},
        	[3] = {
        		["type"] = "Items",
				["name"] = "Pot",
				["query"] = "33448 > 0 or 33447 > 0 or 40212 > 0 or 40211 > 0",
				["std"] = true,
        	},
        },
        cdruid="DF7C0E",
        cdeathknight = "C41F3B",
        chunter = "ABD473",
        cmage = "69CCF0",
        cpaladin = "F58CBA",
        cpriest = "FFFFFF",
        crogue = "FFF569",
        cshaman = "2459FF",
        cwarlock = "9482C9",
        cwarrior = "C79C6E",
        ctank = "883F3F",
        chealer = "0B8C2C",
        cdd = "009D8C",
        cmelee = "A9D425",
        rangeFrameX = 50,
        rangeFrameY = -50,
        rangeFramePoint = "CENTER",
        tacticFontSize = 12,
        useOraMT = true,
    },
    char = {
    	 joinedChannelList = {},
    },
}


------------------------------------------------------
-- Addon events
------------------------------------------------------

function BossTactics:OnInitialize()

    -- Called when the addon is loaded

     --set variables
    self.settingsVersion = 2
    self.version = "2.14"
    self.versionChecked = false
    self.modules = {}
    self.debug = false
    self.player = UnitName("player")
    self.currAddon = "WOTLK"
    self.buttonTypes = {
        ["rangedDPS"] = {["name"] = "f",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-blue",
            ["text"] = L["ranged DPS"],
            ["x"] = 10,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
            },
        ["melee"] = {["name"] = "n",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-yellow",
            ["text"] = L["melee"],
            ["x"] = 55,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
             },
        ["healer"] = {["name"] = "h",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-green",
            ["text"] = L["healer"],
            ["x"] = 100,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
            },
        ["tank"] = {["name"] = "t",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-white",
            ["text"] = L["tank"],
            ["x"] = 145,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32
             },
        ["boss"] = {["name"] = "b",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-red",
            ["text"] = L["boss"],
            ["x"] = 190,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
             },
        ["boss2"] = {["name"] = "x",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-violet",
            ["text"] = L["boss"],
            ["x"] = 235,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
             },
        ["boss3"] = {["name"] = "y",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-pink",
            ["text"] = L["boss"],
            ["x"] = 280,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
             },
        ["boss4"] = {["name"] = "z",
            ["button"] = "Interface\\AddOns\\BossTactics\\Textures\\player-orange",
            ["text"] = L["boss"],
            ["x"] = 325,
            ["y"] = -650,
            ["width"] = 32,
            ["height"] = 32,
             },
    }

    self.currInstanceId = "EMPTY"
    self.currImgId = -1
    self.currModuleId = -1
    self.currBossId = -1
    self.instanceTable = {}
    self.currDropdownTable = nil
    self.isSession = false
    self.currSessionBtnId = -1
    self.SESSIONID = 100
    self.currBtnId = -1
    self.dataChanged = false
    self.isSessionLeader = false
    self.isOUS = 0
    self.incompatible = false
    self.incompatibleModule = false
    self.dataChangedArray = {}
    self.isNotWatching = false
    self.isNotWatchingAsked = false
    self.currInstanceMemberMax = -1
    self.currInstanceMode = "NONE"
    self.TAXIROUTE_LINEFACTOR = 32/56; -- Multiplying factor for texture coordinates
    self.syncDraw = false
    self.countedSyncs = 0
    self.totalSyncs = 0
    self.syncFinished = false
    self.syncInProgressTimer = LibStub("LibSimpleTimer-1.0")
    self.myRaidleader = nil
    self.askedAssistant = false
    self.isAssistant = false
    self.tacticMode = false
    self.currMemberCount = 0
    self.stateRl = false
    self.stateNRl = false
    self.incompatibleModules = {}
    self.rangeCheck = {}
    self.commCallbacks = {}
    self.tanklist = {}

    --initialize database
    self.db = LibStub("AceDB-3.0"):New("BossTacticsDB", defaults, "Default")

    --add chat commands
    LibStub("AceConfig-3.0"):RegisterOptionsTable("BossTactics", options, {L["bt"],L["BossTactics"]})
    self.optionsFrame = LibStub("AceConfigDialog-3.0"):AddToBlizOptions("BossTactics", "BossTactics")
    self.optionsDropdown = LibStub("AceConfigDialog-3.0")

    --set up communication
    self:ConfigComm()

    self.channels = {
		[1] = {
			name = BabbleClass["Druid"],
			shortcuts = { L["d"], BabbleClass["Druid"] },
			id = 1,
			color = self.db.profile.cdruid,
		},
		[2] = {
			name = BabbleClass["Deathknight"],
			shortcuts = { L["dk"], BabbleClass["Deathknight"] },
			id = 2,
			color = self.db.profile.cdeathknight,
		},
		[3] = {
			name = BabbleClass["Hunter"],
			shortcuts = { L["h"], BabbleClass["Hunter"] },
			id = 3,
			color = self.db.profile.chunter,
		},
		[4] = {
			name = BabbleClass["Mage"],
			shortcuts = { L["m"], BabbleClass["Mage"] },
			id = 4,
			color = self.db.profile.cmage,
		},
		[5] = {
			name = BabbleClass["Paladin"],
			shortcuts = { L["p"],  BabbleClass["Paladin"] },
			id = 5,
			color = self.db.profile.cpaladin,
		},
		[6] = {
			name = BabbleClass["Priest"],
			shortcuts = { L["pr"], BabbleClass["Priest"] },
			id = 6,
			color = self.db.profile.cpriest,
		},
		[7] = {
			name = BabbleClass["Rogue"],
			shortcuts = { L["r"], BabbleClass["Rogue"] },
			id = 7,
			color = self.db.profile.crogue,
		},
		[8] = {
			name = BabbleClass["Shaman"],
			shortcuts = { L["s"], BabbleClass["Shaman"] },
			id = 8,
			color = self.db.profile.cshaman,
		},
		[9] = {
			name = BabbleClass["Warlock"],
			shortcuts = { L["w"], BabbleClass["Warlock"] },
			id = 9,
			color = self.db.profile.cwarlock,
		},
		[10] = {
			name = BabbleClass["Warrior"],
			shortcuts = { L["wa"], BabbleClass["Warrior"] },
			id = 10,
			color = self.db.profile.cwarrior,
		},
		[11] = {
			name = L["tank"],
			shortcuts = { L["t"], L["tank"] },
			id = 11,
			color = self.db.profile.ctank,
		},
		[12] = {
			name = L["healer"],
			shortcuts = { L["he"], L["healer"] },
			id = 12,
			color = self.db.profile.chealer,
		},
		[13] = {
			name = L["ranged DPS"],
			shortcuts = { L["dd"], L["ranged DPS"] },
			id = 13,
			color = self.db.profile.cdd,
		},
		[14] = {
			name = L["melee"],
			shortcuts = { L["me"], L["melee"] },
			id = 14,
			color = self.db.profile.cmelee,
		},
	}

	self.tankClasses = {"WARRIOR","DEATHKNIGHT","PALADIN","DRUID"}
	self.healClasses = {"DRUID","SHAMAN","PRIEST","PALADIN"}
	self.meleeClasses = {"DRUID","ROGUE","DEATHKNIGHT","PALADIN","WARRIOR","SHAMAN"}
	self.rangeClasses = {"DRUID","PRIEST","WARLOCK","MAGE","SHAMAN","HUNTER"}

    --register instances
    self:RegisterInstances()
    if(self:IsMinimap())then
        self:CreateMinimapButton()
    end

    --clear the raidleaders list if needed
    if(not self.db.profile.saveRaidleaders)then
    	self.db.profile.raidleaderList = {}
    end

	self:SetupRangeCheck()

    --self:Print(self.instanceTable[1].." "..self.instanceTable[2])
end

function BossTactics:OnEnable()
    -- Called when the addon is enabled
    --self:RegisterEvent("RAID_INSTANCE_WELCOME")
    --self:RegisterEvent("PARTY_MEMBERS_CHANGED")
    --self:RegisterEvent("PARTY_LEADER_CHANGED")
    self:RegisterEvent("RAID_ROSTER_UPDATE")
    self:RegisterEvent("CHAT_MSG_WHISPER")

    if(#self.db.char.joinedChannelList == 0)then
    	local loc,eng = UnitClass("player")
    	local chaninfo = self:GetChannelInfoFromShortcut(loc)
    	if(chaninfo ~= nil)then
    		tinsert(self.db.char.joinedChannelList,chaninfo.id)
    	end
    end
    if(oRA3)then
    	self:Print("ora3 found")
        local tankCallback = {}
        function tankCallback:OnTanksUpdated(event, tanks)
            wipe(BossTactics.tanklist)
            for i,v in ipairs(tanks)do
                BossTactics.tanklist[i] = v
            end
        end
        oRA3.RegisterCallback(tankCallback, "OnTanksUpdated")
	end
end

function BossTactics:OnDisable()
    -- Called when the addon is disabled
end


------------------------------------------
-- EVENT handler
------------------------------------------

function BossTactics:RAID_ROSTER_UPDATE()
    local anzMembers = GetNumRaidMembers()
    for i=1, anzMembers, 1 do
        local name, rank, subgroup, level, class,
                fileName,zone, online, isDead, role, isML = GetRaidRosterInfo(i)
        if(name and name == self.player and subgroup <= self.currInstanceMemberMax/5)then
            self.isNotWatching = false
            break;
        end
    end

    self:CheckAssistants()

    --initialize the raidleader
    if(not self.myRaidleader)then
        if(IsRaidLeader() and UnitInRaid(self.player))then
           self.myRaidleader = self.player
        else
            self:BT_SendDataMessage("{RL}")
            self.myRaidleader = "BossTactics"
        end
    end
    --handle if I gave someone else the raidleader
    if(self.myRaidleader == self.player and not IsRaidLeader() and UnitInRaid(self.player)) then
       self:BT_SendDataMessage("{RL}")
       self.askedAssistant = false
       self.myRaidleader = nil
    end

    --handle if someone promoted me raidleader
    if(not self.myRaidleader == self.player and IsRaidLeader() and UnitInRaid(self.player)) then
       self:BT_SendDataMessage("{RLME}")
       self.askedAssistant = true
       self.myRaidleader = self.player
    end

    if(self:IsRaidLeader())then
        if(self.stateRl == false)then
       		 self:BecomeRaidLeader()
       		 self.stateRl = true
       		 self.stateNRl = false
        end
        if(self.currMemberCount ~= anzMembers)then
        	self:CompareRaid()
        end
    else
        if(self.stateNRl == false)then
        	self:LooseRaidLeader()
        	self.stateNRl = true
        	self.stateRl = false
        end
    end

    if(not self.versionChecked) then
        self:VersionCheck()
    end
    if(self.RaidleadersFrame)then
        self:UpdateRaidleaderFrameData()
    end


	--handle if player left the raid
    if(not UnitInRaid(self.player))then
    	self:LooseRaidLeader()
        self.stateNRl = false
        self.stateRl = false
        self.askedAssistant = false
        self.myRaidleader = nil
    end

    --new the value of the count of members
    self.currMemberCount = anzMembers
end

function BossTactics:CHAT_MSG_WHISPER()


	if(self.MainWindow and self.MainWindow.TaskManagerFrame)then
		self.MainWindow.TaskManagerFrame:TaskManagerWhisper(arg2, arg1)
	end

end


------------------------------------------------------
--compares the raid with the version list
------------------------------------------------------
function BossTactics:CompareRaid()
    if(self.MainWindow)then
        local anzMembers = GetNumRaidMembers()
        local i =0
        local versionframe = self.MainWindow.RightPane.versionlistFrame
        local textarray = versionframe.TextArray
        for i=1, anzMembers, 1 do
            local name, rank, subgroup, level, class,
                fileName,zone, online, isDead, role, isML = GetRaidRosterInfo(i)
            local found = false
            for index,v in ipairs(textarray) do
                local front = strsplit(":",v:GetText())
                if(front == name) then
                    found = true
                    if(not online)then
                        v:SetText(name..": |cff989898"..L["offline"].."|r")
                    else
                        v:SetText(name..": |cff707400"..L["No addon found"].."|r")
                    end
                    break
                end
            end
            if(not found)then
                local lastElement = true
                local chatfontstring = versionframe:CreateFontString(nil, "OVERLAY","GameFontNormal")
                if(#textarray == 0)then
                    textarray[1] = chatfontstring
                else
                    for index,v in ipairs(textarray) do
                        local sub = strsub(v:GetText(),1,strfind(v:GetText(),":")-1)
                        if(sub >= name) then
                            tinsert(textarray,index,chatfontstring)
                            lastElement = false
                            break
                        end
                    end
                    if(lastElement)then
                        textarray[#textarray+1] = chatfontstring
                    end
                end
                if(not online)then
                    chatfontstring:SetText(name..": |cff989898"..L["offline"].."|r")
                else
                    chatfontstring:SetText(name..": |cff707400"..L["No addon found"].."|r")
                end
                chatfontstring:SetWidth(versionframe:GetWidth()-20)
                chatfontstring:SetJustifyH("LEFT");
                chatfontstring:SetJustifyV("BOTTOM");
                chatfontstring:SetTextColor(1,1,1)
                self:ScrollStringTop(versionframe,textarray,true)
            end

        end
        --if someone left the raid
        if(#textarray > anzMembers)then
            for index,v in ipairs(textarray) do
                local found = false
                for i=1, anzMembers, 1 do
                    local name, rank, subgroup, level, class,
                        fileName,zone, online, isDead, role, isML = GetRaidRosterInfo(i)
                    if(strfind(v:GetText(),name,1)) then
                        found = true
                        break
                    end
                end
                if(not found)then
                    v:Hide()
                    tremove(textarray,index)
                    self:ScrollStringTop(versionframe,textarray,true)
                end
            end
        end
    end
end;

------------------------------------------------------------------
--checks if somone must be promoted as assistant
------------------------------------------------------------------

function BossTactics:CheckAssistants()

   if(not IsRaidLeader() and UnitInRaid(self.player)) then return end

   local anzMembers = GetNumRaidMembers()

    for i=1, anzMembers, 1 do
        local name, rank, subgroup, level, class,
                fileName,zone, online, isDead, role, isML = GetRaidRosterInfo(i)
        for index, value in ipairs(self.db.profile.raidleaderList)do
            if(value == name and rank == 0)then
                PromoteToAssistant(name)
            end

        end
    end

end;

------------------------------------------------------------------
--checks if somone in the raid has a new version
------------------------------------------------------------------

function BossTactics:VersionCheck()

    if(UnitInRaid(self.player))then
        self:BT_SendDataMessage("{VER:"..self.version.."}")
        self.versionChecked = true
    end

end;

----------------------------------------------------------------------
--checks in the global array if the current image was changed before
----------------------------------------------------------------------

function BossTactics:CheckImgDataChanged()

    for i,v in ipairs(self.dataChangedArray) do
        if(v.instId == self.currInstanceId and
            v.imgId == self.currImgId and v.bossId == self.currBossId) then
            return true
        end
    end
    return false
end;

---------------------------------------------------------
-- returns the text from a button type
-- parameter: buttonType: string of one char
---------------------------------------------------------
function BossTactics:GetTextFromButtonType(buttonType)

    if(buttonType == nil or strlen(buttonType) ~= 1)then
     return ""
    end

    if(buttonType == self.buttonTypes.melee.name)then
        return self.buttonTypes.melee.text
    elseif(buttonType == self.buttonTypes.rangedDPS.name)then
        return self.buttonTypes.rangedDPS.text
    elseif(buttonType == self.buttonTypes.healer.name)then
        return self.buttonTypes.healer.text
    elseif(buttonType == self.buttonTypes.tank.name)then
        return self.buttonTypes.tank.text
    elseif(buttonType == self.buttonTypes.boss.name)then
        return self.buttonTypes.boss.text
    elseif(buttonType == self.buttonTypes.boss2.name)then
        return self.buttonTypes.boss2.text
    elseif(buttonType == self.buttonTypes.boss3.name)then
        return self.buttonTypes.boss3.text
    elseif(buttonType == self.buttonTypes.boss4.name)then
        return self.buttonTypes.boss4.text
    end
    return ""
end;

---------------------------------------------------------
-- returns the type-object from a button type

---------------------------------------------------------
function BossTactics:GetTypeFromButtonType(buttonType)

    if(buttonType == nil or strlen(buttonType) ~= 1)then
     return nil
    end

    if(buttonType == self.buttonTypes.melee.name)then
        return self.buttonTypes.melee
    elseif(buttonType == self.buttonTypes.rangedDPS.name)then
        return self.buttonTypes.rangedDPS
    elseif(buttonType == self.buttonTypes.healer.name)then
        return self.buttonTypes.healer
    elseif(buttonType == self.buttonTypes.tank.name)then
        return self.buttonTypes.tank
    elseif(buttonType == self.buttonTypes.boss.name)then
        return self.buttonTypes.boss
    elseif(buttonType == self.buttonTypes.boss2.name)then
        return self.buttonTypes.boss2
    elseif(buttonType == self.buttonTypes.boss3.name)then
        return self.buttonTypes.boss3
    elseif(buttonType == self.buttonTypes.boss4.name)then
        return self.buttonTypes.boss4
    end
    return nil
end;



-----------------------------------------------------------
--- shows options tab
-----------------------------------------------------------

function BossTactics:showOptions()

InterfaceOptionsFrame_OpenToFrame(self.optionsFrame)

end;

--------------------------------------------------------
-- checks the state, to select the right instance module
--------------------------------------------------------

function BossTactics:CheckInstanceState()

	local zone = GetRealZoneText();
	if(self.MainWindow.LeftPane.InstanzBtn:GetText() == zone)then
		return
	else
		for i,v in pairs(self.instanceTable)do
			for ind,va in pairs (v.values)do
				for ind2,val in ipairs(va)do
					if(val[1] == zone and self.currInstanceId ~= val[2])then
						self:AddonDropdownClick(i)
						self:InstanceDropdownClick(val[2])
					elseif(val[4])then
						for ind3,val3 in ipairs(val[4])do
							if(val3.name == zone and self.currInstanceId ~= val[2])then
								self:AddonDropdownClick(i)
                                self:InstanceDropdownClick(val[2])
							end
						end
					end
				end
			end
		end
	end

end;

---------------------------------------------------------------
--- open the main frame
---------------------------------------------------------------

function BossTactics:openBossFrame()
  if(self.MainWindow == nil) then
    self:CreateMainFrame()
    self:CreateLeftPanel()
    self:CreateRightPanel()
  end
  if(self:IsRaidLeader())then
        self:BecomeRaidLeader()
        self:CompareRaid()
  else
  	self:LooseRaidLeader()
  end
  if(not self.myRaidleader)then
        if(IsRaidLeader() and UnitInRaid(self.player))then
           self.myRaidleader = self.player
        else
            self:BT_SendDataMessage("{RL}")
        end
  end
  if(self.isNotWatching)then
      self:BT_SendDataMessage("{SYNCREQ}")
      self.isNotWatching = false;
  end
  self.MainWindow:Show()
  self.MainWindow:Raise()
  self:CheckUpdateDatabase()
  self:CheckInstanceState()
end;



----------------------------------------------------
--- config acecomm
----------------------------------------------------
function BossTactics:ConfigComm()
    BossTactics:RegisterComm("BOSSTACTICS", "OnCommReceive")
end;


--------------------------------------------------------
--method for modules, if they need chat communication
--callback should return true if the message was received
--------------------------------------------------------

function BossTactics:RegisterForCommunication(callback)
	if(type(callback) == "function")then
		tinsert(self.commCallbacks,callback)
	else
		error("you must register a funtion for callback")
	end
end

-----------------------------------------------------------------
--- method for the communication
--------------------------------------------------------------
function BossTactics:OnCommReceive(prefix, Msgs, distribution, target)

    if(self.debug)then
        if(self:IsRaidLeader())then
            self:Print(Msgs.." distr: "..distribution.." player: "..target)
        else
            if(not strfind(Msgs,"{LCH")) then
                self:Print(Msgs.." distr: "..distribution.." player: "..target)
            end
        end
    end

    local regex_leaderchat = "{LCH}(.*)"
    local regex_leaderChInstance = "{RLI:(.*)}"
    local regex_leaderChAddon = "{RLADDON:(.*)}"
    local regex_leaderChMode = "{RLMODE:(.*)}"
    local regex_leaderChBoss = "{RLB:([^:]-):([^}]-)}"
    local regex_leaderNextImg = "{RLNX:([^:]-):([^:]-):([^}]-)}"
    local regex_leaderPrevImg = "{RLPR:([^:]-):([^:]-):([^}]-)}"
    local regex_instinfo = "{INSTINFO:([^:]-):([^:]-):([^:]-):([^:]-):([^}]-)}"
    local regex_userVersion = "{UVER:([^:]-):([^}]-)}"
    local regex_versionCheck = "{VER:([^}]-)}"
    local regex_sessionStart = "{LSTART:([^}]-)}"
    local regex_leaderPing = "{LPING:([^:]-):([^}]-)}"
    local regex_drawing = "{DL:([^:]-):([^:]-):([^:]-):([^}]-)}"
    local regex_moduleVersion = "{MVER:([^:]-):([^}]-)}"
    local regex_textSyncStart = "{TEXTSYNC:([^:]-):([^}]-)}"
    local regex_textSyncPart = "{TXT:(.*)}"
    local regex_trashStatus = "{TRST:(.*)}"
    local regex_tacticSwitch = "{TASW:([^:]-):([^}]-)}"
    local regex_queryRequest = "{RLQR:([^:]-):([^}]-)}"
    local regex_queryReply = "{UQR:(.*)}"


	self:CheckChat(Msgs,distribution,target)
    if(Msgs == "{RLVERCH}")then
        if(self:IsRaidLeader())then
            self:CompareRaid()
        end
        if(self.incompatibleModule)then
        	self:BT_SendDataMessage("{UVER:"..self.version..":2}")
        else
        	self:BT_SendDataMessage("{UVER:"..self.version..":"..tostring(self.isOUS).."}")
        end
    end

    --this must be checked before the version check comes
    if(target ~= self.player)then
        --raidleader changed instance
        for instid in string.gmatch(Msgs,regex_leaderChInstance) do
            if(not self.isNotWatching) then
                self:HandleInstanceSwitch(instid)
                self:UserSessionImgSwitch()
            end
        end
    end

    --dont continue if you are incompatible
    if(self.incompatible or self.incompatibleModule)then
        return
    end

	--call the callback methods
	for i,v in ipairs(self.commCallbacks)do
		local res = v(Msgs, distribution, target)
		if(res)then return end
	end

    if(Msgs == "{INC}" and not self.incompatible)then
        self.incompatible = true
        self:ShowVersionInfoFrame()
        return
    elseif((Msgs == "{DRAWSYNCEND}" or Msgs == "{TEXTSYNCEND}") and target==self.player)then
        self.syncFinished = true
        self.txtSyncInProgress = false
        return
    elseif(Msgs == "{TEXTSYNCEND}")then
    	 if(not self.isNotWatching and self.MainWindow) then
            self.MainWindow.RightPane.ScrollRight:GetScrollChild():SetText(self.tmpSyncText)
            self.MainWindow.RightPane.ScrollRight:GetScrollChild():SetCursorPosition(1)
            if(self.tmpSyncTextId)then
            	if(self:CheckTextNew(false,self.tmpSyncTextId))then
            		self:SaveAsText(self.tmpSyncTextId)
            	else
					self:SaveText(self.tmpSyncTextVersion)
            	end
            end
            self.tmpSyncText = ""
    	 end
    	return
    elseif(Msgs == "{RL}")then
        if(IsRaidLeader() and UnitInRaid(self.player))then
           self:BT_SendDataMessage("{RLME}")
        end
        return
    elseif(Msgs == "{INCM}")then
    	self.incompatibleModule = true
    	local found = false
    	for i,v in ipairs(self.incompatibleModules)do
    		if(v == self.currInstanceId)then
    			found = true
    			break
    		end
    	end
    	if not found then
    		tinsert(self.incompatibleModules,self.currInstanceId)
    	end
    	self:Print(#self.incompatibleModules)
    	self:ShowInfoMessage(L["incompatible module"])
    	return
    end
    --versioncheck
    for sentversion in string.gmatch(Msgs,regex_versionCheck) do
        if(not self:CompareVersions(sentversion))then
            self:BT_SendDataMessage("{INC}",true,target)
        end
    end

    --versioncheck of modules
    for moduleId, sentversion in string.gmatch(Msgs,regex_moduleVersion) do
        if(not self:CompareModuleVersions(moduleId,sentversion))then
            self:BT_SendDataMessage("{INCM}",true,target)
        end
    end


    --Drawing
    for xstart, ystart, xend, yend in string.gmatch(Msgs,regex_drawing) do
        if(not self.isNotWatching and self.MainWindow) then
            if(target == self.player)then
                self.countedSyncs = self.countedSyncs + 1
            else
                local imgPane = self.MainWindow.LeftPane.ImgPane
                imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].deleted = false
                if(self:IsRaidLeader())then
                    imgPane.PaintDelBtn:Show()
                end
                self:DrawLine(imgPane,xstart,ystart,xend,yend,imgPane.linewidth,imgPane.optColor)
            end
        end
    end

    --request of a Query
    for query, type in string.gmatch(Msgs,regex_queryRequest) do

        if(self:IsRaidLeader()) then
			if(not self.QueryResultFrame or not self.QueryResultFrame:IsShown())then
			    self:ShowQueryResultFrame()
                self:ClearQueryResults(query)
            end
			self.QueryResultFrame.currQuery = query
			self.QueryResultFrame.currType = type
		end

        local parser = self:ParseQuery(query,type)
        local result = self:EvaluateQuery(parser,type)
        local resultArr = {strsplit("#",result)}
		local resultStr, resultPred = self:CreateEvaluationString(parser, type, resultArr)
        self:BT_SendDataMessage("{UQR:"..result.."}")
    end


    --a part of the text
    for txt in string.gmatch(Msgs,regex_textSyncPart) do
        if(not self.isNotWatching and self.MainWindow) then
            if(target == self.player)then
                self.countedSyncs = self.countedSyncs + 1
            else
            	self.tmpSyncText = self.tmpSyncText..txt
            end
        end
    end

	--some raidleader events do not requiere the main frame
	if(self:IsRaidLeader())then
		--reply to a query
		for reply in string.gmatch(Msgs,regex_queryReply) do
			local parser = self:ParseQuery(self.QueryResultFrame.currQuery,self.QueryResultFrame.currType)
            local resultArr = {strsplit("#",reply)}
            local resultStr, resultPred = self:CreateEvaluationString(parser, self.QueryResultFrame.currType, resultArr)
            self:InsertQueryResult(target,resultStr,resultPred)
		end
	end

    --some events are only importent if you are raidleader
    if(self:IsRaidLeader() and self.MainWindow)then
        --version check
        for uver, isOUS in string.gmatch(Msgs,regex_userVersion) do
            self:VersionStrings(target,uver,isOUS)
        end

        --leadermsg
        for leadermsg in string.gmatch(Msgs,regex_leaderchat) do
            --local chatedit = self.MainWindow.RightPane.LeaderChatFrame.chatEdit
            local leaderframe = self.MainWindow.RightPane.LeaderChatFrame
            local chatfontstring = leaderframe:CreateFontString(nil, "OVERLAY","GameFontNormal")
            local textarray = leaderframe.TextArray
            --chatfontstring:SetPoint("BOTTOMLEFT",self.MainWindow.RightPane.LeaderChatFrame)
            if(#textarray > self.db.profile.anzMsgRLChat)then
                textarray[1]:Hide()
                table.remove(textarray,1)
            end
            textarray[#textarray+1] = chatfontstring
            chatfontstring:SetText(target..": "..leadermsg)
            chatfontstring:SetWidth(leaderframe:GetWidth()-20)
            chatfontstring:SetJustifyH("LEFT");
            chatfontstring:SetJustifyV("BOTTOM");
            chatfontstring:SetTextColor(1,1,1)
            self:ScrollString(leaderframe,textarray,true)
        end

        --user getting out of sync
        if(Msgs == "{UICH}")then
            self:VersionStrings(target,self.version,1)
        elseif(Msgs == "{MAINCL}")then
            self:VersionStrings(target,self.version,1)
        end

        --some events are only for sessionleaders
        if(self.isSessionLeader)then
            --syncrequest
            if(Msgs == "{SYNCREQ}")then
                self:BT_SendDataMessage("{LSTART:"..self.currInstanceMemberMax.."}")
                self:SyncRaid(false,target)
                return
            elseif(Msgs == "{TXTSREQ}")then
        	    if(not self.txtSyncInProgress)then
                    self.txtSyncInProgress = true
                    self:SyncText()
                end
        		return
            end
        end
      end

    --some events must only be done if they are not from us
    if(target ~= self.player)then
        --call method for button handling
        self:CommBtnData(Msgs,target)
        --session started by a leader
        if(not self:IsSession())then
            for maxRaidNr in string.gmatch(Msgs,regex_sessionStart) do
                self.currInstanceMemberMax = tonumber(maxRaidNr)
                self:StartUserSession(target)
            end
        end
        if(Msgs == "{LSEND}")then
            if(not self.isNotWatching) then
                self:EndUserSession(target)
            end
        elseif(Msgs == "{DRAWDEL}")then
            self:ClearImage()
            if(self.MainWindow.LeftPane.ImgPane.PaintDelBtn)then
            	self.MainWindow.LeftPane.ImgPane.PaintDelBtn:Hide()
            end
            return
        elseif(Msgs == "{RLME}")then
            self.myRaidleader = target
            if(IsRaidOfficer())then
            	self:BT_SendDataMessage("{RLA}",true,self.myRaidleader)
            end
            return
        elseif(Msgs == "{RLA}")then
            if(IsRaidLeader() and UnitInRaid(self.player))then
                 for i,v in ipairs(self.db.profile.raidleaderList)do
                     if(target == v)then
                     self:BT_SendDataMessage("{AYES}",true,target)
                     break
                     end
                 end
            end
            return
        elseif(Msgs == "{AYES}")then
            self.isAssistant = true
            self:BecomeRaidLeader()
            self:CompareRaid()
            return
        elseif(Msgs == "{ANO}")then
            self.isAssistant = false
            self:LooseRaidLeader()
            return
        end

       --switch of a tactic text
        for name,version in string.gmatch(Msgs,regex_tacticSwitch) do
            if(not self.isNotWatching and self.MainWindow) then
               	local id = self:TextToId(name)
               	if(id ~= -1)then
               		self:HandleTacticSwitch(id, tonumber(version))
               	else
					self:BT_SendDataMessage("{TXTSREQ}")
               	end
            end
        end

        --Trash flag
        for flag in string.gmatch(Msgs,regex_trashStatus) do
            if(not self.isNotWatching and self.MainWindow) then
                if(tonumber(flag) == 1)then
                	self.MainWindow.RightPane.TrashBtn.stdTactic = true
                	self.MainWindow.RightPane.TrashBtn:SetText(L["Trash"])
                	self:HandleTacticSwitch(self.MainWindow.RightPane.TrashBtn.tacticId)
                else
                	self.MainWindow.RightPane.TrashBtn.stdTactic = false
                	self.MainWindow.RightPane.TrashBtn:SetText(L["Tactic"])
                	self:HandleTacticSwitch(self.MainWindow.RightPane.TrashBtn.trashId)
                end
                self.MainWindow.RightPane.SaveBtn:Disable()
            end
        end

        --Start of textsync
        for name,version in string.gmatch(Msgs,regex_textSyncStart) do
            if(not self.isNotWatching and self.MainWindow) then
                self.tmpSyncText = ""
                self.tmpSyncTextId = name
                self.tmpSyncTextVersion = tonumber(version)
            end
        end

        --Ping form raidleader
        for x, y in string.gmatch(Msgs,regex_leaderPing) do
            if(not self.isNotWatching and self.MainWindow) then
                local imgPane = self.MainWindow.LeftPane.ImgPane
                imgPane.Ping:ClearAllPoints()
                PlaySound("MapPing");
                imgPane.Ping:SetPoint("BOTTOMLEFT", imgPane, "BOTTOMLEFT",x,y)
                imgPane.Ping:Show()
                imgPane.Ping.timer = 2
                imgPane.Ping:SetAlpha(1)
                imgPane.PingTimer:ScheduleRepeatingTimer("PingTimer", function () BossTactics:FadePing() end, 0.2)
            end
        end

        --instinfo from syncronisation
        for addonid, instid, bossid, imgid, membermax in string.gmatch(Msgs,regex_instinfo) do
            if(not self.isNotWatching) then
                if(not (self.TacticQuestionFrame and self.TacticQuestionFrame:IsShown()))then
                    self.currInstanceMemberMax = membermax
                    self:openBossFrame()
                    if(not self:IsSession())then
                        self:StartUserSession(target)
                    end
                    self.isOUS = 0
                    self:HandleAddonSwitch(addonid)
                    self:HandleInstanceSwitch(instid)
                    self:SetInstanceMode("mode"..membermax)
                    self:ShowBossTactic(tonumber(bossid))
                    self:ShowBossImage(tonumber(imgid))
                    self:UserSessionImgSwitch()
                end
            end
        end

		 --raidleader changed Addon
        for addonid in string.gmatch(Msgs,regex_leaderChAddon) do
            if(not self.isNotWatching) then
                self:HandleAddonSwitch(addonid)
                self:UserSessionImgSwitch()
            end
        end
         --raidleader changed Mode
        for mode in string.gmatch(Msgs,regex_leaderChMode) do
            if(not self.isNotWatching) then
                self:SetInstanceMode(mode)
                self:UserSessionImgSwitch()
            end
        end

        --raidleader changed boss
        for instid, bossid in string.gmatch(Msgs,regex_leaderChBoss) do
            if(not self.isNotWatching) then
                if(instid ~= self.currInstanceId)then
                    if(self.isOUS == 0)then
                    self:Print(L["Out of synch with raidleader"])
                    self.isOUS = 1
                    self:BT_SendDataMessage("{UICH}")
                end
                else
                    self:ShowBossTactic(tonumber(bossid))
                    self:UserSessionImgSwitch()
                end
            end
        end
        --raidleader next image
        for instid, bossid, imgid in string.gmatch(Msgs,regex_leaderNextImg) do
            if(not self.isNotWatching) then
                if(instid ~= self.currInstanceId or tonumber(bossid) ~= self.currBossId)then
                    if(self.isOUS == 0)then
                    self:Print(L["Out of synch with raidleader"])
                    self.isOUS = 1
                    self:BT_SendDataMessage("{UICH}")
                end
                else
                    self:ShowBossImage(tonumber(imgid))
                    self:UserSessionImgSwitch()
                end
            end
        end
        --raidleader prev image
        for instid, bossid, imgid in string.gmatch(Msgs,regex_leaderPrevImg) do
            if(not self.isNotWatching) then
                if(instid ~= self.currInstanceId or tonumber(bossid) ~= self.currBossId)then
                    if(self.isOUS == 0)then
                    self:Print(L["Out of synch with raidleader"])
                    self.isOUS = 1
                    self:BT_SendDataMessage("{UICH}")
                end
                else
                    self:ShowBossImage(tonumber(imgid))
                    self:UserSessionImgSwitch()
                end
            end
        end
    end

end;

function BossTactics:CommBtnData(Msgs,target)

    if(not self.MainWindow) then return end

    if(self.isNotWatching) then return end

    local regex_leaderRemBtn = "{BTRM:([^}]-)}"
    local regex_leaderChText = "{BTCT:([^:]-):([^}]-)}"
    local regex_leaderNewBtn = "{BTN:([^:]-):([^:]-):([^:]-):([^}]-)}"
    local regex_movedbtn = "{BTMV:([^:]-):([^:]-):([^}]-)}"

    --button drag event
    for btnid, x, y in string.gmatch(Msgs,regex_movedbtn) do
        for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
             if(self:ButtonEqual(v) and v.id == tonumber(btnid)) then
                v:ClearAllPoints()
                v:SetPoint("TOPLEFT",self.MainWindow.LeftPane,"TOPLEFT",x,y)
                break
            end
        end
    end
    --button new event
    for btnid,x, y, typename in string.gmatch(Msgs,regex_leaderNewBtn) do
        self:CreateNewMapButton(self:GetTypeFromButtonType(typename),false,self:GetTextFromButtonType(typename),x,y,btnid)
        self.currSessionBtnId = tonumber(btnid)+1
    end
    --raidleader change button text
    for btnid, newtext in string.gmatch(Msgs,regex_leaderChText) do
       for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(self:ButtonEqual(v) and v.id == tonumber(btnid))then
                 v.text:SetText(newtext)
                break
            end
        end
    end
    --raidleader deletes button
    for btnid in string.gmatch(Msgs,regex_leaderRemBtn) do
        for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(self:ButtonEqual(v) and v.id == tonumber(btnid))then
                v:Hide()
                tremove(self.MainWindow.LeftPane.buttons,i)
                break
            end
        end
    end
end;

-----------------------------------------------------------
--handels updates to the VersionStrings
--target the player, uver version of the player
--isOus 1=true false otherwise
-----------------------------------------------------------

function BossTactics:VersionStrings(target,uver,isOUS)
    if(self.MainWindow)then
        local versionframe = self.MainWindow.RightPane.versionlistFrame
        local textarray = versionframe.TextArray
        local compatible = self:CompareVersions(uver)
        local inctext = ""
        if(not compatible)then
            self:BT_SendDataMessage("{INC}",true,target)
            inctext = " "..L["version incompatible"]
        end
        for i,v in ipairs(textarray) do
            if(strfind(v:GetText(),target,1)) then
                if(tonumber(isOUS) == 1)then
                    v:SetText(target..": |cffdf6003"..uver.."|r".." |cffff0000"..L["out of sync"]..inctext.."|r")
                elseif(tonumber(isOUS) == 2)then
                	v:SetText(target..": |cffdf6003"..uver.."|r".." |cffff0000"..L["module incompatible"].."|r")
                else
                    v:SetText(target..": |cffdf6003"..uver.."|r".." |cffff0000"..inctext.."|r")
                end
                break
            end
        end
    end
end;

---------------------------------------------------------------
--compares versions
--uver the version of a player to compare with mine
--returns true if the version is compatible, false otherwise
---------------------------------------------------------------

function BossTactics:CompareVersions(uver)

    minor, second = strsplit(".",uver)

    myminor, mysecond = strsplit(".",self.version)

    if(tonumber(minor) < tonumber(myminor))then
        return false
    elseif(tonumber(minor) == tonumber(myminor)) then
    	if(tonumber(second) < tonumber(mysecond))then
            return false
        end
    end
    return true

end;

function BossTactics:CompareModuleVersions(moduleId, uver)

	if(IsAddOnLoaded(moduleId)) then
		for i,v in ipairs(self.modules)do
			if(v.id == moduleId)then
				if(v.version > tonumber(uver))then return false end
				break
			end
        end
    end
    return true

end;


--------------------------------------------------------
--wrapper for easy use of sending messages
--------------------------------------------------------
function BossTactics:BT_SendDataMessage(msg, whisper, target)

    if(target and target == "BossTactics")then return end

    if(whisper)then
    	self:SendCommMessage("BOSSTACTICS",msg,"WHISPER",target)
    else
    	if not UnitInRaid(self.player) then return end
    	self:SendCommMessage("BOSSTACTICS",msg,"RAID")
    end
end;


--------------------------------------------------------------------
--- options functions
--------------------------------------------------------------------
function BossTactics:IsDebug(info)
    return self.debug
end

function BossTactics:ToggleDebug(info, value)
    self.debug = value
    if(self.debug)then
        self:Print("Debug enabled")
    else
        self:Print("Debug disabled")
    end
end

function BossTactics:IsMinimap(info)
    return self.db.profile.minimapShow
end

function BossTactics:ToggleMinimap(info, value)
    self.db.profile.minimapShow = value
    if(self.db.profile.minimapShow)then
        self:CreateMinimapButton()
        self:Print(L["minimap on"])
    else
        self.MinimapBtnFrame:Hide()
        self:Print(L["minimap off"])
    end
end

------------------------------------------------------------
---tests if player is raidleader
-- returns if a player is leader or assistant
------------------------------------------------------------

function BossTactics:IsRaidLeader()
    if(not self.askedAssistant and self.myRaidleader and not IsRaidLeader() and IsRaidOfficer())then
        self:BT_SendDataMessage("{RLA}",true,self.myRaidleader)
        self.askedAssistant = true
        return false
    end
    return  UnitInRaid(self.player) and (IsRaidLeader() or self.isAssistant)
end;

------------------------------------------------------------
---tests if we are in session mode
-- returns if a player is leader or assistant
------------------------------------------------------------

function BossTactics:IsSession()
    return self.isSession;
end;

function BossTactics:IsSessionLeader()
    return self.isSessionLeader
end;

------------------------------------------------------------
--start or end the leader session
------------------------------------------------------------

function BossTactics:StartSession()

    if(not self.MainWindow) then return end

    self.isSession = true;
    self.isSessionLeader = true
    if(self:IsRaidLeader())then
        self:BT_SendDataMessage("{LSTART:"..self.currInstanceMemberMax.."}")
    end
    self.currSessionBtnId = self.SESSIONID
    self.MainWindow.LeftPane.SyncBtn:SetWidth(150)
    self.MainWindow.LeftPane.SyncBtn:SetHeight(20)
    self.MainWindow.LeftPane.SyncBtn:SetText(L["LeaderSync"])
    self.syncDraw = true
    self:SyncRaid(true)
    self.MainWindow.LeftPane.StdBtn:Disable()
    self.MainWindow.LeftPane.PingPaintBtn:Enable()
    self.MainWindow.RightPane.TextSyncBtn:Enable()

    --self.MainWindow.LeftPane.SyncBtn:Enable()
    self.isOUS = 0
end;

function BossTactics:EndSession()

    if(not self.MainWindow) then return end

    self.isSession = false;
    self.isSessionLeader = false;
    self:ResetSessionIds()
    if(self:IsRaidLeader())then
        self:BT_SendDataMessage("{LSEND}")
    end
    self.MainWindow.LeftPane.SyncBtn:SetWidth(120)
    self.MainWindow.LeftPane.SyncBtn:SetHeight(20)
    self.MainWindow.LeftPane.SyncBtn:SetText(L["Sync"])
    self.MainWindow.LeftPane.SessBtn:SetText(L["Session"])
    self.MainWindow.RightPane.TextSyncBtn:Disable()
    if(self.currInstanceId ~= "EMPTY")then
        --self.MainWindow.LeftPane.SyncBtn:Disable()
        self.MainWindow.LeftPane.StdBtn:Enable()
        self.MainWindow.LeftPane.SessResetBtn:Enable()
        self.MainWindow.LeftPane.PingPaintBtn:Disable()
    end

end;

-----------------------------------------------------
--sends the raidmessages
-----------------------------------------------------

function BossTactics:SendRaMessages()

    local tbl = { strsplit("\n", self.MainWindow.RightPane.ScrollRaidMsgFrame:GetScrollChild():GetText()) }
    for i,v in ipairs(tbl)do
        SendChatMessage(v,"RAID")
    end
end;

-----------------------------------------------------
--synchronize the raid
--mode: boolean true --> normal sync; false --> syncrequest to target
-----------------------------------------------------

function BossTactics:SyncRaid(mode,target)

    if(not self.MainWindow) then return end

    if(self.currInstanceId == "EMPTY")then
        if(mode)then
            self:BT_SendDataMessage("{NOINSTNCE}")
        else
            self:BT_SendDataMessage("{NOINSTNCE}",true,target)
        end
    else
        local bossText
	    if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
            bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].tactictext[self.MainWindow.RightPane.SwitchStdBtn.currId]
        else
            bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].trash[self.MainWindow.RightPane.SwitchStdBtn.currId]
        end
        if(mode) then
            self:BT_SendDataMessage("{INSTINFO:"..self.currAddon..":"..self.currInstanceId..":"..self.currBossId..":"..self.currImgId..":"..self.currInstanceMemberMax.."}")
            if(self.MainWindow.RightPane.TrashBtn.stdTactic and self.MainWindow.RightPane.TextSyncBtn.sync)then
                self:BT_SendDataMessage("{TRST:1}")
            else
                self:BT_SendDataMessage("{TRST:0}")
            end
            if(self.MainWindow.RightPane.SwitchStdBtn.currId ~= 1 and self.MainWindow.RightPane.TextSyncBtn.sync)then
            	self:BT_SendDataMessage("{TASW:"..self.MainWindow.RightPane.SwitchStdBtn:GetText()..":"..bossText.version.."}")
           end
        else    self:BT_SendDataMessage("{INSTINFO:"..self.currAddon..":"..self.currInstanceId..":"..self.currBossId..":"..self.currImgId..":"..self.currInstanceMemberMax.."}",true,target)
        	if(self.MainWindow.RightPane.TrashBtn.stdTactic and self.MainWindow.RightPane.TextSyncBtn.sync)then
                self:BT_SendDataMessage("{TRST:1}")
            else
                self:BT_SendDataMessage("{TRST:0}")
            end
        	if(self.MainWindow.RightPane.SwitchStdBtn.currId ~= 1 and self.MainWindow.RightPane.TextSyncBtn.sync)then
            	self:BT_SendDataMessage("{TASW:"..self.MainWindow.RightPane.SwitchStdBtn:GetText()..":"..bossText.version.."}",true,target)
           end
        end
        local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
        local defaultDB = module:GetDefaults()
        local defaultBoss = defaultDB.profile.bosses[self.currInstanceMode][self.currBossId]
        local msg = ""

        --inform about new or changed buttons, which are not in defaults
        for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(v:IsShown() and v.dragged) then
                local btn = defaultBoss.imgdata[self.currImgId].buttons[v.id]
                local point, relativeTo, relativePoint, xOfs, yOfs = v:GetPoint(1)
                if(btn == nil)then
                    msg = msg..";".."{BTN:"..v.id..":"..floor(xOfs)..":"..floor(yOfs)..":"..v.typename.."}"
                    if(v.text:GetText() ~= self:GetTypeFromButtonType(v.typename).text)then
                        msg = msg..";".."{BTCT:"..v.id..":"..v.text:GetText().."}"
                    end
                else
                    if(btn.x ~= floor(xOfs) or btn.y ~= floor(yOfs))then
                        msg = msg..";".."{BTMV:"..v.id..":"..floor(xOfs)..":"..floor(yOfs).."}"
                    end
                    if(v.text:GetText() ~= btn.caption)then
                        msg = msg..";".."{BTCT:"..v.id..":"..v.text:GetText().."}"
                    end
                end
            end
        end

        --inform about deleted buttons
        for i, v in ipairs(defaultBoss.imgdata[self.currImgId].buttons) do
            local found = false
            for index,value in ipairs(self.MainWindow.LeftPane.buttons) do
                if(value.id == i and self:ButtonEqual(value))then
                    found = true
                    break
                end
            end
            if(not found)then
                msg = msg..";".."{BTRM:"..i.."}"
            end
        end
        if(strlen(msg)>0)then
            if(mode)then
                self:BT_SendDataMessage(strsub(msg,2))
            else
                self:BT_SendDataMessage(strsub(msg,2),true,target)
            end
        end

        self:SyncDrawings(mode,target)

    end
    self:CompareRaid()
    self:BT_SendDataMessage("{RLVERCH}")
end;

---------------------------------------------------------
--syncs only the drawing part step by step
---------------------------------------------------------

function BossTactics:SyncDrawings(mode,target)

    if(not self.syncDraw)then return end
    --if(not self.MainWindow) then return end

    self.countedSyncs = 0
    self.totalSyncs = 0
    self.syncFinished = false
    if(self.MainWindow.LeftPane.ImgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].count > 0 and
        not self.MainWindow.LeftPane.ImgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].deleted) then
        self.syncInProgressTimer:ScheduleRepeatingTimer("BT_SyncProgressTimer", function () BossTactics:SyncProgress() end, 0.2)
        if(mode)then
            self:BT_SendDataMessage("{DRAWDEL}")
        else
            self:BT_SendDataMessage("{DRAWDEL}",true,target)
        end
        local anzLines = #self.MainWindow.LeftPane.ImgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures
        for i,v in ipairs (self.MainWindow.LeftPane.ImgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures)do
            if(v:IsShown())then
                if(mode)then
                    self:BT_SendDataMessage("{DL:"..v.data.sx..":"..v.data.sy..":"..v.data.ex..":"..v.data.ey.."}")
                else
                    self:BT_SendDataMessage("{DL:"..v.data.sx..":"..v.data.sy..":"..v.data.ex..":"..v.data.ey.."}",true,target)
                end
                self.totalSyncs = self.totalSyncs +1
            end
        end
        if(mode)then
            self:BT_SendDataMessage("{DRAWSYNCEND}")
        else
            self:SendCommMessage("{DRAWSYNCEND}",true,target)
            self:OnCommReceive("BOSSTACTICS", "{DRAWSYNCEND}", "RAID", self.player)
        end
    end
    self.syncDraw = false
end;

function BossTactics:SyncProgress()

    if(not self.syncFinished)then
        self:ShowInfoMessage(string.format(L["syncmessage"],(self.countedSyncs/self.totalSyncs)*100))
    else
        self.syncInProgressTimer:CancelTimer("BT_SyncProgressTimer");
        self:ShowInfoMessage(string.format(L["syncmessage"],100.0))
        self.InfoMessageFrame:Hide()
    end

end;

-------------------------------------------------------------
--user session handling
-------------------------------------------------------------

function BossTactics:StartUserSession(target, showAnyway)

    local anzMembers = GetNumRaidMembers()
    for i=1, anzMembers, 1 do
        local name, rank, subgroup, level, class,
                fileName,zone, online, isDead, role, isML = GetRaidRosterInfo(i)
        if(name and self.currInstanceMemberMax ~= -1 and name == self.player and subgroup > self.currInstanceMemberMax/5)then
        	if(not showAnyway)then
        		if(not self.isNotWatching and not self.isNotWatchingAsked)then
                    self:ShowTacticQuestionFrame(target)
                    return
                elseif(self.isNotWatching and self.isNotWatchingAsked) then
                	return
                end
            end
        end
    end

    self.currSessionBtnId = self.SESSIONID
    if(target)then
        self:Print(string.format(L["session started"],target))
    end
    self.isSession = true;
    self.currSessionBtnId = self.SESSIONID
    self:openBossFrame()
    self:UserSessionImgSwitch()
    if(self.MainWindow.LeftPane.SessBtn ~= nil)then
        self.MainWindow.LeftPane.SessBtn:Disable()
        self.MainWindow.LeftPane.StdBtn:Disable()
        self.MainWindow.LeftPane.PingPaintBtn:Enable()
        self.MainWindow.RightPane.TextSyncBtn:Disable()
    end
    --self.MainWindow.LeftPane.SyncBtn:Enable()
    self.MainWindow.LeftPane.SessResetBtn:Disable()
end;

------------------------------------------------------
--helps to switch a user image when there is a session
------------------------------------------------------

function BossTactics:UserSessionImgSwitch()
    if(not self.MainWindow) then return end
    if(self.incompatibleModule)then return end

    if(self.modules[self.currModuleId] ~= nil)then
        local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
        local defaultDB = module:GetDefaults()
        local defaultBoss = defaultDB.profile.bosses[self.currInstanceMode][self.currBossId]

        local btnsToRemove = {}
        --remove added buttons or change to old texts
        for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(v:IsShown() and v.dragged) then
                local btn = defaultBoss.imgdata[self.currImgId].buttons[v.id]
                if(btn == nil)then
                    tinsert(btnsToRemove,v)
                else
                    v:ClearAllPoints()
                    v:SetPoint("TOPLEFT",self.MainWindow.LeftPane,"TOPLEFT",btn.x,btn.y)
                    if(btn.caption == nil)then
                        v.text:SetText(self:GetTypeFromButtonType(btn.type).text)
                    else
                        v.text:SetText(btn.caption)
                    end
                end
            end
        end

        for i,v in ipairs(btnsToRemove) do
            for index,value in ipairs(self.MainWindow.LeftPane.buttons)do
                if(v.id==value.id and self:ButtonEqual(v, value))then
                    v:Hide()
                    tinsert(self.MainWindow.LeftPane.buttonPool,tremove(self.MainWindow.LeftPane.buttons,index))
                    break
                end
            end
        end

        --recover deleted buttons
        for i, v in ipairs(defaultBoss.imgdata[self.currImgId].buttons) do
            local found = false
            for index,value in ipairs(self.MainWindow.LeftPane.buttons) do
                if(value.id == i and self:ButtonEqual(value))then
                    found = true
                    value:Show()
                    break
                end
            end
            if(not found)then
                if(v.caption == nil)then
                    self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,self:GetTextFromButtonType(v.type),v.x,v.y,i)
                else
                    self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,v.caption,v.x,v.y,i)
                end
            end
        end
    end
end;

----------------------------------------------------
--handles the end of a session
----------------------------------------------------

function BossTactics:EndUserSession(target)

    if(not self.MainWindow) then return end

    self.isSession = false;
    self:ResetSessionIds()
    if(self.currInstanceId ~= "EMPTY")then
        if(self.MainWindow.LeftPane.SessBtn)then
            self.MainWindow.LeftPane.SessBtn:Enable()
            self.MainWindow.LeftPane.StdBtn:Enable()
            self.MainWindow.LeftPane.PingPaintBtn:Disable()
        end
        --self.MainWindow.LeftPane.SyncBtn:Disable()
        self.MainWindow.LeftPane.SaveBtn:Enable()
        self.MainWindow.LeftPane.SessResetBtn:Enable()
    end
    if(target)then
        self:Print(string.format(L["session ended"],target))
    end
end;


-------------------------------------------------
--resets the session ids to normal ids
-------------------------------------------------

function BossTactics:ResetSessionIds()

    if(not self.MainWindow) then return end

    for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
        if(v.dragged)then
            local btnId = self.currBtnId--self.modules[v.moduleId].bosses[v.bossId].imgdata[v.imgId].btnId
            if(v.id > btnId)then
                v.id = btnId
                self.currBtnId = btnId + 1
            end
        end
    end

end;

---------------------------------------------------------
--resets the session data if the user likes to
---------------------------------------------------------

function BossTactics:ResetSessionData()

    --local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
    --local defaultDB = module:GetDefaults()
    --local defaultBoss = defaultDB.profile.bosses[self.currBossId]
    if(not self.MainWindow) then return end

    if(self:IsSession())then
    	self:ShowInfoMessage(L["not while session"])
    	return
    end

    self.isSession = false;
    while(self:ButtonsDragged(self.MainWindow.LeftPane.buttons))do
        for i, v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(v.dragged)then
                v:Hide()
                tinsert(self.MainWindow.LeftPane.buttonPool,tremove(self.MainWindow.LeftPane.buttons,i))
                break
            end
        end
    end
    self:ShowBossImage(self.currImgId)
    self.MainWindow.LeftPane.SessResetBtn:Disable()
end;

--helps to delete all dragged buttons
function BossTactics:ButtonsDragged(tableVar)

    for i, v in ipairs(tableVar) do
        if(v.dragged)then
            return true
        end
    end
    return false
end;

------------------------------------------------------------
-- handels a switch in the addon menu
--instance: the name of the instance module
------------------------------------------------------------

function BossTactics:HandleAddonSwitch(newAddon)

    if(not self.MainWindow) then return end

    local leftpane = self.MainWindow.LeftPane
    local rightpane = self.MainWindow.RightPane

    self.currAddon = newAddon
    self.currInstanceId = "EMPTY"
    self.currImgId = -1
    self.currModuleId = -1
    self.currBossId = -1

    leftpane.BossBtn:Disable()
    leftpane.AddonBtn:SetText(newAddon)
    rightpane.ScrollRight:GetScrollChild():SetText("")
    rightpane.TrashBtn:Disable()
    leftpane.PrevImgBtn:Disable()
    leftpane.NextImgBtn:Disable()
    rightpane.SwitchStdBtn:Disable()
    rightpane.TrashBtn:Disable()
    rightpane.SaveBtn:Disable()
    rightpane.SaveAsBtn:Disable()
    rightpane.DelBtn:Disable()
    leftpane.StdBtn:Disable()
    leftpane.titleLeftPane:SetText("BossTactics")
    leftpane.ImgPane.texture1:SetTexture(nil)
    for i,v in ipairs(leftpane.ImgPane.fontstrings)do
    	v:Hide()
    end
    leftpane.ImgPane.fontstrings = {}
    leftpane.ImgPane.LegendPane:Hide()

    while(self:ButtonsDragged(self.MainWindow.LeftPane.buttons))do
        for i, v in ipairs(self.MainWindow.LeftPane.buttons) do
            if(v.dragged)then
                v:Hide()
                tinsert(self.MainWindow.LeftPane.buttonPool,tremove(self.MainWindow.LeftPane.buttons,i))
                break
            end
        end
    end

    if(self:IsRaidLeader())then
        rightpane.ScrollRaidMsgFrame:GetScrollChild():SetText("")
    end

end;

------------------------------------------------------------
--
------------------------------------------------------------
function BossTactics:SetInstanceMode(mode)

	if(self.incompatibleModule)then return end

    if(not self.modules[self.currModuleId].bosses[mode]) then
        self:ShowInfoMessage(L["mode not supported"]);
        return
    end
    if(self.currBossId ~= -1) then
    	local imgPane = self.MainWindow.LeftPane.ImgPane
        if(imgPane.lines[self.currInstanceId] and
        	imgPane.lines[self.currInstanceId][self.currInstanceMode] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId])then
            self:HideLines(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures)
        end
    end
    self.currInstanceMode = mode
    self.currInstanceMemberMax = tonumber(strsub(mode,5))
    self.MainWindow.LeftPane.ModeBtn:SetText(L["mode"].." "..self.currInstanceMemberMax)
    if(self.currBossId ~= -1) then
    	self:ShowBossTactic(self.currBossId)
    else
    	self:ShowBossTactic(1)
    end
end;

------------------------------------------------------------
-- handels a switch in the menu
--instance: the name of the instance module
------------------------------------------------------------

function BossTactics:HandleInstanceSwitch(instanceModule)

    if(not self.MainWindow) then return end

    if(instanceModule == nil) then return end

    if(not IsAddOnLoaded(instanceModule)) then
        self:LoadInstanceModule(instanceModule)
    end

     if(IsAddOnLoaded(instanceModule)) then
     	local found = false
        for i,v in ipairs(self.incompatibleModules)do
        	if(v == instanceModule)then
        		self.incompatibleModule = true
        		found = true
        		break
        	end
        end
        if not found then
        	self.incompatibleModule = false
        end
     else
     	self.incompatibleModule = true
     	return
     end

     if(self:IsDebug())then
     	self:Print(self.incompatibleModule)
     end

    local bosstable = {}
    local found = false
    local imgPane = self.MainWindow.LeftPane.ImgPane

    for i,v in ipairs(self.modules) do
        if(v.id == instanceModule) then
            --clear up shown lines
            if(self.currModuleId ~= -1) then
                if(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId])then
                    self:HideLines(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures)
                end
            end
            --set the instance id
            self.currModuleId = i
            self.currInstanceId = instanceModule
            --defining the mode
            local anzMembers = GetNumRaidMembers()
            local mode = ""
            if(anzMembers >= 20)then
            	mode = "mode25"
            else
            	mode = "mode10"
            end
            self.currBossId = -1
            if(v.bosses[mode])then
              self:SetInstanceMode(mode)
            else
              local counter = false
              table.foreach(v.bosses, function (i,v)
                 if (counter) then  return;
                else self:SetInstanceMode(i); counter = true; end
              end)
            end
            --copy bossnames for menue
            for index,Boss in ipairs(v.bosses[self.currInstanceMode]) do
                table.insert(bosstable,{ Boss.name, index })
            end
            found = true
            self.currBossTable = bosstable
            break
        end
    end
    if(found) then
        self.MainWindow.LeftPane.BossBtn:Enable()
        self.MainWindow.LeftPane.ModeBtn:Enable()
    end

end;

-----------------------------------------------------------
-- Shows the tactics from a boss
-- id: bossid of the current instance
-----------------------------------------------------------

function BossTactics:ShowBossTactic(id)

    if(not self.MainWindow) then return end
    if(self.incompatibleModule)then return end

    local boss = self.modules[self.currModuleId].bosses[self.currInstanceMode][id]
    local leftpane = self.MainWindow.LeftPane
    local rightpane = self.MainWindow.RightPane
    local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
    local defaultDB = module:GetDefaults()
    local defaultBoss = defaultDB.profile.bosses[self.currInstanceMode][id]
    local imgPane = self.MainWindow.LeftPane.ImgPane

    leftpane.titleLeftPane:SetText(self.modules[self.currModuleId].instance.." - "..boss.name)
    if(self:IsRaidLeader())then
        rightpane.ScrollRaidMsgFrame:GetScrollChild():SetText(boss.ratext)
    end
    if(boss.trash)then
        rightpane.TrashBtn:Enable()
        rightpane.TrashBtn:SetText(L["Trash"])
        rightpane.TrashBtn.stdTactic = true
    else
        rightpane.TrashBtn:Disable()
    end

    --clear up shown lines
    if(self.currBossId ~= -1) then
        if(imgPane.lines[self.currInstanceId] and
        	imgPane.lines[self.currInstanceId][self.currInstanceMode] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId])then
            self:HideLines(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures)
        end
    end

    --update the action buttons
    if(boss.actionBtn1)then
    	imgPane.Action1Btn:SetText(boss.actionBtn1.text)
    	imgPane.Action1Btn.ClickAction = boss.actionBtn1.action
    	if(boss.actionBtn1.raidleadOnly)then
    		if(self:IsRaidLeader())then
    			imgPane.Action1Btn:Show()
    		else
    			imgPane.Action1Btn:Hide()
    		end
    	else
    		imgPane.Action1Btn:Show()
    	end
    else
    	imgPane.Action1Btn:Hide()
    end
    if(boss.actionBtn2)then
    	imgPane.Action2Btn:SetText(boss.actionBtn2.text)
    	imgPane.Action2Btn.ClickAction = boss.actionBtn2.action
    	if(boss.actionBtn2.raidleadOnly)then
    		if(self:IsRaidLeader())then
    			imgPane.Action2Btn:Show()
    		else
    			imgPane.Action2Btn:Hide()
    		end
    	else
    		imgPane.Action2Btn:Show()
    	end
    else
    	imgPane.Action2Btn:Hide()
    end
    if(boss.actionBtn3)then
    	imgPane.Action3Btn:SetText(boss.actionBtn3.text)
    	imgPane.Action3Btn.ClickAction = boss.actionBtn3.action
    	if(boss.actionBtn3.raidleadOnly)then
    		if(self:IsRaidLeader())then
    			imgPane.Action3Btn:Show()
    		else
    			imgPane.Action3Btn:Hide()
    		end
    	else
    		imgPane.Action3Btn:Show()
    	end
    else
    	imgPane.Action3Btn:Hide()
    end


    self.currBossId = id
    self.MainWindow.LeftPane.Patchlvl:SetText(self.modules[self.currModuleId].patchlevel)
    self:HandleTacticSwitch(1)
    self.MainWindow.RightPane.SaveAsBtn:Enable()
    self.MainWindow.RightPane.SwitchStdBtn:Enable()
    self.MainWindow.LeftPane.StdBtn:Enable()
    self:ShowBossImage(1)

end;

-----------------------------------------------------------
-- Shows a image from a boss
-- id: imgid of the current boss
-----------------------------------------------------------

function BossTactics:ShowBossImage(id)

    if(not self.MainWindow) then return end
    if(self.incompatibleModule)then return end

    local boss = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]
    local imgPane = self.MainWindow.LeftPane.ImgPane

    if(id == 1) then
        self.MainWindow.LeftPane.PrevImgBtn:Disable()
    else
        self.MainWindow.LeftPane.PrevImgBtn:Enable()
    end
    if(id < #(boss.imgdata)) then
        self.MainWindow.LeftPane.NextImgBtn:Enable()
    else
        self.MainWindow.LeftPane.NextImgBtn:Disable()
    end

    --imgPane:SetBackdrop({
   --         bgFile = boss.imgdata[id].source, tile = false,
    --    })
    imgPane.texture1:SetTexture(boss.imgdata[id].source)



    --clear up shown lines
    if(self.currImgId ~= -1) then
        if(imgPane.lines[self.currInstanceId] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId] and
            imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId] )then
            self:HideLines(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures)
        end
    end

    self.currImgId = id
    self.currBtnId = boss.imgdata[self.currImgId].btnId
    local found = false

    for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
        if(self:ButtonEqual(v) and v.dragged) then
            found = true
            v:Show()
        --show the pool buttons
        elseif(not v.dragged)then
            v:Show()
        else
            v:Hide()
        end
    end

    local btnDB = boss.imgdata[self.currImgId].buttons
    if(not found and btnDB) then
        for i,v in ipairs(btnDB) do
            if(v.caption == "")then v.caption = " " end
            if(not v.deleted)then
                if(v.caption == nil)then
                    self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,self:GetTypeFromButtonType(v.type).text,v.x,v.y,i)
                else
                    self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,v.caption,v.x,v.y,i)
                end
            end
        end
    end

    for i,v in ipairs(imgPane.fontstrings) do
        v:Hide()
    end
    imgPane.fontstrings = {}

    local fontstrDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].imgdata[self.currImgId].fontstrings
    if(fontstrDB) then
        for i,v in ipairs(fontstrDB) do
            self:CreateMapFontstring(v.text,v.x,v.y,v.font,v.r,v.g,v.b)
        end
    end


    local legendDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].imgdata[self.currImgId].legend
    if(legendDB)then
        --clear the old legend pane
        for i,v in ipairs(imgPane.LegendPane.fontstrings) do
            v:Hide()
        end
        imgPane.LegendPane.fontstrings = {}

        local btnsToRemove = {}
        --copy all buttons into the pool
        for i,v in ipairs(imgPane.LegendPane.buttons) do
            tinsert(btnsToRemove,v)
        end

        for i,v in ipairs(btnsToRemove) do
            for index,value in ipairs(imgPane.LegendPane.buttons)do
                if(v.id==value.id)then
                    v:Hide()
                    tinsert(imgPane.LegendPane.buttonPool,tremove(imgPane.LegendPane.buttons,index))
                    break
                end
            end
        end

        imgPane.LegendPane:Show()

        local anz = 0
        for i,v in ipairs(legendDB.entries) do
            local btn
            if(#imgPane.LegendPane.buttonPool > 0)then
                btn = tremove(imgPane.LegendPane.buttonPool)
            else
                btn = CreateFrame("Button",nil,imgPane.LegendPane)
            end
            local type = self:GetTypeFromButtonType(v.type)
            btn:SetFrameLevel(imgPane.LegendPane:GetFrameLevel()+2)
            if(type ~= nil)then
                btn:SetWidth(20)
                btn:SetHeight(20)
                btn:ClearAllPoints()
                btn:SetPoint("TOPLEFT",imgPane.LegendPane,"TOPLEFT",(math.floor((i-1)/3)*120)+5, -(2+((i-1)%3)*20))       --,2+((i-1)%2)*90,-((math.floor((i-1)/2)*20)+2))
                btn:SetMovable(false)
                btn:SetNormalTexture(type.button)
                btn:SetAlpha(1.0)
                btn.id = i
                btn:Show()
                tinsert(imgPane.LegendPane.buttons,btn)

                local fontstr = imgPane.LegendPane:CreateFontString(nil,"OVERLAY","GameFontNormal")
                fontstr:SetTextColor(v.r,v.g,v.b)
                fontstr:SetText(v.caption)
                fontstr:SetPoint("TOPLEFT",imgPane.LegendPane,"TOPLEFT",(math.floor((i-1)/3)*120)+25, -(2+((i-1)%3)*20+4))                 --32+((i-1)%2)*90,-((math.floor((i-1)/2)*20)+4))
                tinsert(imgPane.LegendPane.fontstrings,fontstr)
            else
                self:Print("Buttontype "..v.type.." does not exist")
            end
            anz = anz+1
        end

    else
        imgPane.LegendPane:Hide()
    end

    --if there are lines show them, if not create the data structure

    if(not imgPane.lines[self.currInstanceId])then
        imgPane.lines[self.currInstanceId] = {}
    end
    if(not imgPane.lines[self.currInstanceId][self.currInstanceMode])then
    	imgPane.lines[self.currInstanceId][self.currInstanceMode] = {}
    end
    if(not imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId])then
        imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId] = {}
    end
    if(self:IsRaidLeader())then
        imgPane.PaintDelBtn:Hide()
    end
    if(not imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId])then
        imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId] = {}
        imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures = {}
        imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].deleted = true
        imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].count = 0
    else
        if(not imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].deleted)then
            self:ShowLines(imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].textures,
                 imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].count)
            if(not (imgPane.lines[self.currInstanceId][self.currInstanceMode][self.currBossId][self.currImgId].count == 0) and self:IsRaidLeader())then
                imgPane.PaintDelBtn:Show()
            end
        end
    end

    --save button restore
    if(self:CheckImgDataChanged())then
        self.dataChanged = true
        self.MainWindow.LeftPane.SaveBtn:Enable()
    else
        self.dataChanged = false
        self.MainWindow.LeftPane.SaveBtn:Disable()
    end

end;

------------------------------------------------------------
--loads a Instanze Module
--module: string module
------------------------------------------------------------

function BossTactics:LoadInstanceModule(module)

    local loaded, reason = LoadAddOn(module)

    if not loaded then
      tinsert(self.incompatibleModules,module)
      if reason == "DISABLED" then
        self:Print(string.format(L["Module disabled"],module))
      elseif reason == "MISSING" then
        self:Print(string.format(L["Module missing"],module))
      elseif reason == "CORRUPT" then
        self:Print(string.format(L["Module corrupt"],module))
      elseif reason == "INTERFACE_VERSION" then
        self:Print(string.format(L["Module interface version"],module))
      end
    else
     for i,v in ipairs(self.modules) do
     	if v.id == module then
     		self:BT_SendDataMessage("{MVER:"..module..":"..v.version.."}")
     	    break
     	end
     end
      self:Print(string.format(L["Module loaded"],module))
    end

end;

-----------------------------------------------
--handles a tactic switch to tactic id
-----------------------------------------------

function BossTactics:HandleTacticSwitch(id,version)
    local rightpane = self.MainWindow.RightPane
    local boss = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]

    local mode
    if(rightpane.TrashBtn.stdTactic)then
        mode = "tactic"
    else
        mode = "trash"
    end

    if(boss.trash == nil) then mode = "tactic" end

    if(mode == "trash")then
        if(version)then
        	if(boss.trash[id].version ~= version)then
        		self:BT_SendDataMessage("{TXTSREQ}")
        	end
        end
        rightpane.ScrollRight:GetScrollChild():SetText(self:CheckColors(boss.trash[id].data))
        rightpane.SwitchStdBtn:SetText(boss.trash[id].name);
        rightpane.TrashBtn.trashId = id
    else
    	if(version)then
        	if(boss.tactictext[id].version ~= version)then
        		self:BT_SendDataMessage("{TXTSREQ}")
        	end
        end
        rightpane.ScrollRight:GetScrollChild():SetText(self:CheckColors(boss.tactictext[id].data))
        rightpane.SwitchStdBtn:SetText(boss.tactictext[id].name);
        rightpane.TrashBtn.tacticId = id

    end
    rightpane.ScrollRight:GetScrollChild():SetCursorPosition(1)
    rightpane.SaveBtn:Disable()
    rightpane.SwitchStdBtn.currId = id
    if(id == 1)then
        rightpane.DelBtn:Disable()
    else
        rightpane.DelBtn:Enable()
    end
    rightpane.SwitchStdBtn:Enable()
end;

function BossTactics:TextToId(text)
	local bossText
	if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].tactictext
    else
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].trash
    end
	for i,v in ipairs(bossText)do
		if(v.name == text)then
			return i;
		end
	end
	return -1;
end


------------------------------------------------
--deletes the current selected text
------------------------------------------------

function BossTactics:DelTacticText()

    local bossDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]
    local textId = self.MainWindow.RightPane.SwitchStdBtn.currId
    if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
        tremove(bossDB.tactictext,textId)
    else
        tremove(bossDB.trash,textId)
    end

    self:HandleTacticSwitch(1)

end;

----------------------------------------------------
--saves the current text
----------------------------------------------------

function BossTactics:SaveText(version)

    local bossDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]
    local textId = self.MainWindow.RightPane.SwitchStdBtn.currId
    if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
        bossDB.tactictext[textId].data = self.MainWindow.RightPane.ScrollRight:GetScrollChild():GetText()
        if(not version)then
        	version = bossDB.tactictext[textId].version + 1
        end
        bossDB.tactictext[textId].version = version
    else
        bossDB.trash[textId].data = self.MainWindow.RightPane.ScrollRight:GetScrollChild():GetText()
        if(not version)then
        	version = bossDB.trash[textId].version + 1
        end
        bossDB.trash[textId].version = version
    end

    self.MainWindow.RightPane.SaveBtn:Disable()
end;

----------------------------------------------------
--saves the current text as a new text
----------------------------------------------------

function BossTactics:SaveAsText(newName)

    if(not newName)then return end

    if(not self:CheckTextNew(true,newName))then return end

    local bossDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]

	local id = 0

    if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
        tinsert(bossDB.tactictext, {["name"]=newName,["data"] = self.MainWindow.RightPane.ScrollRight:GetScrollChild():GetText(),["version"]=1})
        id = #bossDB.tactictext
        self.MainWindow.RightPane.TrashBtn.tacticId = id
    else
        tinsert(bossDB.trash, {["name"]=newName,["data"] = self.MainWindow.RightPane.ScrollRight:GetScrollChild():GetText(),["version"]=1})
        id = #bossDB.trash
        self.MainWindow.RightPane.TrashBtn.trashId = id
    end

    self.MainWindow.RightPane.SaveBtn:Disable()
    self.MainWindow.RightPane.SwitchStdBtn:SetText(newName)
    self.MainWindow.RightPane.SwitchStdBtn.currId = id
end;

function BossTactics:CheckTextNew(output,newname)

	local bossText

	if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].tactictext
    else
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].trash
    end
    for i,v in ipairs(bossText)do
        if(v.name == newname)then
            if(output)then
                self:ShowInfoMessage(L["tactic name already used"])
            end
            return false
        end
    end
	return true
end

---------------------------------------------------
--handles the sync of texts
---------------------------------------------------

function BossTactics:SyncText()

	if(not(self:IsSession() and self.isSessionLeader)) then return end

    local bossText

    if(self.MainWindow.RightPane.TrashBtn.stdTactic)then
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].tactictext[self.MainWindow.RightPane.SwitchStdBtn.currId]
    else
    	bossText = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId].trash[self.MainWindow.RightPane.SwitchStdBtn.currId]
    end

    if(bossText.name == "BossTactics") then return end

	if(self.MainWindow.RightPane.TextSyncBtn.sync)then
        self.countedSyncs = 0
        self.totalSyncs = 0
        self.syncFinished = false
        if(self.currInstanceId ~= "EMPTY") then
            self.syncInProgressTimer:ScheduleRepeatingTimer("BT_SyncProgressTimer", function () BossTactics:SyncProgress() end, 0.2)
            self:BT_SendDataMessage("{TEXTSYNC:"..bossText.name..":"..bossText.version.."}")
            local anzParts = strlen(bossText.data) / 200
            if(anzParts - math.floor(anzParts) ~= 0)then
            	anzParts = math.floor(anzParts) + 1
            end
            local counter =0
            for i=0, anzParts-1, 1 do
            	self:BT_SendDataMessage("{TXT:"..strsub(bossText.data, i*200, (i+1)*200).."}")
            	counter = counter +1
            end
            self.totalSyncs = anzParts

           	self:Print(counter)
            self:BT_SendDataMessage("{TEXTSYNCEND}")
        end
	end

end

----------------------------------------------------
--saves current shown values
----------------------------------------------------

function BossTactics:SaveValues()

    if(self:IsSession())then
        self:ShowInfoMessage(L["no save while session"])
        return
    end
    local bossDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]
    local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
    local defaultDB = module:GetDefaults()
    local defaultBoss = defaultDB.profile.bosses[self.currInstanceMode][self.currBossId]

    if(self:IsRaidLeader())then
        bossDB.ratext = self.MainWindow.RightPane.ScrollRaidMsgFrame:GetScrollChild():GetText()
    end

    --bossDB.imgdata[self.currImgId].buttons = {}
    local anz = 0
    for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
        if(v:IsShown() and v.dragged) then
            local point, relativeTo, relativePoint, xOfs, yOfs = v:GetPoint(1)
            if(bossDB.imgdata[self.currImgId].buttons[v.id] ~= nil and not bossDB.imgdata[self.currImgId].buttons[v.id].new)then
                bossDB.imgdata[self.currImgId].buttons[v.id].x = xOfs
                bossDB.imgdata[self.currImgId].buttons[v.id].y= yOfs
                bossDB.imgdata[self.currImgId].buttons[v.id].caption = v.text:GetText()
                bossDB.imgdata[self.currImgId].buttons[v.id].found = true
            else
                local btn = {}
                btn.x = xOfs
                btn.y = yOfs
                btn.type = v.typename
                btn.caption = v.text:GetText()
                btn.new = true
                btn.found = true
                tinsert(bossDB.imgdata[self.currImgId].buttons, btn)
            end
            anz = anz+1
        end
    end
    local btnsToRemove = {}
    for i,v in ipairs(bossDB.imgdata[self.currImgId].buttons) do
        if(i >= defaultBoss.imgdata[self.currImgId].btnId and not v.found)then
            tinsert(btnsToRemove,bossDB.imgdata[self.currImgId].buttons[i])
        end
    end
    for i,v in ipairs(btnsToRemove) do
        for index,value in ipairs(bossDB.imgdata[self.currImgId].buttons) do
            if(v.x == value.x and v.y == value.y)then
                tremove(bossDB.imgdata[self.currImgId].buttons,index)
            end
        end
    end
    for i,v in ipairs(bossDB.imgdata[self.currImgId].buttons) do
        v.new = nil
        v.found = nil
    end
    --mark deleted standard buttons
    for i,v in ipairs(defaultBoss.imgdata[self.currImgId].buttons)do
        local found = false
        for index,value in ipairs(self.MainWindow.LeftPane.buttons)do
            if(value:IsShown() and value.dragged) then
                if(value.id == i)then
                    found = true
                    break
                end
            end
        end
        if(not found)then
            bossDB.imgdata[self.currImgId].buttons[i].deleted = true
            anz = anz+1
        end
    end

    bossDB.imgdata[self.currImgId].btnId = anz+1
    self.MainWindow.LeftPane.SaveBtn:Disable()

    --manage the dataChanged array
    self.dataChanged = false
    for i,v in ipairs(self.dataChangedArray) do
        if(v.instId == self.currInstanceId and
            v.imgId == self.currImgId and v.bossId == self.currBossId) then
            tremove(self.dataChangedArray,i)
            break
        end
    end

    --just make sure that the btnids are the same as set in database
    btnsToRemove = {}
    for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
        if(v:IsShown() and v.dragged) then
            tinsert(btnsToRemove,v)
        end
    end

    for i,v in ipairs(btnsToRemove) do
        for index,value in ipairs(self.MainWindow.LeftPane.buttons)do
            if(v.id==value.id and self:ButtonEqual(value,v))then
                v:Hide()
                tinsert(self.MainWindow.LeftPane.buttonPool,tremove(self.MainWindow.LeftPane.buttons,index))
                break
            end
        end
    end

    self:ShowBossImage(self.currImgId)
end;

----------------------------------------------------
--restores default values to a tactic
----------------------------------------------------

function BossTactics:RestoreDefaults()

    if(self:IsSession())then
    	self:ShowInfoMessage(L["not while session"])
    	return
    end
    local module = LibStub("AceAddon-3.0"):GetAddon( self.modules[self.currModuleId].id )
    local defaultDB = module:GetDefaults()
    local defaultBoss = defaultDB.profile.bosses[self.currInstanceMode][self.currBossId]
    local bossDB = self.modules[self.currModuleId].bosses[self.currInstanceMode][self.currBossId]

    bossDB.ratext = defaultBoss.ratext
    bossDB.imgdata[self.currImgId].btnId = defaultBoss.imgdata[self.currImgId].btnId

    bossDB.imgdata[self.currImgId].buttons = {}

    --copy the default values
    for i,v in ipairs(defaultBoss.imgdata[self.currImgId].buttons)do
        local btn = {}
        btn.x = v.x
        btn.y = v.y
        btn.type = v.type
        btn.caption = v.caption
        tinsert(bossDB.imgdata[self.currImgId].buttons, btn)
    end

    --remove added buttons or change to old texts
    local btnsToRemove = {}
    for i,v in ipairs(self.MainWindow.LeftPane.buttons) do
        if(v:IsShown() and v.dragged and self:ButtonEqual(v)) then
            local btn = bossDB.imgdata[self.currImgId].buttons[v.id]
            if(btn == nil)then
                v:Hide()
                tinsert(btnsToRemove,v)
            else
                v:ClearAllPoints()
                v:SetPoint("TOPLEFT",self.MainWindow.LeftPane,"TOPLEFT",btn.x,btn.y)
                v:SetNormalTexture(self:GetTypeFromButtonType(btn.type).button)
                if(btn.caption == nil)then
                    v.text:SetText(self:GetTypeFromButtonType(btn.type).text)
                else
                    v.text:SetText(btn.caption)
                end
            end
        end
    end

    for i,v in ipairs(btnsToRemove) do
        for index,value in ipairs(self.MainWindow.LeftPane.buttons)do
            if(v.id==value.id and self:ButtonEqual(v,value))then
                v:Hide()
                tinsert(self.MainWindow.LeftPane.buttonPool,tremove(self.MainWindow.LeftPane.buttons,index))
                break
            end
        end
    end

    --recover deleted buttons
    for i, v in ipairs(bossDB.imgdata[self.currImgId].buttons) do
        local found = false
        for index,value in ipairs(self.MainWindow.LeftPane.buttons) do
            if(value.id == i and value.dragged and self:ButtonEqual(value))then
                found = true
                break
            end
        end
        if(not found)then
            if(v.caption == nil)then
                self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,self:GetTypeFromButtonType(v.type).text,v.x,v.y,i)
            else
                self:CreateNewMapButton(self:GetTypeFromButtonType(v.type),false,v.caption,v.x,v.y,i)
            end
        end
    end

    if(self.MainWindow.RightPane.ScrollRaidMsgFrame)then
        self.MainWindow.RightPane.ScrollRaidMsgFrame:GetScrollChild():SetText(bossDB.ratext)
    end
    self:Print(L["defaults recovered"])

end;

function BossTactics:CameraDistanceMax()

	SetCVar("cameraDistanceMaxFactor",5)
	self:Print(L["Camera set to max distance"])

end

-----------------------------------------------------
--prints a name in the classcolor
-----------------------------------------------------

function BossTactics:FindColor(charname)
	local anzMembers = GetNumRaidMembers()
	for i=1, anzMembers, 1 do
        local name, _, _, _, _,fileName = GetRaidRosterInfo(i)
        if(name == charname)then
        	return "|cFF"..self:RgbToHex(RAID_CLASS_COLORS[fileName].r,RAID_CLASS_COLORS[fileName].g, RAID_CLASS_COLORS[fileName].b)..charname.."|r"
        end
    end
	return "|cFFFFFFFF"..charname.."|r"
end

--------------------------------------------------------------
-- converts strings to colors
--------------------------------------------------------------

function BossTactics:CheckColors(inStr)

    --{Group}
    inStr = string.gsub(inStr,"{group}", "|cffff0000")
    inStr = string.gsub(inStr,"{/group}", "|r")

	--{Abilities}
    inStr = string.gsub(inStr,"{abilities}", "|cffff0000")
    inStr = string.gsub(inStr,"{/abilities}", "|r")

    --{Spell}
    inStr = string.gsub(inStr,"{spell}", "|cFF4DFFFD")
    inStr = string.gsub(inStr,"{/spell}", "|r")

    --{tactic}
    inStr = string.gsub(inStr,"{tactic}", "|cffff0000")
    inStr = string.gsub(inStr,"{/tactic}", "|r")

    --{pos}
    inStr = string.gsub(inStr,"{pos}", "|cFFDBD533")
    inStr = string.gsub(inStr,"{/pos}", "|r")

    --{fight}
    inStr = string.gsub(inStr,"{fight}", "|cFFDBD533")
    inStr = string.gsub(inStr,"{/fight}", "|r")

    --{buffs}
    inStr = string.gsub(inStr,"{buffs}", "|cffff0000")
    inStr = string.gsub(inStr,"{/buffs}", "|r")

    --{phase}
    inStr = string.gsub(inStr,"{phase}", "|cff00ff00")
    inStr = string.gsub(inStr,"{/phase}", "|r")

    --{add}
    inStr = string.gsub(inStr,"{add}", "|cFFDBD533")
    inStr = string.gsub(inStr,"{/add}", "|r")

    --{hard}
    inStr = string.gsub(inStr,"{hard}", "|cFF9102D4")
    inStr = string.gsub(inStr,"{/hard}", "|r")

    return inStr

end;

function BossTactics:ChangeFontSize(info, size)

	local newSize = tonumber(size)
	if(newSize)then
		self.db.profile.tacticFontSize = newSize
		self.MainWindow.RightPane.ScrollRight:GetScrollChild():SetFont("Fonts\\FRIZQT__.TTF",self.db.profile.tacticFontSize)
		self:Print(format(L["text size changed"],newSize))
	else
		self:Print(L["error fontsize"])
	end

end;

---------------------------------------------------------------
--Checks if the database must get an overall update
---------------------------------------------------------------

function BossTactics:CheckUpdateDatabase()

    --update because the structure of tactictexts and trashtext changed
    if(self.db.profile.settingsVersion < 2)then
        self:ShowInfoMessage(L["updateinfo for version 1.1"])
        for i,v in pairs(self.instanceTable["BC"].values)do
            for index,value in ipairs(v)do
                self:LoadInstanceModule(value[2])
            end
        end
        for i,v in ipairs(self.modules) do
            local module = LibStub("AceAddon-3.0"):GetAddon( v.id )
            local defaultDB = module:GetDefaults()
            if(v.bosses.mode25)then
                for index,value in ipairs(v.bosses.mode25)do
                    local defaultBoss = defaultDB.profile.bosses["mode25"][index]
                    if(value.tactictext)then
                        if(not value.tactictext[1])then
                            local tmptactic = value.tactictext
                            value.tactictext = {}
                            value.tactictext[1] = {["name"] = defaultBoss.tactictext[1].name, ["data"] = defaultBoss.tactictext[1].data}
                            table.insert(value.tactictext,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                        if(type(value.trash) ~= "table" and defaultBoss.trash)then
                            local tmptactic = value.trash
                            value.trash = {}
                            value.trash[1] = {["name"] = defaultBoss.trash[1].name, ["data"] = defaultBoss.trash[1].data}
                            table.insert(value.trash,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                    end
                end
            end
            if(v.bosses.mode10)then
                for index,value in ipairs(v.bosses.mode10)do
                    local defaultBoss = defaultDB.profile.bosses["mode10"][index]
                    if(value.tactictext)then
                         if(not value.tactictext[1])then
                            local tmptactic = value.tactictext
                            value.tactictext = {}
                            value.tactictext[1] = {["name"] = defaultBoss.tactictext[1].name, ["data"] = defaultBoss.tactictext[1].data}
                            table.insert(value.tactictext,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                        if(type(value.trash) ~= "table" and defaultBoss.trash)then
                            local tmptactic = value.trash
                            value.trash = {}
                            value.trash[1] = {["name"] = defaultBoss.trash[1].name, ["data"] = defaultBoss.trash[1].data}
                            table.insert(value.trash,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                    end
                end
            end
            if(v.bosses.mode40)then
                for index,value in ipairs(v.bosses.mode40)do
                    local defaultBoss = defaultDB.profile.bosses["mode40"][index]
                    if(value.tactictext)then
                         if(not value.tactictext[1])then
                            local tmptactic = value.tactictext
                            value.tactictext = {}
                            value.tactictext[1] = {["name"] = defaultBoss.tactictext[1].name, ["data"] = defaultBoss.tactictext[1].data}
                            table.insert(value.tactictext,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                        if(type(value.trash) ~= "table" and defaultBoss.trash)then
                            local tmptactic = value.trash
                            value.trash = {}
                            value.trash[1] = {["name"] = defaultBoss.trash[1].name, ["data"] = defaultBoss.trash[1].data}
                            table.insert(value.trash,{["name"] = "usertactic", ["data"] = tmptactic,})
                        end
                    end
                end
            end
        end
    end

    if(self.db.profile.settingsVersion <= 3)then
    	self:ShowInfoMessage(L["updateinfo for version 1.1"])
        for i,v in pairs(self.instanceTable["BC"].values)do
            for index,value in ipairs(v)do
                self:LoadInstanceModule(value[2])
            end
        end
        for i,v in pairs(self.instanceTable["WOTLK"].values)do
            for index,value in ipairs(v)do
                self:LoadInstanceModule(value[2])
            end
        end
        for i,v in ipairs(self.modules) do
            if(v.bosses.mode25)then
                for index,value in ipairs(v.bosses.mode25)do
                    if(value.tactictext)then
                         for ind,val in ipairs (value.tactictext) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                    if(value.trash)then
                    	for ind,val in ipairs (value.trash) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                end
            end
            if(v.bosses.mode10)then
                for index,value in ipairs(v.bosses.mode10)do
                    if(value.tactictext)then
                         for ind,val in ipairs (value.tactictext) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                    if(value.trash)then
                    	for ind,val in ipairs (value.trash) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                end
            end
            if(v.bosses.mode40)then
                 for index,value in ipairs(v.bosses.mode40)do
                    if(value.tactictext)then
                         for ind,val in ipairs (value.tactictext) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                    if(value.trash)then
                    	for ind,val in ipairs (value.trash) do
                         	if(ind ~= 1)then
                         		val.version = 1
                         	end
                         end
                    end
                end
            end
        end
    end
    
	-- handle extension of the queryList
    if(self.db.profile.settingsVersion <= 4)then
    	local toBeMoved = {}
    	local db = self.db.profile.queryList
    	local countStdQueries = 3;
    	if(not (db[1].type == "Addons" and
    		db[1].name == "Raid" and
    		db[1].query == "(\"DBM-Core\" or  \"BigWigs\") and \"Omen3\""))then
				tinsert(toBeMoved,{type = db[1].type, name = db[1].name, query = db[1].query})
				db[1].type = defaults.profile.queryList[1].type
				db[1].name = defaults.profile.queryList[1].name
				db[1].std = true
				db[1].query = defaults.profile.queryList[1].query
		end
		if(not (db[2].type == "Items" and
    		db[2].name == "Flask" and
    		db[2].query == "46376 > 0 or 46379 > 0 or 46378 > 0 or 46377 > 0"))then
				tinsert(toBeMoved,{type = db[2].type, name = db[2].name, query = db[2].query})
				db[2].type = defaults.profile.queryList[2].type
				db[2].name = defaults.profile.queryList[2].name
				db[2].std = true
				db[2].query = defaults.profile.queryList[2].query
		end
		if(not (db[3].type == "Items" and
    		db[3].name == "Pot" and
    		db[3].query == "33448 > 0 or 33447 > 0 or 40212 > 0 or 40211 > 0"))then
				tinsert(toBeMoved,{type = db[3].type, name = db[3].name, query = db[3].query})
				db[3].type = defaults.profile.queryList[3].type
				db[3].name = defaults.profile.queryList[3].name
				db[3].std = true
				db[3].query = defaults.profile.queryList[3].query
		end


		local tmpFun = {}
		function tmpFun:checkName(name)
			for ind,val in ipairs(db)do
    			if(name == val.name)then
    				return true;
    			end
    		end
    		return false;
		end
		function tmpFun:checkName2(name,pos)
			for ind,val in ipairs(db)do
    			if(name == val.name and ind ~= pos)then
    				return true;
    			end
    		end
    		return false
		end

    	for i,v in ipairs(toBeMoved)do
    		local count = 1
    		local oldname = v.name
    		while(tmpFun:checkName(v.name))do
    			v.name = oldname..tostring(count)
    			count = count +1
    		end
    		tinsert(db,v);
    	end

    	for i,v in ipairs(db)do
			--ignore the first two, they should not be changed
			if(i > countStdQueries)then
			    local count = 1
                local oldname = v.name
                while(tmpFun:checkName2(v.name,i))do
                    v.name = oldname..tostring(count)
                    count = count +1
                end
    		end
		end
    end

    self.db.profile.settingsVersion = self.db.profile.settingsVersion+1
end;

--------------------------------------------------
--get methods
--------------------------------------------------
function BossTactics:GetCurrInstId()
    return self.currInstanceId
end;

function BossTactics:GetDefaults()
	return defaults
end;