-- Load the addon menu library
local LAM = LibStub("LibAddonMenu-2.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

	SLASH_COMMANDS["/rret"] = CommandHandler
end

-- Create the settings in the control panel
local function CreateSettings()
    local panelData = {
        type = "panel",
        name = "RangeReticle",
        displayName = "RangeReticle",
        author = "Adein",
        version = "0.6",
        slashCommand = "/rret",	--(optional) will register a keybind to open to this panel
        registerForRefresh = true,	--boolean (optional) (will refresh all options controls when a setting is changed and when the panel is shown)
        registerForDefaults = true,	--boolean (optional) (will set all options controls back to default values)
    }

    local optionsTable = {
        [1] = {
            type = "header",
            name = "Range Reticle Settings",
            width = "full",	--or "half" (optional)
        },
        [2] = {
            type = "submenu",
            name = "Hostile Targets",
            tooltip = "Settings for hostile targets",	--(optional)
            controls = {
                [1] = {
                    type = "checkbox",
                    name = "Show Name",
                    tooltip = "If enabled, the target name is shown above the reticle",
                    getFunc = function() return db.hostileNameEnabled end,
                    setFunc = function() db.hostileNameEnabled = not db.hostileNameEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [2] = {
                    type = "checkbox",
                    name = "Show Level",
                    tooltip = "If enabled, the target level is shown above the reticle",
                    getFunc = function() return db.hostileLevelEnabled end,
                    setFunc = function() db.hostileLevelEnabled = not db.hostileLevelEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [3] = {
                    type = "checkbox",
                    name = "Show Range",
                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
                    getFunc = function() return db.hostileRangeEnabled end,
                    setFunc = function() db.hostileRangeEnabled = not db.hostileRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [4] = {
                    type = "checkbox",
                    name = "Show Target Difficulty",
                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
                    getFunc = function() return db.hostileDifficultyEnabled end,
                    setFunc = function() db.hostileDifficultyEnabled = not db.hostileDifficultyEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [5] = {
                    type = "checkbox",
                    name = "Colorize Reticle",
                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
                    getFunc = function() return db.hostileReticleColoringEnabled end,
                    setFunc = function() db.hostileReticleColoringEnabled = not db.hostileReticleColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [6] = {
                    type = "checkbox",
                    name = "Colorize Range",
                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
                    getFunc = function() return db.hostileRangeColoringEnabled end,
                    setFunc = function() db.hostileRangeColoringEnabled = not db.hostileRangeColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [7] = {
                    type = "checkbox",
                    name = "Colorize Name and Level",
                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
                    getFunc = function() return db.hostileNameLevelColoringEnabled end,
                    setFunc = function() db.hostileNameLevelColoringEnabled = not db.hostileNameLevelColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [8] = {
                    type = "checkbox",
                    name = "Out Of Range",
                    tooltip = "If enabled, the reticle color will change when the target is out of range",
                    getFunc = function() return db.hostileOutOfRangeEnabled end,
                    setFunc = function() db.hostileOutOfRangeEnabled = not db.hostileOutOfRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [9] = {
                    type = "colorpicker",
                    name = "Out Of Range Color",
                    tooltip = "The reticle color when the target is out of range",
                    getFunc = function() return db.hostileOORColor.r, db.hostileOORColor.g, db.hostileOORColor.b end,
                    setFunc = function(r,g,b,a)
                        db.hostileOORColor.r = r
                        db.hostileOORColor.g = g
                        db.hostileOORColor.b = b
                        hostileOORColorHex = RGBPercToHex(r,g,b)
				        end,
                    width = "half",	--or "half" (optional)
                },
                [10] = {
                    type = "checkbox",
                    name = "In Range",
                    tooltip = "If enabled, the reticle color will change when the target is in range",
                    getFunc = function() return db.hostileInRangeEnabled end,
                    setFunc = function() db.hostileInRangeEnabled = not db.hostileInRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [11] = {
                    type = "slider",
                    name = "In Range Distance",
                    tooltip = "Set the distance that determines when a target is in range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.hostileInRangeDistance end,
                    setFunc = function(value) db.hostileInRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [12] = {
                    type = "colorpicker",
                    name = "In Range Color",
                    tooltip = "The reticle color when the target is in range",
                    getFunc = function() return db.hostileIRColor.r, db.hostileIRColor.g, db.hostileIRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.hostileIRColor.r = r
                        db.hostileIRColor.g = g
                        db.hostileIRColor.b = b
                        hostileIRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
                [13] = {
                    type = "checkbox",
                    name = "In Melee Range",
                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
                    getFunc = function() return db.hostileInMeleeRangeEnabled end,
                    setFunc = function() db.hostileInMeleeRangeEnabled = not db.hostileInMeleeRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [14] = {
                    type = "slider",
                    name = "In Melee Range Distance",
                    tooltip = "Set the distance that determines when a target is in melee range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.hostileInMeleeRangeDistance end,
                    setFunc = function(value) db.hostileInMeleeRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [15] = {
                    type = "colorpicker",
                    name = "In Melee Range Color",
                    tooltip = "The reticle color when the target is in melee range",
                    getFunc = function() return db.hostileIMRColor.r, db.hostileIMRColor.g, db.hostileIMRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.hostileIMRColor.r = r
                        db.hostileIMRColor.g = g
                        db.hostileIMRColor.b = b
                        hostileIMRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
            },
        },
        [3] = {
            type = "submenu",
            name = "Allies",
            tooltip = "Settings for allies",	--(optional)
            controls = {
                [1] = {
                    type = "checkbox",
                    name = "Show Name",
                    tooltip = "If enabled, the target name is shown above the reticle",
                    getFunc = function() return db.alliesNameEnabled end,
                    setFunc = function() db.alliesNameEnabled = not db.alliesNameEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [2] = {
                    type = "checkbox",
                    name = "Show Level",
                    tooltip = "If enabled, the target level is shown above the reticle",
                    getFunc = function() return db.alliesLevelEnabled end,
                    setFunc = function() db.alliesLevelEnabled = not db.alliesLevelEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [3] = {
                    type = "checkbox",
                    name = "Show Range",
                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
                    getFunc = function() return db.alliesRangeEnabled end,
                    setFunc = function() db.alliesRangeEnabled = not db.alliesRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [4] = {
                    type = "checkbox",
                    name = "Show Target Difficulty",
                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
                    getFunc = function() return db.alliesDifficultyEnabled end,
                    setFunc = function() db.alliesDifficultyEnabled = not db.alliesDifficultyEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [5] = {
                    type = "checkbox",
                    name = "Colorize Reticle",
                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
                    getFunc = function() return db.alliesReticleColoringEnabled end,
                    setFunc = function() db.alliesReticleColoringEnabled = not db.alliesReticleColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [6] = {
                    type = "checkbox",
                    name = "Colorize Range",
                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
                    getFunc = function() return db.alliesRangeColoringEnabled end,
                    setFunc = function() db.alliesRangeColoringEnabled = not db.alliesRangeColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [7] = {
                    type = "checkbox",
                    name = "Colorize Name and Level",
                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
                    getFunc = function() return db.alliesNameLevelColoringEnabled end,
                    setFunc = function() db.alliesNameLevelColoringEnabled = not db.alliesNameLevelColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [8] = {
                    type = "checkbox",
                    name = "Out Of Range",
                    tooltip = "If enabled, the reticle color will change when the target is out of range",
                    getFunc = function() return db.alliesOutOfRangeEnabled end,
                    setFunc = function() db.alliesOutOfRangeEnabled = not db.alliesOutOfRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [9] = {
                    type = "colorpicker",
                    name = "Out Of Range Color",
                    tooltip = "The reticle color when the target is out of range",
                    getFunc = function() return db.alliesOORColor.r, db.alliesOORColor.g, db.alliesOORColor.b end,
                    setFunc = function(r,g,b,a)
                        db.alliesOORColor.r = r
                        db.alliesOORColor.g = g
                        db.alliesOORColor.b = b
                        alliesOORColorHex = RGBPercToHex(r,g,b)
				        end,
                    width = "half",	--or "half" (optional)
                },
                [10] = {
                    type = "checkbox",
                    name = "In Range",
                    tooltip = "If enabled, the reticle color will change when the target is in range",
                    getFunc = function() return db.alliesInRangeEnabled end,
                    setFunc = function() db.alliesInRangeEnabled = not db.alliesInRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [11] = {
                    type = "slider",
                    name = "In Range Distance",
                    tooltip = "Set the distance that determines when a target is in range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.alliesInRangeDistance end,
                    setFunc = function(value) db.alliesInRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [12] = {
                    type = "colorpicker",
                    name = "In Range Color",
                    tooltip = "The reticle color when the target is in range",
                    getFunc = function() return db.alliesIRColor.r, db.alliesIRColor.g, db.alliesIRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.alliesIRColor.r = r
                        db.alliesIRColor.g = g
                        db.alliesIRColor.b = b
                        alliesIRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
                [13] = {
                    type = "checkbox",
                    name = "In Melee Range",
                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
                    getFunc = function() return db.alliesInMeleeRangeEnabled end,
                    setFunc = function() db.alliesInMeleeRangeEnabled = not db.alliesInMeleeRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [14] = {
                    type = "slider",
                    name = "In Melee Range Distance",
                    tooltip = "Set the distance that determines when a target is in melee range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.alliesInMeleeRangeDistance end,
                    setFunc = function(value) db.alliesInMeleeRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [15] = {
                    type = "colorpicker",
                    name = "In Melee Range Color",
                    tooltip = "The reticle color when the target is in melee range",
                    getFunc = function() return db.alliesIMRColor.r, db.alliesIMRColor.g, db.alliesIMRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.alliesIMRColor.r = r
                        db.alliesIMRColor.g = g
                        db.alliesIMRColor.b = b
                        alliesIMRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
            },
        },
        [4] = {
            type = "submenu",
            name = "Neutral Targets",
            tooltip = "Settings for neutral targets",	--(optional)
            controls = {
                [1] = {
                    type = "checkbox",
                    name = "Show Name",
                    tooltip = "If enabled, the target name is shown above the reticle",
                    getFunc = function() return db.neutralNameEnabled end,
                    setFunc = function() db.neutralNameEnabled = not db.neutralNameEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [2] = {
                    type = "checkbox",
                    name = "Show Level",
                    tooltip = "If enabled, the target level is shown above the reticle",
                    getFunc = function() return db.neutralLevelEnabled end,
                    setFunc = function() db.neutralLevelEnabled = not db.neutralLevelEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [3] = {
                    type = "checkbox",
                    name = "Show Range",
                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
                    getFunc = function() return db.neutralRangeEnabled end,
                    setFunc = function() db.neutralRangeEnabled = not db.neutralRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [4] = {
                    type = "checkbox",
                    name = "Show Target Difficulty",
                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
                    getFunc = function() return db.neutralDifficultyEnabled end,
                    setFunc = function() db.neutralDifficultyEnabled = not db.neutralDifficultyEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [5] = {
                    type = "checkbox",
                    name = "Colorize Reticle",
                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
                    getFunc = function() return db.neutralReticleColoringEnabled end,
                    setFunc = function() db.neutralReticleColoringEnabled = not db.neutralReticleColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [6] = {
                    type = "checkbox",
                    name = "Colorize Range",
                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
                    getFunc = function() return db.neutralRangeColoringEnabled end,
                    setFunc = function() db.neutralRangeColoringEnabled = not db.neutralRangeColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [7] = {
                    type = "checkbox",
                    name = "Colorize Name and Level",
                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
                    getFunc = function() return db.neutralNameLevelColoringEnabled end,
                    setFunc = function() db.neutralNameLevelColoringEnabled = not db.neutralNameLevelColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [8] = {
                    type = "checkbox",
                    name = "Out Of Range",
                    tooltip = "If enabled, the reticle color will change when the target is out of range",
                    getFunc = function() return db.neutralOutOfRangeEnabled end,
                    setFunc = function() db.neutralOutOfRangeEnabled = not db.neutralOutOfRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [9] = {
                    type = "colorpicker",
                    name = "Out Of Range Color",
                    tooltip = "The reticle color when the target is out of range",
                    getFunc = function() return db.neutralOORColor.r, db.neutralOORColor.g, db.neutralOORColor.b end,
                    setFunc = function(r,g,b,a)
                        db.neutralOORColor.r = r
                        db.neutralOORColor.g = g
                        db.neutralOORColor.b = b
                        neutralOORColorHex = RGBPercToHex(r,g,b)
				        end,
                    width = "half",	--or "half" (optional)
                },
                [10] = {
                    type = "checkbox",
                    name = "In Range",
                    tooltip = "If enabled, the reticle color will change when the target is in range",
                    getFunc = function() return db.neutralInRangeEnabled end,
                    setFunc = function() db.neutralInRangeEnabled = not db.neutralInRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [11] = {
                    type = "slider",
                    name = "In Range Distance",
                    tooltip = "Set the distance that determines when a target is in range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.neutralInRangeDistance end,
                    setFunc = function(value) db.neutralInRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [12] = {
                    type = "colorpicker",
                    name = "In Range Color",
                    tooltip = "The reticle color when the target is in range",
                    getFunc = function() return db.neutralIRColor.r, db.neutralIRColor.g, db.neutralIRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.neutralIRColor.r = r
                        db.neutralIRColor.g = g
                        db.neutralIRColor.b = b
                        neutralIRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
                [13] = {
                    type = "checkbox",
                    name = "In Melee Range",
                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
                    getFunc = function() return db.neutralInMeleeRangeEnabled end,
                    setFunc = function() db.neutralInMeleeRangeEnabled = not db.neutralInMeleeRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [14] = {
                    type = "slider",
                    name = "In Melee Range Distance",
                    tooltip = "Set the distance that determines when a target is in melee range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.neutralInMeleeRangeDistance end,
                    setFunc = function(value) db.neutralInMeleeRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [15] = {
                    type = "colorpicker",
                    name = "In Melee Range Color",
                    tooltip = "The reticle color when the target is in melee range",
                    getFunc = function() return db.neutralIMRColor.r, db.neutralIMRColor.g, db.neutralIMRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.neutralIMRColor.r = r
                        db.neutralIMRColor.g = g
                        db.neutralIMRColor.b = b
                        neutralIMRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
            },
        },
        [5] = {
            type = "submenu",
            name = "NPC Targets",
            tooltip = "Settings for NPC targets",	--(optional)
            controls = {
                [1] = {
                    type = "checkbox",
                    name = "Show Name",
                    tooltip = "If enabled, the target name is shown above the reticle",
                    getFunc = function() return db.npcsNameEnabled end,
                    setFunc = function() db.npcsNameEnabled = not db.npcsNameEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [2] = {
                    type = "checkbox",
                    name = "Show Level",
                    tooltip = "If enabled, the target level is shown above the reticle",
                    getFunc = function() return db.npcsLevelEnabled end,
                    setFunc = function() db.npcsLevelEnabled = not db.npcsLevelEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [3] = {
                    type = "checkbox",
                    name = "Show Range",
                    tooltip = "If enabled, the target range is shown at the top-right of the reticle",
                    getFunc = function() return db.npcsRangeEnabled end,
                    setFunc = function() db.npcsRangeEnabled = not db.npcsRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [4] = {
                    type = "checkbox",
                    name = "Show Target Difficulty",
                    tooltip = "If enabled, the target difficulty is shown as *'s above the reticle",
                    getFunc = function() return db.npcsDifficultyEnabled end,
                    setFunc = function() db.npcsDifficultyEnabled = not db.npcsDifficultyEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [5] = {
                    type = "checkbox",
                    name = "Colorize Reticle",
                    tooltip = "If enabled, the color of the target reticle is colorized to reflect range status",
                    getFunc = function() return db.npcsReticleColoringEnabled end,
                    setFunc = function() db.npcsReticleColoringEnabled = not db.npcsReticleColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [6] = {
                    type = "checkbox",
                    name = "Colorize Range",
                    tooltip = "If enabled, the color of the target range is colorized to reflect range status",
                    getFunc = function() return db.npcsRangeColoringEnabled end,
                    setFunc = function() db.npcsRangeColoringEnabled = not db.npcsRangeColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [7] = {
                    type = "checkbox",
                    name = "Colorize Name and Level",
                    tooltip = "If enabled, the color of the name and level is colorized to reflect range status",
                    getFunc = function() return db.npcsNameLevelColoringEnabled end,
                    setFunc = function() db.npcsNameLevelColoringEnabled = not db.npcsNameLevelColoringEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [8] = {
                    type = "checkbox",
                    name = "Out Of Range",
                    tooltip = "If enabled, the reticle color will change when the target is out of range",
                    getFunc = function() return db.npcsOutOfRangeEnabled end,
                    setFunc = function() db.npcsOutOfRangeEnabled = not db.npcsOutOfRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [9] = {
                    type = "colorpicker",
                    name = "Out Of Range Color",
                    tooltip = "The reticle color when the target is out of range",
                    getFunc = function() return db.npcsOORColor.r, db.npcsOORColor.g, db.npcsOORColor.b end,
                    setFunc = function(r,g,b,a)
                        db.npcsOORColor.r = r
                        db.npcsOORColor.g = g
                        db.npcsOORColor.b = b
                        npcsOORColorHex = RGBPercToHex(r,g,b)
				        end,
                    width = "half",	--or "half" (optional)
                },
                [10] = {
                    type = "checkbox",
                    name = "In Range",
                    tooltip = "If enabled, the reticle color will change when the target is in range",
                    getFunc = function() return db.npcsInRangeEnabled end,
                    setFunc = function() db.npcsInRangeEnabled = not db.npcsInRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [11] = {
                    type = "slider",
                    name = "In Range Distance",
                    tooltip = "Set the distance that determines when a target is in range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.npcsInRangeDistance end,
                    setFunc = function(value) db.npcsInRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [12] = {
                    type = "colorpicker",
                    name = "In Range Color",
                    tooltip = "The reticle color when the target is in range",
                    getFunc = function() return db.npcsIRColor.r, db.npcsIRColor.g, db.npcsIRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.npcsIRColor.r = r
                        db.npcsIRColor.g = g
                        db.npcsIRColor.b = b
                        npcsIRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
                [13] = {
                    type = "checkbox",
                    name = "In Melee Range",
                    tooltip = "If enabled, the reticle color will change when the target is in melee range",
                    getFunc = function() return db.npcsInMeleeRangeEnabled end,
                    setFunc = function() db.npcsInMeleeRangeEnabled = not db.npcsInMeleeRangeEnabled end,
                    width = "half",	--or "half" (optional)
                },
                [14] = {
                    type = "slider",
                    name = "In Melee Range Distance",
                    tooltip = "Set the distance that determines when a target is in melee range",
                    min = 0,
                    max = 60,
                    step = 1,	--(optional)
                    getFunc = function() return db.npcsInMeleeRangeDistance end,
                    setFunc = function(value) db.npcsInMeleeRangeDistance = value end,
                    width = "half",	--or "half" (optional)
                },
                [15] = {
                    type = "colorpicker",
                    name = "In Melee Range Color",
                    tooltip = "The reticle color when the target is in melee range",
                    getFunc = function() return db.npcsIMRColor.r, db.npcsIMRColor.g, db.npcsIMRColor.b end,
                    setFunc = function(r,g,b,a)
                        db.npcsIMRColor.r = r
                        db.npcsIMRColor.g = g
                        db.npcsIMRColor.b = b
                        npcsIMRColorHex = RGBPercToHex(r,g,b)
                        end,
                    width = "half",	--or "half" (optional)
                },
            },
        },
    }

    LAM:RegisterAddonPanel("RangeReticle", panelData)
    LAM:RegisterOptionControls("RangeReticle", optionsTable)
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 targetClass = GetUnitClass('reticleover') -- TODO
    local targetRank, targetSubRank = GetUnitAvARank('reticleover') -- TODO
    local targetGrouped = IsUnitGrouped('reticleover') -- TODO

    -- 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 mapType = GetMapType()
        local mapContentType = GetMapContentType()

        -- Calculate and display target range
        if targetX and targetY then
        	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

-- Slash command handlers
local function CommandHandler(text)
	-- Display help
	if text == nil or string.len(text) <= 0 or string.lower(text) == "help" then
		ChatMessage("RangeReticle Help:")
		ChatMessage("/rret : display help.")
		ChatMessage("/rret dbg : dump debug information to chat")
    elseif text ~= nil and string.lower(text) == "dbg" then
	end
end

-- Debug info to chat window
local function Debug()
    -- 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 mapIndex = GetCurrentMapIndex()
    local mapZoneIndex = GetCurrentMapZoneIndex()
    local mapWidth, mapHeight = GetMapNumTiles()
    local mapType = GetMapType()
    local mapContentType = GetMapContentType()
    local mapCurrentFloor, mapNumFloors =  GetMapFloorInfo()
    local mapName = GetMapName()

    --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

    CHAT_SYSTEM:AddMessage("Map Index: " .. tostring(mapIndex))
    CHAT_SYSTEM:AddMessage("Map Zone Index: " .. tostring(mapZoneIndex))
    CHAT_SYSTEM:AddMessage("Map W/H: " .. tostring(mapWidth) .. ', ' .. tostring(mapHeight))
    CHAT_SYSTEM:AddMessage("Map Type: " .. tostring(mapType))
    CHAT_SYSTEM:AddMessage("Map Content Type: " .. tostring(mapContentType))
    CHAT_SYSTEM:AddMessage("Floor Cur/Num: " .. tostring(mapCurrentFloor) .. ', ' .. tostring(mapNumFloors))
    CHAT_SYSTEM:AddMessage("Map Name: " .. tostring(mapName))
    CHAT_SYSTEM:AddMessage("Target X/Y/H: " .. tostring(targetX) .. ', ' .. tostring(targetY) .. ', ' .. tostring(targetH))
    CHAT_SYSTEM:AddMessage("Target X/Y/H: " .. tostring(selfX) .. ', ' .. tostring(selfY) .. ', ' .. tostring(selfH))

    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))
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)