-- Load the addon menu library
local LAM = LibStub("LibAddonMenu-1.0")
local db
local hostileOORColorHex, hostileIRColorHex, hostileIMRColorHex
local alliesOORColorHex, alliesIRColorHex, alliesIMRColorHex
local neutralOORColorHex, neutralIRColorHex, neutralIMRColorHex
local npcsOORColorHex, npcsIRColorHex, npcsIMRColorHex
local previousDimensionsX, previousDimensionsY

-- Defaults for settings
local defaults = {

    hostileNameEnabled = true,
    hostileLevelEnabled = true,
    hostileRangeEnabled = true,
	hostileDifficultyEnabled = true,
    hostileReticleColoringEnabled = true,
    hostileRangeColoringEnabled = true,
    hostileNameLevelColoringEnabled = true,
    hostileOutOfRangeEnabled = true,
    hostileOORColor = {r=1, g=1, b=0},
    hostileInRangeEnabled = true,
    hostileInRangeDistance = 28,
    hostileIRColor = {r=1, g=0.65, b=0},
    hostileInMeleeRangeEnabled = true,
    hostileInMeleeRangeDistance = 5,
    hostileIMRColor = {r=1, g=0, b=0},

    alliesNameEnabled = true,
    alliesLevelEnabled = true,
    alliesRangeEnabled = true,
    alliesReticleColoringEnabled = true,
    alliesRangeColoringEnabled = true,
    alliesNameLevelColoringEnabled = true,
    alliesOutOfRangeEnabled = true,
    alliesOORColor = {r=0, g=1, b=1},
    alliesInRangeEnabled = true,
    alliesInRangeDistance = 28,
    alliesIRColor = {r=0, g=0, b=1},
    alliesInMeleeRangeEnabled = true,
    alliesInMeleeRangeDistance = 5,
    alliesIMRColor = {r=0, g=1, b=0},

    neutralNameEnabled = false,
    neutralLevelEnabled = false,
    neutralRangeEnabled = false,
	neutralDifficultyEnabled = false,
    neutralReticleColoringEnabled = false,
    neutralRangeColoringEnabled = false,
    neutralNameLevelColoringEnabled = false,
    neutralOutOfRangeEnabled = false,
    neutralOORColor = {r=1, g=1, b=0},
    neutralInRangeEnabled = false,
    neutralInRangeDistance = 28,
    neutralIRColor = {r=1, g=0.65, b=0},
    neutralInMeleeRangeEnabled = false,
    neutralInMeleeRangeDistance = 5,
    neutralIMRColor = {r=1, g=0, b=0},

    npcsNameEnabled = false,
    npcsLevelEnabled = false,
    npcsRangeEnabled = false,
    npcsReticleColoringEnabled = false,
    npcsRangeColoringEnabled = false,
    npcsNameLevelColoringEnabled = false,
    npcsOutOfRangeEnabled = false,
    npcsOORColor = {r=0, g=1, b=1},
    npcsInRangeEnabled = false,
    npcsInRangeDistance = 28,
    npcsIRColor = {r=0, g=0, b=1},
    npcsInMeleeRangeEnabled = false,
    npcsInMeleeRangeDistance = 5,
    npcsIMRColor = {r=0, g=1, b=0},
}

-- Convert an RGB color percentage 0 to 1 to Hex
local function RGBPercToHex(r, g, b)
	r = r <= 1 and r >= 0 and r or 0
	g = g <= 1 and g >= 0 and g or 0
	b = b <= 1 and b >= 0 and b or 0
	return string.format("%02x%02x%02x", r*255, g*255, b*255)
end

local function tprint(tbl, indent)
  if not indent then indent = 0 end
  for k, v in pairs(tbl) do
    formatting = string.rep("  ", indent) .. k .. ": "
    if type(v) == "table" then
      CHAT_SYSTEM:AddMessage(formatting)
      tprint(v, indent+1)
    elseif type(v) == 'boolean' then
      CHAT_SYSTEM:AddMessage(formatting .. tostring(v))
    else
      CHAT_SYSTEM:AddMessage(formatting .. tostring(v))
    end
  end
end

