Utils = {}

Utils.keyStrMap = {
    SPACE = KEY_SPACE,
    APOSTROPHE = KEY_APOSTROPHE,
    COMMA = KEY_COMMA,
    MINUS = KEY_MINUS,
    PERIOD = KEY_PERIOD,
    SLASH = KEY_SLASH,
    DIGIT_0 = KEY_DIGIT_0,
    DIGIT_1 = KEY_DIGIT_1,
    DIGIT_2 = KEY_DIGIT_2,
    DIGIT_3 = KEY_DIGIT_3,
    DIGIT_4 = KEY_DIGIT_4,
    DIGIT_5 = KEY_DIGIT_5,
    DIGIT_6 = KEY_DIGIT_6,
    DIGIT_7 = KEY_DIGIT_7,
    DIGIT_8 = KEY_DIGIT_8,
    DIGIT_9 = KEY_DIGIT_9,
    SEMICOLON = KEY_SEMICOLON,
    EQUAL = KEY_EQUAL,
    A = KEY_A,
    B = KEY_B,
    C = KEY_C,
    D = KEY_D,
    E = KEY_E,
    F = KEY_F,
    G = KEY_G,
    H = KEY_H,
    I = KEY_I,
    J = KEY_J,
    K = KEY_K,
    L = KEY_L,
    M = KEY_M,
    N = KEY_N,
    O = KEY_O,
    P = KEY_P,
    Q = KEY_Q,
    R = KEY_R,
    S = KEY_S,
    T = KEY_T,
    U = KEY_U,
    V = KEY_V,
    W = KEY_W,
    X = KEY_X,
    Y = KEY_Y,
    Z = KEY_Z,
    LEFT_BRACKET = KEY_LEFT_BRACKET,
    BACKSLASH = KEY_BACKSLASH,
    RIGHT_BRACKET = KEY_RIGHT_BRACKET,
    GRAVE_ACCENT = KEY_GRAVE_ACCENT,
    WORLD_1 = KEY_WORLD_1,
    WORLD_2 = KEY_WORLD_2,
    ESCAPE = KEY_ESCAPE,
    ENTER = KEY_ENTER,
    RETURN = KEY_RETURN,
    TAB = KEY_TAB,
    BACKSPACE = KEY_BACKSPACE,
    INSERT = KEY_INSERT,
    DELETE = KEY_DELETE,
    RIGHT = KEY_RIGHT,
    LEFT = KEY_LEFT,
    DOWN = KEY_DOWN,
    UP = KEY_UP,
    PAGE_UP = KEY_PAGE_UP,
    PAGE_DOWN = KEY_PAGE_DOWN,
    HOME = KEY_HOME,
    END = KEY_END,
    CAPS_LOCK = KEY_CAPS_LOCK,
    SCROLL_LOCK = KEY_SCROLL_LOCK,
    NUM_LOCK = KEY_NUM_LOCK,
    PRINT_SCREEN = KEY_PRINT_SCREEN,
    PAUSE = KEY_PAUSE,
    F1 = KEY_F1,
    F2 = KEY_F2,
    F3 = KEY_F3,
    F4 = KEY_F4,
    F5 = KEY_F5,
    F6 = KEY_F6,
    F7 = KEY_F7,
    F8 = KEY_F8,
    F9 = KEY_F9,
    F10 = KEY_F10,
    F11 = KEY_F11,
    F12 = KEY_F12,
    F13 = KEY_F13,
    F14 = KEY_F14,
    F15 = KEY_F15,
    F16 = KEY_F16,
    F17 = KEY_F17,
    F18 = KEY_F18,
    F19 = KEY_F19,
    F20 = KEY_F20,
    F21 = KEY_F21,
    F22 = KEY_F22,
    F23 = KEY_F23,
    F24 = KEY_F24,
    KP_0 = KEY_KP_0,
    KP_1 = KEY_KP_1,
    KP_2 = KEY_KP_2,
    KP_3 = KEY_KP_3,
    KP_4 = KEY_KP_4,
    KP_5 = KEY_KP_5,
    KP_6 = KEY_KP_6,
    KP_7 = KEY_KP_7,
    KP_8 = KEY_KP_8,
    KP_9 = KEY_KP_9,
    KP_DECIMAL = KEY_KP_DECIMAL,
    KP_DIVIDE = KEY_KP_DIVIDE,
    KP_MULTIPLY = KEY_KP_MULTIPLY,
    KP_SUBTRACT = KEY_KP_SUBTRACT,
    KP_ADD = KEY_KP_ADD,
    KP_ENTER = KEY_KP_ENTER,
    KP_EQUAL = KEY_KP_EQUAL,
    SHIFT = KEY_SHIFT,
    CTRL = KEY_CTRL,
    ALT = KEY_ALT,
    LEFT_SHIFT = KEY_LEFT_SHIFT,
    LEFT_CONTROL = KEY_LEFT_CONTROL,
    LEFT_ALT = KEY_LEFT_ALT,
    LEFT_SUPER = KEY_LEFT_SUPER,
    RIGHT_SHIFT = KEY_RIGHT_SHIFT,
    RIGHT_CONTROL = KEY_RIGHT_CONTROL,
    RIGHT_ALT = KEY_RIGHT_ALT,
    RIGHT_SUPER = KEY_RIGHT_SUPER,
    MENU = KEY_MENU,
    SHIFT = KEY_MODIFIER_SHIFT,
    CTRL = KEY_MODIFIER_CONTROL,
    ALT = KEY_MODIFIER_ALT,
    SUPER = KEY_MODIFIER_SUPER
}