-- Setup the addon when it loads
local function AddonSetup()
	-- Populate the settings DB
	Range_ReticleDB = Range_ReticleDB or {}
	for k,v in pairs(defaults) do
	    if type(Range_ReticleDB[k]) == "nil" then
	        Range_ReticleDB[k] = v
	    end
	end
	db = Range_ReticleDB

	-- Convert colors to hex
    hostileIRColorHex = RGBPercToHex(db.hostileOORColor.r,db.hostileOORColor.g,db.hostileOORColor.b)
    hostileOORColorHex = RGBPercToHex(db.hostileIRColor.r,db.hostileIRColor.g,db.hostileIRColor.b)
    hostileIMRColorHex = RGBPercToHex(db.hostileIMRColor.r,db.hostileIMRColor.g,db.hostileIMRColor.b)

    alliesIRColorHex = RGBPercToHex(db.alliesOORColor.r,db.alliesOORColor.g,db.alliesOORColor.b)
    alliesOORColorHex = RGBPercToHex(db.alliesIRColor.r,db.alliesIRColor.g,db.alliesIRColor.b)
    alliesIMRColorHex = RGBPercToHex(db.alliesIMRColor.r,db.alliesIMRColor.g,db.alliesIMRColor.b)

    neutralIRColorHex = RGBPercToHex(db.neutralOORColor.r,db.neutralOORColor.g,db.neutralOORColor.b)
    neutralOORColorHex = RGBPercToHex(db.neutralIRColor.r,db.neutralIRColor.g,db.neutralIRColor.b)
    neutralIMRColorHex = RGBPercToHex(db.neutralIMRColor.r,db.neutralIMRColor.g,db.neutralIMRColor.b)

    npcsIRColorHex = RGBPercToHex(db.npcsOORColor.r,db.npcsOORColor.g,db.npcsOORColor.b)
    npcsOORColorHex = RGBPercToHex(db.npcsIRColor.r,db.npcsIRColor.g,db.npcsIRColor.b)
    npcsIMRColorHex = RGBPercToHex(db.npcsIMRColor.r,db.npcsIMRColor.g,db.npcsIMRColor.b)

    previousDimensionsX = 10000
    previousDimensionsY = 10000
end