function Utils.setAppVar(varName, value)
    invokeProgram(MAIN_PROGRAMID, "setAppVar", varName, value)
end

function Utils.getAppVar(varName)
    return invokeProgram(MAIN_PROGRAMID, "getAppVar", varName)
end

function Utils.setProjectVar(varName, value)
    invokeProgram(MAIN_PROGRAMID, "setProjectVar", varName, value)
end

function Utils.getProjectVar(varName)
    return invokeProgram(MAIN_PROGRAMID, "getProjectVar", varName)
end

Utils.registeredShortcuts = {}
function Utils.registerShortcut(toolName, callback, key, modifier, config)
	if config ~= nil then
		if config.shortcuts[toolName] ~= nil then
			if config.shortcuts[toolName].key ~= nil then
				key = config.shortcuts[toolName].key

				if config.shortcuts[toolName].modifier ~= nil then
					modifier = config.shortcuts[toolName].modifier
				end
			end
		end
	end

	if type(key) == "string" then
		key = string.upper(key)
	end

	if type(modifier) == "string" then
		modifier = string.upper(modifier)
	end

	local keyVal = Utils.keyStrMap[key]
	local modifierVal = nil
	if modifier ~= nil then
		modifierVal = Utils.keyStrMap[modifier]
	end
	
	if keyVal ~= nil then
		Utils.registeredShortcuts[toolName] = {key = key, modifier = modifier}
		invokeProgram(MAIN_PROGRAMID, "registerShortcut", {desc = toolName, key = keyVal, modifier = modifierVal, callback = callback, programId = getProgramId()})
	end
end

function Utils.deserializeTable(tableStr)
	local fn = load("return " .. tableStr)

	local retTable = {}
	if fn ~= nil then
		retTable = fn()
	end

	return retTable
end

function Utils.serializeTable(t, indent)
    indent = indent or ""
    local nextIndent = indent .. "  "
    local lines = {"{"}

    local isArray = (#t > 0)

    if isArray == true then
    	for i = 1, #t do
    		local v = t[i]

    		local key = "[" .. i .. "] = "

    		local value
	        if type(v) == "table" then
	            value = Utils.serializeTable(v, nextIndent)
	        elseif type(v) == "string" then
	            value = string.format("%q", v)
	        else
	            value = tostring(v)
	        end

    		table.insert(lines, string.format("%s%s%s,", nextIndent, key, value))
    	end
    else
	    for k, v in pairs(t) do
	        local key
            if type(k) == "string" then
                if k:match("^%a[%w_]*$") then
                    key = k .. " = "
                else
                    key = "[" .. string.format("%q", k) .. "] = "
                end
            elseif type(k) == "number" then
                key = "[" .. k .. "] = "
	        else
	            key = ""
	        end

	        local value
	        if type(v) == "table" then
	            value = Utils.serializeTable(v, nextIndent)
	        elseif type(v) == "string" then
	            value = string.format("%q", v)
	        else
	            value = tostring(v)
	        end

	        table.insert(lines, string.format("%s%s%s,", nextIndent, key, value))
	    end
	end

    table.insert(lines, indent .. "}")
    return table.concat(lines, "\n")
end

function remapRange(value, min1, max1, min2, max2)
	return min2 + (value - min1) * (max2 - min2) / (max1 - min1)
end

function Utils.removeElements(sourceTable, elementsToRemove)
    local retTable = {}

    for i = 1, #sourceTable do
        if elementsToRemove[i] == nil then
            table.insert(retTable, sourceTable[i])
        end
    end

    return retTable
end