-- Create the settings in the control panel
local function CreateSettings()
	local panel = LAM:CreateControlPanel("RANGE_RETICLE_SETTINGS", "Range Reticle")

	LAM:AddHeader(panel, "Range_Reticle_Settings_Hostile_Header", "Hostile")
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
				function() return db.hostileNameEnabled end,	--getFunc
				function()							--setFunc
					db.hostileNameEnabled = not db.hostileNameEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
				function() return db.hostileLevelEnabled end,	--getFunc
				function()							--setFunc
					db.hostileLevelEnabled = not db.hostileLevelEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
				function() return db.hostileRangeEnabled end,	--getFunc
				function()							--setFunc
					db.hostileRangeEnabled = not db.hostileRangeEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Difficulty_Enabled", "Show Target Difficulty", "If enabled, the target difficulty is shown as *'s above the reticle",
				function() return db.hostileDifficultyEnabled end,	--getFunc
				function()							--setFunc
					db.hostileDifficultyEnabled = not db.hostileDifficultyEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
				function() return db.hostileReticleColoringEnabled end,	--getFunc
				function()							--setFunc
					db.hostileReticleColoringEnabled = not db.hostileReticleColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
				function() return db.hostileRangeColoringEnabled end,	--getFunc
				function()							--setFunc
					db.hostileRangeColoringEnabled = not db.hostileRangeColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
				function() return db.hostileNameLevelColoringEnabled end,	--getFunc
				function()							--setFunc
					db.hostileNameLevelColoringEnabled = not db.hostileNameLevelColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
				function() return db.hostileOutOfRangeEnabled end,	--getFunc
				function()							--setFunc
					db.hostileOutOfRangeEnabled = not db.hostileOutOfRangeEnabled
				end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
				function() return db.hostileOORColor.r, db.hostileOORColor.g, db.hostileOORColor.b end,
				function(r,g,b,a)
					db.hostileOORColor.r = r
					db.hostileOORColor.g = g
					db.hostileOORColor.b = b
					hostileOORColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
				function() return db.hostileInRangeEnabled end,	--getFunc
				function()							--setFunc
					db.hostileInRangeEnabled = not db.hostileInRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Hostile_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
					function() return db.hostileInRangeDistance end,
					function(value)
						db.hostileInRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_IR_Color", "In Range Color", "The reticle color when the target is in range",
				function() return db.hostileIRColor.r, db.hostileIRColor.g, db.hostileIRColor.b end,
				function(r,g,b,a)
					db.hostileIRColor.r = r
					db.hostileIRColor.g = g
					db.hostileIRColor.b = b
					hostileIRColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Hostile_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
				function() return db.hostileInMeleeRangeEnabled end,	--getFunc
				function()							--setFunc
					db.hostileInMeleeRangeEnabled = not db.hostileInMeleeRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Hostile_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
					function() return db.hostileInMeleeRangeDistance end,
					function(value)
						db.hostileInMeleeRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Hostile_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
				function() return db.hostileIMRColor.r, db.hostileIMRColor.g, db.hostileIMRColor.b end,
				function(r,g,b,a)
					db.hostileIMRColor.r = r
					db.hostileIMRColor.g = g
					db.hostileIMRColor.b = b
					hostileIMRColorHex = RGBPercToHex(r,g,b)
				end)

	LAM:AddHeader(panel, "Range_Reticle_Settings_Allies_Header", "Allies")
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
				function() return db.alliesNameEnabled end,	--getFunc
				function()							--setFunc
					db.alliesNameEnabled = not db.alliesNameEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
				function() return db.alliesLevelEnabled end,	--getFunc
				function()							--setFunc
					db.alliesLevelEnabled = not db.alliesLevelEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
				function() return db.alliesRangeEnabled end,	--getFunc
				function()							--setFunc
					db.alliesRangeEnabled = not db.alliesRangeEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
				function() return db.alliesReticleColoringEnabled end,	--getFunc
				function()							--setFunc
					db.alliesReticleColoringEnabled = not db.alliesReticleColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
				function() return db.alliesRangeColoringEnabled end,	--getFunc
				function()							--setFunc
					db.alliesRangeColoringEnabled = not db.alliesRangeColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
				function() return db.alliesNameLevelColoringEnabled end,	--getFunc
				function()							--setFunc
					db.alliesNameLevelColoringEnabled = not db.alliesNameLevelColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
				function() return db.alliesOutOfRangeEnabled end,	--getFunc
				function()							--setFunc
					db.alliesOutOfRangeEnabled = not db.alliesOutOfRangeEnabled
				end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
				function() return db.alliesOORColor.r, db.alliesOORColor.g, db.alliesOORColor.b end,
				function(r,g,b,a)
					db.alliesOORColor.r = r
					db.alliesOORColor.g = g
					db.alliesOORColor.b = b
					alliesOORColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
				function() return db.alliesInRangeEnabled end,	--getFunc
				function()							--setFunc
					db.alliesInRangeEnabled = not db.alliesInRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Allies_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
					function() return db.alliesInRangeDistance end,
					function(value)
						db.alliesInRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_IR_Color", "In Range Color", "The reticle color when the target is in range",
				function() return db.alliesIRColor.r, db.alliesIRColor.g, db.alliesIRColor.b end,
				function(r,g,b,a)
					db.alliesIRColor.r = r
					db.alliesIRColor.g = g
					db.alliesIRColor.b = b
					alliesIRColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Allies_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
				function() return db.alliesInMeleeRangeEnabled end,	--getFunc
				function()							--setFunc
					db.alliesInMeleeRangeEnabled = not db.alliesInMeleeRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Allies_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
					function() return db.alliesInMeleeRangeDistance end,
					function(value)
						db.alliesInMeleeRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Allies_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
				function() return db.alliesIMRColor.r, db.alliesIMRColor.g, db.alliesIMRColor.b end,
				function(r,g,b,a)
					db.alliesIMRColor.r = r
					db.alliesIMRColor.g = g
					db.alliesIMRColor.b = b
					alliesIMRColorHex = RGBPercToHex(r,g,b)
				end)

	LAM:AddHeader(panel, "Range_Reticle_Settings_Neutral_Header", "Neutral")
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
				function() return db.neutralNameEnabled end,	--getFunc
				function()							--setFunc
					db.neutralNameEnabled = not db.neutralNameEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
				function() return db.neutralLevelEnabled end,	--getFunc
				function()							--setFunc
					db.neutralLevelEnabled = not db.neutralLevelEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
				function() return db.neutralRangeEnabled end,	--getFunc
				function()							--setFunc
					db.neutralRangeEnabled = not db.neutralRangeEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Difficulty_Enabled", "Show Target Difficulty", "If enabled, the target difficulty is shown as *'s above the reticle",
				function() return db.neutralDifficultyEnabled end,	--getFunc
				function()							--setFunc
					db.neutralDifficultyEnabled = not db.neutralDifficultyEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
				function() return db.neutralReticleColoringEnabled end,	--getFunc
				function()							--setFunc
					db.neutralReticleColoringEnabled = not db.neutralReticleColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
				function() return db.neutralRangeColoringEnabled end,	--getFunc
				function()							--setFunc
					db.neutralRangeColoringEnabled = not db.neutralRangeColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
				function() return db.neutralNameLevelColoringEnabled end,	--getFunc
				function()							--setFunc
					db.neutralNameLevelColoringEnabled = not db.neutralNameLevelColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
				function() return db.neutralOutOfRangeEnabled end,	--getFunc
				function()							--setFunc
					db.neutralOutOfRangeEnabled = not db.neutralOutOfRangeEnabled
				end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
				function() return db.neutralOORColor.r, db.neutralOORColor.g, db.neutralOORColor.b end,
				function(r,g,b,a)
					db.neutralOORColor.r = r
					db.neutralOORColor.g = g
					db.neutralOORColor.b = b
					neutralOORColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
				function() return db.neutralInRangeEnabled end,	--getFunc
				function()							--setFunc
					db.neutralInRangeEnabled = not db.neutralInRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Neutral_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
					function() return db.neutralInRangeDistance end,
					function(value)
						db.neutralInRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_IR_Color", "In Range Color", "The reticle color when the target is in range",
				function() return db.neutralIRColor.r, db.neutralIRColor.g, db.neutralIRColor.b end,
				function(r,g,b,a)
					db.neutralIRColor.r = r
					db.neutralIRColor.g = g
					db.neutralIRColor.b = b
					neutralIRColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_Neutral_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
				function() return db.neutralInMeleeRangeEnabled end,	--getFunc
				function()							--setFunc
					db.neutralInMeleeRangeEnabled = not db.neutralInMeleeRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_Neutral_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
					function() return db.neutralInMeleeRangeDistance end,
					function(value)
						db.neutralInMeleeRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_Neutral_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
				function() return db.neutralIMRColor.r, db.neutralIMRColor.g, db.neutralIMRColor.b end,
				function(r,g,b,a)
					db.neutralIMRColor.r = r
					db.neutralIMRColor.g = g
					db.neutralIMRColor.b = b
					neutralIMRColorHex = RGBPercToHex(r,g,b)
				end)

	LAM:AddHeader(panel, "Range_Reticle_Settings_NPCs_Header", "NPCs")
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Name_Enabled", "Show Name", "If enabled, the target name is shown above the reticle",
				function() return db.npcsNameEnabled end,	--getFunc
				function()							--setFunc
					db.npcsNameEnabled = not db.npcsNameEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Level_Enabled", "Show Level", "If enabled, the target level is shown above the reticle",
				function() return db.npcsLevelEnabled end,	--getFunc
				function()							--setFunc
					db.npcsLevelEnabled = not db.npcsLevelEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Range_Enabled", "Show Range", "If enabled, the target range is shown at the top-right of the reticle",
				function() return db.npcsRangeEnabled end,	--getFunc
				function()							--setFunc
					db.npcsRangeEnabled = not db.npcsRangeEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Reticle_Coloring_Enabled", "Colorize Reticle", "If enabled, the color of the target reticle is colorized to reflect range status",
				function() return db.npcsReticleColoringEnabled end,	--getFunc
				function()							--setFunc
					db.npcsReticleColoringEnabled = not db.npcsReticleColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_Range_Coloring_Enabled", "Colorize Range", "If enabled, the color of the target range is colorized to reflect range status",
				function() return db.npcsRangeColoringEnabled end,	--getFunc
				function()							--setFunc
					db.npcsRangeColoringEnabled = not db.npcsRangeColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_NameLevel_Coloring_Enabled", "Colorize Name and Level", "If enabled, the color of the name and level is colorized to reflect range status",
				function() return db.npcsNameLevelColoringEnabled end,	--getFunc
				function()							--setFunc
					db.npcsNameLevelColoringEnabled = not db.npcsNameLevelColoringEnabled
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_OOR_Enabled", "Out Of Range", "If enabled, the reticle color will change when the target is out of range",
				function() return db.npcsOutOfRangeEnabled end,	--getFunc
				function()							--setFunc
					db.npcsOutOfRangeEnabled = not db.npcsOutOfRangeEnabled
				end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_OOR_Color", "Out Of Range Color", "The reticle color when the target is out of range",
				function() return db.npcsOORColor.r, db.npcsOORColor.g, db.npcsOORColor.b end,
				function(r,g,b,a)
					db.npcsOORColor.r = r
					db.npcsOORColor.g = g
					db.npcsOORColor.b = b
					npcsOORColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_IR_Enabled", "In Range", "If enabled, the reticle color will change when the target is in range",
				function() return db.npcsInRangeEnabled end,	--getFunc
				function()							--setFunc
					db.npcsInRangeEnabled = not db.npcsInRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_NPCs_IR_Distance", "In Range Distance", "Set the distance that determines when a target is in range", 0, 60, 1,
					function() return db.npcsInRangeDistance end,
					function(value)
						db.npcsInRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_IR_Color", "In Range Color", "The reticle color when the target is in range",
				function() return db.npcsIRColor.r, db.npcsIRColor.g, db.npcsIRColor.b end,
				function(r,g,b,a)
					db.npcsIRColor.r = r
					db.npcsIRColor.g = g
					db.npcsIRColor.b = b
					npcsIRColorHex = RGBPercToHex(r,g,b)
				end)
	LAM:AddCheckbox(panel, "Range_Reticle_Settings_NPCs_IMR_Enabled", "In Melee Range", "If enabled, the reticle color will change when the target is in melee range",
				function() return db.npcsInMeleeRangeEnabled end,	--getFunc
				function()							--setFunc
					db.npcsInMeleeRangeEnabled = not db.npcsInMeleeRangeEnabled
				end)
	LAM:AddSlider(panel, "Range_Reticle_Settings_NPCs_IMR_Distance", "In Melee Range Distance", "Set the distance that determines when a target is in melee range", 0, 60, 1,
					function() return db.npcsInMeleeRangeDistance end,
					function(value)
						db.npcsInMeleeRangeDistance = value
					end)
	LAM:AddColorPicker(panel, "Range_Reticle_Settings_NPCs_IMR_Color", "In Melee Range Color", "The reticle color when the target is in melee range",
				function() return db.npcsIMRColor.r, db.npcsIMRColor.g, db.npcsIMRColor.b end,
				function(r,g,b,a)
					db.npcsIMRColor.r = r
					db.npcsIMRColor.g = g
					db.npcsIMRColor.b = b
					npcsIMRColorHex = RGBPercToHex(r,g,b)
				end)
end

function GetColor(imrColor, irColor, oorColor, inMeleeRangeEnabled, inRangeEnabled, outOfRangeEnabled, targetInMeleeRange, targetInRange)
    local colorRed = 1
    local colorGreen = 1
    local colorBlue = 1
    -- Check colorize settings
    if inMeleeRangeEnabled and targetInMeleeRange then
        colorRed = imrColor.r
        colorGreen = imrColor.g
        colorBlue = imrColor.b
    elseif inRangeEnabled and targetInRange then
        colorRed = irColor.r
        colorGreen = irColor.g
        colorBlue = irColor.b
    elseif outOfRangeEnabled then
        colorRed = oorColor.r
        colorGreen = oorColor.g
        colorBlue = oorColor.b
    end
    return colorRed, colorGreen, colorBlue
end

function OnRangeUpdate()
    -- Determine if reticle is hidden
    local reticleHidden = IsReticleHidden()
    if reticleHidden then
        return
    end

    -- Get target name and reaction
	local targetReaction = GetUnitReaction('reticleover')
	local targetName = GetUnitName('reticleover')

    -- Local variables to store what needs to be done
    local nameEnabled = false
    local levelEnabled = false
    local rangeEnabled = false
	local difficultyEnabled = false
    local reticleColoringEnabled = false
    local rangeColoringEnabled = false
    local nameLevelColoringEnabled = false
    local outOfRangeEnabled = false
    local inRangeEnabled = false
    local inMeleeRangeEnabled = false

    -- Shared information
    local distance = -999
    local oorColor
    local inRangeDistance
    local irColor
    local inMeleeRangeDistance
    local imrColor
    local targetInMeleeRange = false
    local targetInRange = false

    -- Determine target type and if we need to do anything
    if targetReaction and targetName and string.len(targetName) > 0 then
		if targetReaction == UNIT_REACTION_HOSTILE then
            nameEnabled = db.hostileNameEnabled
            levelEnabled = db.hostileLevelEnabled
            rangeEnabled = db.hostileRangeEnabled
			difficultyEnabled = db.hostileDifficultyEnabled
            reticleColoringEnabled = db.hostileReticleColoringEnabled
            rangeColoringEnabled = db.hostileRangeColoringEnabled
            nameLevelColoringEnabled = db.hostileNameLevelColoringEnabled
            outOfRangeEnabled = db.hostileOutOfRangeEnabled
            inRangeEnabled = db.hostileInRangeEnabled
            inMeleeRangeEnabled = db.hostileInMeleeRangeEnabled
            oorColor = db.hostileOORColor
            inRangeDistance = db.hostileInRangeDistance
            irColor = db.hostileIRColor
            inMeleeRangeDistance = db.hostileInMeleeRangeDistance
            imrColor = db.hostileIMRColor
        elseif targetReaction == UNIT_REACTION_PLAYER_ALLY then
            nameEnabled = db.alliesNameEnabled
            levelEnabled = db.alliesLevelEnabled
            rangeEnabled = db.alliesRangeEnabled
            reticleColoringEnabled = db.alliesReticleColoringEnabled
            rangeColoringEnabled = db.alliesRangeColoringEnabled
            nameLevelColoringEnabled = db.alliesNameLevelColoringEnabled
            outOfRangeEnabled = db.alliesOutOfRangeEnabled
            inRangeEnabled = db.alliesInRangeEnabled
            inMeleeRangeEnabled = db.alliesInMeleeRangeEnabled
            oorColor = db.alliesOORColor
            inRangeDistance = db.alliesInRangeDistance
            irColor = db.alliesIRColor
            inMeleeRangeDistance = db.alliesInMeleeRangeDistance
            imrColor = db.alliesIMRColor
        elseif targetReaction == UNIT_REACTION_NEUTRAL then
            nameEnabled = db.neutralNameEnabled
            levelEnabled = db.neutralLevelEnabled
            rangeEnabled = db.neutralRangeEnabled
			difficultyEnabled = db.neutralDifficultyEnabled
            reticleColoringEnabled = db.neutralReticleColoringEnabled
            rangeColoringEnabled = db.neutralRangeColoringEnabled
            nameLevelColoringEnabled = db.neutralNameLevelColoringEnabled
            outOfRangeEnabled = db.neutralOutOfRangeEnabled
            inRangeEnabled = db.neutralInRangeEnabled
            inMeleeRangeEnabled = db.neutralInMeleeRangeEnabled
            oorColor = db.neutralOORColor
            inRangeDistance = db.neutralInRangeDistance
            irColor = db.neutralIRColor
            inMeleeRangeDistance = db.neutralInMeleeRangeDistance
            imrColor = db.neutralIMRColor
        elseif targetReaction == UNIT_REACTION_NPC_ALLY or UNIT_REACTION_FRIENDLY then
            nameEnabled = db.npcsNameEnabled
            levelEnabled = db.npcsLevelEnabled
            rangeEnabled = db.npcsRangeEnabled
            reticleColoringEnabled = db.npcsReticleColoringEnabled
            rangeColoringEnabled = db.npcsRangeColoringEnabled
            nameLevelColoringEnabled = db.npcsNameLevelColoringEnabled
            outOfRangeEnabled = db.npcsOutOfRangeEnabled
            inRangeEnabled = db.npcsInRangeEnabled
            inMeleeRangeEnabled = db.npcsInMeleeRangeEnabled
            oorColor = db.npcsOORColor
            inRangeDistance = db.npcsInRangeDistance
            irColor = db.npcsIRColor
            inMeleeRangeDistance = db.npcsInMeleeRangeDistance
            imrColor = db.npcsIMRColor
        end
    end

    RangeReticleRange:SetText('')
    if rangeEnabled or nameLevelColoringEnabled or reticleColoringEnabled then
        -- Get details of what's under the reticle
        local targetX, targetY, targetH = GetMapPlayerPosition('reticleover')

        -- Get details of the player
        local selfX, selfY, selfH = GetMapPlayerPosition('player')

        -- Get map details
        local mapWidth, mapHeight = GetMapNumTiles()
        local mapType = GetMapType()
        local mapContentType = GetMapContentType()

        --MAPTYPE_NONE: 0
        --MAPTYPE_SUBZONE: 1
        --MAPTYPE_ZONE: 2
        --MAPTYPE_WORLD: 3
        --MAPTYPE_ALLIANCE: 4
        --MAPTYPE_COSMIC: 5

        --MAP_CONTENT_NONE: 0
        --MAP_CONTENT_AVA: 1
        --MAP_CONTENT_DUNGEON: 2

        -- Calculate and display target range
        if targetX and targetY then
            -- For debugging map types
            --[[if true then
            	CHAT_SYSTEM:AddMessage("Width: " .. tostring(mapWidth))
            	CHAT_SYSTEM:AddMessage("Height: " .. tostring(mapHeight))
            	CHAT_SYSTEM:AddMessage("Type: " .. tostring(mapType))
            	CHAT_SYSTEM:AddMessage("Content: " .. tostring(mapContentType))
            	local dimensionsX, dimensionsY = ZO_WorldMapContainer:GetDimensions()
            	CHAT_SYSTEM:AddMessage("WMDimensions: " .. tostring(dimensionsX) .. ', ' .. tostring(dimensionsY))
            	local dimensionsX1, dimensionsY1 = ZO_WorldMapContainer1:GetDimensions()
            	CHAT_SYSTEM:AddMessage("1Dimensions: " .. tostring(dimensionsX1) .. ', ' .. tostring(dimensionsY1))
            	local dimensionsX2, dimensionsY2 = ZO_WorldMapContainer2:GetDimensions()
            	CHAT_SYSTEM:AddMessage("2Dimensions: " .. tostring(dimensionsX2) .. ', ' .. tostring(dimensionsY2))
            	local dimensionsX3, dimensionsY3 = ZO_WorldMapContainer3:GetDimensions()
            	CHAT_SYSTEM:AddMessage("3Dimensions: " .. tostring(dimensionsX3) .. ', ' .. tostring(dimensionsY3))
            	local dimensionsX4, dimensionsY4 = ZO_WorldMapContainer4:GetDimensions()
            	CHAT_SYSTEM:AddMessage("4Dimensions: " .. tostring(dimensionsX4) .. ', ' .. tostring(dimensionsY4))

            	CHAT_SYSTEM:AddMessage("Self: " .. tostring(selfX) .. ', ' .. tostring(selfY))
            	CHAT_SYSTEM:AddMessage("Target: " .. tostring(targetX) .. ', ' .. tostring(targetY))

            	--local mdata = getmetatable(ZO_WorldMapContainer1)
            	--local mdata = getmetatable(ZO_WorldMapContainer)
            	--tprint(mdata)
            	CHAT_SYSTEM:AddMessage("H: " .. tostring(ZO_WorldMapContainer:GetHeight()))  --405
            	CHAT_SYSTEM:AddMessage("W: " .. tostring(ZO_WorldMapContainer:GetWidth()))	--405

				CHAT_SYSTEM:AddMessage("ZIndex: " .. tostring(GetCurrentMapZoneIndex()))
            end]]

        	local dimensionsX, dimensionsY = ZO_WorldMapContainer:GetDimensions()
        	local multiplier = 5.0

            if mapContentType == MAP_CONTENT_NONE then
                if mapType == MAPTYPE_SUBZONE then
                elseif mapType == MAPTYPE_ZONE then
                end
            elseif mapContentType == MAP_CONTENT_AVA then
                if mapType == MAPTYPE_SUBZONE then
                elseif mapType == MAPTYPE_ZONE then
                	multiplier = 12.0
                end
            elseif mapContentType == MAP_CONTENT_DUNGEON then
                if mapType == MAPTYPE_SUBZONE then
                	dimensionsX, dimensionsY = ZO_WorldMapContainer1:GetDimensions()
                	multiplier = 1.0
                elseif mapType == MAPTYPE_ZONE then
                end
            end

        	if dimensionsX <= 2000 then
        		previousDimensionsX = dimensionsX
        	elseif previousDimensionsX <= 2000 then
        		dimensionsX = previousDimensionsX
        	end
        	if dimensionsY <= 2000 then
        		previousDimensionsY = dimensionsY
        	elseif previousDimensionsY <= 2000 then
        		dimensionsY = previousDimensionsY
        	end

        	if dimensionsX > 2000 or dimensionsY > 2000 then
	       		local X, Y = ZO_WorldMapContainer:GetDimensions()
        		local X1, Y1 = ZO_WorldMapContainer1:GetDimensions()
        		dimensionsX = math.min(X, X1)
        		dimensionsY = math.min(Y, Y1)
        	end

   			local actualSelfX = selfX * dimensionsX
			local actualSelfY = selfY * dimensionsY
			local actualTargetX = targetX * dimensionsX
			local actualTargetY = targetY * dimensionsY
			local dist = math.sqrt(math.pow((actualSelfX - actualTargetX), 2) + math.pow((actualSelfY - actualTargetY), 2)) * multiplier
			distance = math.floor(dist + 0.5)

			-- Disable range functionality when a zone isn't working with range calculation
			if distance > 100 then
				distance = -999
			end

            if distance <= inRangeDistance then
                targetInRange = true
            end
            if distance <= inMeleeRangeDistance then
                targetInMeleeRange = true
            end
            if rangeEnabled and distance >= 0 then
                RangeReticleRange:SetText(tostring(distance) .. 'm')
            elseif rangeEnabled then
            	RangeReticleRange:SetText('e')
            	--CHAT_SYSTEM:AddMessage("Dimensions: " .. tostring(dimensionsX) .. ', ' .. tostring(dimensionsY))
            	--CHAT_SYSTEM:AddMessage("Multiplier: " .. tostring(multiplier))
            end
        end
    end

    -- Display the name and level/rank
    RangeReticleName:SetText('')
    if nameEnabled or levelEnabled or difficultyEnabled then
        -- Get target name and level/rank
        local nameString = ''
        local levelString = ''
		local difficultyString = ''
        if levelEnabled then
            local targetLevel = GetUnitLevel('reticleover')
            local targetVRank = GetUnitVeteranRank('reticleover')
            if targetVRank and string.len(targetVRank) > 0 and targetVRank ~= 0 then
                levelString = ' (v' .. tostring(targetVRank) .. ')'
            elseif targetLevel and string.len(targetLevel) > 0 then
                levelString = ' (' .. tostring(targetLevel) .. ')'
            end
        end
        if nameEnabled then
            nameString = targetName
        end
		if difficultyEnabled then
			local targetDifficulty = GetUnitDifficulty('reticleover')
			if targetDifficulty > 1 then
				difficultyString = " " .. string.rep("*", (targetDifficulty - 1))
			end
		end
        RangeReticleName:SetText(nameString .. levelString .. difficultyString)
    end

    -- Colorize the various items
    if distance >= 0 then
        local colorRed = 1
        local colorGreen = 1
        local colorBlue = 1
        if nameLevelColoringEnabled then
            colorRed, colorGreen, colorBlue = GetColor(imrColor, irColor, oorColor, inMeleeRangeEnabled, inRangeEnabled, outOfRangeEnabled, targetInMeleeRange, targetInRange)
        end
	    RangeReticleName:SetColor(colorRed, colorGreen, colorBlue)

        colorRed = 1
        colorGreen = 1
        colorBlue = 1
        if reticleColoringEnabled then
            colorRed, colorGreen, colorBlue = GetColor(imrColor, irColor, oorColor, inMeleeRangeEnabled, inRangeEnabled, outOfRangeEnabled, targetInMeleeRange, targetInRange)
        end
        -- Set reticle color
        ZO_ReticleContainerReticle:SetColor(colorRed, colorGreen, colorBlue)
        ZO_ReticleContainerStealthEye:SetColor(colorRed, colorGreen, colorBlue)
        ZO_ReticleContainerStealthText:SetColor(colorRed, colorGreen, colorBlue)

        colorRed = 1
        colorGreen = 1
        colorBlue = 1
        if rangeColoringEnabled then
            colorRed, colorGreen, colorBlue = GetColor(imrColor, irColor, oorColor, inMeleeRangeEnabled, inRangeEnabled, outOfRangeEnabled, targetInMeleeRange, targetInRange)
        end
        RangeReticleRange:SetColor(colorRed, colorGreen, colorBlue)
    else
        -- Set everything to white when distance not available
	    RangeReticleName:SetColor(1, 1, 1)
        RangeReticleRange:SetColor(1, 1, 1)
        ZO_ReticleContainerReticle:SetColor(1, 1, 1)
        ZO_ReticleContainerStealthEye:SetColor(1, 1, 1)
        ZO_ReticleContainerStealthText:SetColor(1, 1, 1)
    end
end

-- Reticle hidden update
local function OnReticleHiddenUpdate(event)
    local reticleHidden = IsReticleHidden()
    RangeReticleRange:SetHidden(reticleHidden)
	RangeReticleName:SetHidden(reticleHidden)
end

-- Register event callbacks
EVENT_MANAGER:RegisterForEvent("RangeReticleHidden", EVENT_RETICLE_HIDDEN_UPDATE, OnReticleHiddenUpdate)
EVENT_MANAGER:RegisterForEvent("RangeReticleLoaded", EVENT_ADD_ON_LOADED, function(event, addon)
		if addon == "RangeReticle" then
			AddonSetup()
			CreateSettings()
		end
	end)