classes = classes or {}
ghf = ghf or {}

ghf.bit1 = 1
ghf.bit2 = ghf.bit1*2
ghf.bit3 = ghf.bit2*2
ghf.bit4 = ghf.bit3*2
ghf.bit5 = ghf.bit4*2
ghf.bit6 = ghf.bit5*2
ghf.bit7 = ghf.bit6*2
ghf.bit8 = ghf.bit7*2
ghf.bit9 = ghf.bit8*2
ghf.bit10 = ghf.bit9*2
ghf.bit11 = ghf.bit10*2
ghf.bit12 = ghf.bit11*2
ghf.bit13 = ghf.bit12*2
ghf.bit14 = ghf.bit13*2
ghf.bit15 = ghf.bit14*2
ghf.bit16 = ghf.bit15*2
ghf.bit17 = ghf.bit16*2
ghf.bit18 = ghf.bit17*2
ghf.bit19 = ghf.bit18*2
ghf.bit20 = ghf.bit19*2
ghf.bit21 = ghf.bit20*2
ghf.bit22 = ghf.bit21*2
ghf.bit23 = ghf.bit22*2
ghf.bit24 = ghf.bit23*2
ghf.bit25 = ghf.bit24*2
ghf.bit26 = ghf.bit25*2
ghf.bit27 = ghf.bit26*2
ghf.bit28 = ghf.bit27*2
ghf.bit29 = ghf.bit28*2
ghf.bit30 = ghf.bit29*2
ghf.bit31 = ghf.bit30*2
ghf.bit32 = ghf.bit31*2

--[[
This file will be run whenever a lua state is created. It's a good place to
initialize any functions you want available globally, as well as to override
default lua behaviors.
--]]

math.isinteger = function(test)
	return((test % 1)==0)
end

-- math.random doesn't really do what we want it to do (ie easily allow random
-- numbers in a floating point range) and will often do the wrong thing or
-- fail silently, so it gets removed. Keep a local reference to the function
-- to allow behavior of our choosing
math.__old_random = math.__old_random or math.random
math.random = nil

-- the GHF random. math.random isn't reused in order to avoid confusion for
-- people reading the lua docs (ie it would work differently than documented
-- so make people call something else.)

-- Random function that allows two floating point numbers to be used as the
-- range. If rangeMax is not present, range is considered 1 to rangeMin

-- If both inputs are integers, return value will be a random integer,
-- otherwise, result will be a floating point number (which will be the
-- range mulitplied by the result of math.random())
math.Random = function(rangeMin, rangeMax)
	if rangeMax == nil then
		if rangeMin == nil then
			return math.__old_random()
		else
			rangeMin, rangeMax = 1, rangeMin
		end
	elseif rangeMin > rangeMax then
		rangeMax, rangeMin = rangeMin, rangeMax
	end

	if math.isinteger(rangeMin) and math.isinteger(rangeMax) then
		return math.__old_random(rangeMin, rangeMax)
	end

	local range = rangeMax - rangeMin
	local r = math.__old_random()
	return rangeMin + (r * range)
end

math.calcNewSpeedAndPos = function(time, curPos, targetPos, curSpeed, maxSpeed, accInc, accDec, allowMoveBack)
	allowMoveBack = (allowMoveBack ~= false)

	local breakDistance = curSpeed * curSpeed / (2 * accDec)
	local delta = targetPos - curPos

	if (math.abs(delta) < breakDistance) then
		local acc = (accDec * time) / 1000
		if (curSpeed > 0) then
			curSpeed = curSpeed - acc
			if (curSpeed < 0) then
				curSpeed = 0
			end
		else
			curSpeed = curSpeed + acc
			if (curSpeed > 0) then
				curSpeed = 0
			end
		end
	else
		local acc = (accInc * time) / 1000
		if (delta > 0) then
			curSpeed = curSpeed + acc
			if (curSpeed > maxSpeed) then
				curSpeed = maxSpeed
			end
		elseif (allowMoveBack) then
			curSpeed = curSpeed - acc
			if (curSpeed < -maxSpeed) then
				curSpeed = -maxSpeed
			end
		end
	end

	local onLeftSide = (curPos < targetPos)
	curPos = curPos + (curSpeed * time) / 1000
	if ((curPos < targetPos) ~= onLeftSide) then
		curPos = targetPos
		curSpeed = 0
	end

	return curPos, curSpeed
end

function math.scurve(fact)
	return fact * fact * (3 - fact - fact)
end

function math.jcurve(fact)
	return fact * fact
end

function math.rcurve(fact)
	return 1 - (fact - 1) * (fact - 1)
end

function math.lerp(fact, v1, v2)
	return v1 * (1.0 - fact) + v2 * fact
end

function math.inv_lerp(v, v1, v2)
	if (v2 == v1) then
		return 0
	end
	return (v - v1) / (v2 - v1)
end

function math.clamp(v, min, max)
	return (v <= min and min) or (v >= max and max) or v
end

function table.push_back(t, item)
	table.insert(t, item)
	return item
end

function table.push_front(t, item)
	table.insert(t, 1, item)
	return item
end

function table.count(t)
	local num = 0
	for _,_ in pairs(t) do
		num = num + 1
	end
	return num
end

function table.icount(t)
	return #t
end

function table.empty(t)
	for _,_ in pairs(t) do
		return false
	end
	return true
end

function table.iempty(t)
	return #t == 0
end

function table.pop_back(t)
	local v = t[#t]
	table.remove_at(t, #t)
	return v
end

function table.pop_front(t)
	local v = t[1]
	table.remove_at(t, 1)
	return v
end

function table.copy(t, recursive, metatables)
    if type(t) ~= "table" then
        return t
    end

    local recursiveDepth = 1
    if isNumber(recursive) then
		if recursive ~= 0 then
			recursiveDepth = recursive
		end
	elseif recursive then
		recursiveDepth = -1 -- infinite
	end

	local saved = {}
	function recursiveCopy(t, recDepth)
		function getCopy(v)
			if type(v) == "table" and recDepth ~= 0 then
				if saved[v] == nil then
					saved[v] = recursiveCopy(v, recDepth-1)
				end
				return saved[v]
			end
			return v
		end

		local new = {}
		saved[t] = new
		for k,v in pairs(t) do
			rawset(new, k, getCopy(v))
		end

		if metatables == "set" then
			setmetatable(new, getmetatable(t))
		elseif metatables then
			setmetatable(new, getCopy(getmetatable(t)))
		end

		return new
	end

	return recursiveCopy(t, recursiveDepth-1)
end

function table.contains(t, val, recursive, metatables, keys)
    if val == nil then
        return false
    end

    local checked = {}
    function findInTable(t)
		function checkValue(v)
			if not checked[v] then
				if v == val then
					return true
				end
				if recursive and type(v) == "table" and findInTable(v) then
					return true
				end
				if metatables and checkValue(getmetatable(t)) then
					return true
				end
				checked[v] = true
			end
			return false
		end

		for k,v in pairs(t) do
			if checkValue(v) then
				return true
			end
			if keys and checkValue(k) then
				return true
			end
		end

		return false
	end

	if type(t) == "table" then
		return findInTable(t)
	end
	return false
end

function table.index_of(t, val)
	for k,v in pairs(t) do
		if (v == val) then
			return k
		end
	end
end

table.remove_at = table.remove_at or table.remove
table.remove = function(t, val, all)
	local removed = 0
	for i,v in ipairs(t) do
		if (v == val) then
			table.remove_at(t, i)
			if not all then return 1 end
			removed = removed + 1
		end
	end
	return removed ~= 0 and removed
end

function table.copy_into(dest, src, recursive, metatables)
    if type(dest) ~= "table" then
        dest = {}
    end
    if type(src) ~= "table" then
        return dest
    end
	if recursive then
		local saved = {}
		saved[src] = dest

		function recursiveCopy(dest, src)
			for k,v in pairs(src) do
				if type(v) == "table" then
					if saved[v] == nil then
						local tmp = rawget(dest, k)
						if not isTable(tmp) then
							tmp = {}
						end
						saved[v] = tmp
						recursiveCopy(tmp, v)
					end
					rawset(dest, k, saved[v])
				else
					rawset(dest, k, v)
				end
			end
			if metatables then
				setmetatable(dest, getmetatable(src))
			end
		end

		recursiveCopy(dest, src)
	else
		for k,v in pairs(src) do
			rawset(dest, k, v)
		end
		if metatables then
			setmetatable(dest, getmetatable(src))
		end
	end
	return dest
end

function isTable(v)
	return type(v) == "table"
end

function isString(v)
	return type(v) == "string"
end

function isNumber(v)
	return type(v) == "number"
end

function isBoolean(v)
	return type(v) == "boolean"
end

function isCallable(v)
    if v == nil then return false end
    if type(v) == "function" then
        return true
    else
        local meta = getmetatable(v)
        if isTable(meta) and isCallable(rawget(meta, "__call")) then
            return true
        end
    end
    return false
end

function createCppClass(className)
	if _G.classes[className] ~= nil then
		return
	end
	_G.classes[className] = {}
	return _G.classes[className]
end

function deriveLuaClass(className, superName)
	_G.classes[className] = _G.classes[className] or {}
	return setupMetatable(className, superName)
end

function getClass(className)
	return _G.classes[className]
end

function setupMetatable(className, superName)
	if _G.classes == nil then
		_G.classes = setmetatable({}, {__mode = "k"})
	end

	if not isString(className) then
		error("You need to provide a class name")
		return
	end

	if superName ~= nil and type(superName) ~= "string" then
		error("You need to provide a super class via a string")
		return
	end

	local base = _G.classes[className]
	if base == nil then
		error("This class does not exist yet: " .. className)
		return
	elseif type(base) ~= "table" then
		error("A non-table was stored... WTF?: " .. className)
		return
	end

	local super
	if superName ~= nil then
		super = _G.classes[superName]
		if type(super) ~= "table" then
			error("Could not find the 'super' table: " .. superName .. " (base: " .. className .. ")")
			return
		end
	end

    function link_rawget(base, super, idx)
        local super_rawget
        local base_rawget
        if super ~= nil then
            super_rawget = rawget(super, "__index_funcs")[idx]
            if super_rawget ~= nil then
                base_rawget = function(t, k)
                    local v = rawget(base, k)
                    if v ~= nil then
                        return v
                    end
                    return super_rawget(t, k)
                 end
            end
        end
        if base_rawget == nil then
            base_rawget = function(t, k)
                return rawget(base, k)
            end
        end
        rawget(base, "__index_funcs")[idx] = base_rawget
        return base_rawget
    end

    function link_getters(base, super, idx)
        local getters = rawget(base, "__getters") or {}
        rawset(base, "__getters", getters)

        local base_get
        local super_get
        if super ~= nil then
            super_get = rawget(super, "__index_funcs")[idx]
        end
        if super_get ~= nil then
            base_get = function(t, k)
                local f = getters[k]
                if f ~= nil then
                    return f(t)
                end
                return super_get(t, k)
             end
        else
            base_get = function(t, k)
                local f = getters[k]
                if f ~= nil then
                    return f(t)
                end
                return nil
             end
        end
        rawget(base, "__index_funcs")[idx] = base_get
        return base_get
    end

    function link_setters(base, super, idx)
        local setters = rawget(base, "__setters") or {}
        rawset(base, "__setters", setters)

        local base_set
        local super_set
        if super ~= nil then
            super_set = rawget(super, "__newindex_funcs")[idx]
        end
        if super_set ~= nil then
            base_set = function(t, k, v)
                local f = setters[k]
                if f ~= nil then
                    f(t, v)
                    return true
                end
                return super_set(t, k, v)
             end
        else
            base_set = function(t, k, v)
                local f = setters[k]
                if f ~= nil then
                    f(t, v)
                    return true
                end
                return false
             end
        end
        rawget(base, "__newindex_funcs")[idx] = base_set
        return base_set
    end

    rawset(base, "classname", className)
    rawset(base, "class", base)
    rawset(base, "super", super)
    setmetatable(base, { __index = super })
    if super ~= nil then
        rawset(base, "superInit", function(self, ...)
            local f = super.init
            if isCallable(f) then
                f(self, unpack(arg))
            end
        end)

        rawset(base, "classInit", function(self, ...)
            local f = self.class.init
            if isCallable(f) then
                f(self, unpack(arg))
            end
        end)

        if not rawget(base, "__tostring") then
            rawset(base, "__tostring", function(self)
                if super.__tostring then
                    return super.__tostring(self)
                else
                    return type(self)
                end
            end)
        end
    else
        local f = function() end
        rawset(base, "superInit", f)
        rawset(base, "classInit", f)
    end

    rawset(base, "new", function(...)
        local inst = setmetatable({ class = base }, base)
        local f = inst.init
        if isCallable(f) then
            f(inst, unpack(arg))
        end
        return inst
    end)

    local index_funcs = rawget(base, "__index_funcs") or {}
    rawset(base, "__index_funcs", index_funcs)

    local newindex_funcs = rawget(base, "__newindex_funcs") or {}
    rawset(base, "__newindex_funcs", newindex_funcs)

    if super ~= nil then
        local super_index_funcs = rawget(super, "__index_funcs") or {}
        if super_index_funcs ~= nil then
            for i = 1, #super_index_funcs do
                index_funcs[i] = super_index_funcs[i]
            end
        end

        local super_newindex_funcs = rawget(super, "__newindex_funcs") or {}
        if super_newindex_funcs ~= nil then
            for i = 1, #super_newindex_funcs do
                newindex_funcs[i] = super_newindex_funcs[i]
            end
        end
    end

    link_rawget(base, super, 1)
    link_getters(base, super, 2)

    local base_index
    local i1 = index_funcs[1]
    local i2 = index_funcs[2]
    if #index_funcs == 0 then
        base_index = rawget
    elseif #index_funcs == 2 then -- most common
        base_index = function(t, k)
            local v = rawget(t, k)
            if v ~= nil then return v end
            v = i1(t, k)
            if v ~= nil then return v end
            return i2(t, k)
        end
    else
        base_index = function(t, k)
            local v = rawget(t, k)
            if v ~= nil then return v end
            for i = 1, #index_funcs do
                v = index_funcs[i](t, k)
                if v ~= nil then return v end
            end
        end
    end

    link_setters(base, super, 1)

    local base_newindex
    local i1 = newindex_funcs[1]
    if #newindex_funcs == 0 then
        base_newindex = rawset
    elseif #newindex_funcs == 1 then -- most common
        base_newindex = function(t, k, v)
            if rawget(t, k) == nil then
                if i1(t, k, v) then
                    return
                end
            end
            rawset(t, k, v)
        end
    else
        base_newindex = function(t, k, v)
            if rawget(t, k) == nil then
                for i = 1, #newindex_funcs do
                    if newindex_funcs[i](t, k, v) then
                        return
                    end
                end
            end
            rawset(t, k, v)
        end
    end

    rawset(base, "__index", base_index)
    rawset(base, "__newindex", base_newindex)

    local getters = rawget(base, "__getters");
    local setters = rawget(base, "__setters");

    rawset(base, "setAccessors", function(k, getter, setter)
		rawset(getters, k, getter)
		rawset(setters, k, setter)
    end)

    rawset(base, "setGetter", function(k, getter) rawset(getters, k, getter) end)
    rawset(base, "setSetter", function(k, setter) rawset(setters, k, setter) end)

    return base
end

function forEachMetatable(object, f)
	local meta = getmetatable(object) or object.class or object.super
	while isTable(meta) do
		local r = f(meta)
		if r ~= nil then return r end
		meta = meta.super
	end
end

function getTopMostCppClassName(className)
	if not isString(className) then
		return ""
	end

	local cppClassNames = ghf.getCppClassNames()
	function getRecursive(className)
		if cppClassNames[className] ~= nil then
			return className
		end
		local classMeta = _G.classes[className]
		if type(classMeta) == "table" then
			if classMeta.super then
				return getRecursive(classMeta.super.classname)
			else
				error("Class metatable found without a 'super' field: "..classMeta.classname.." while searching for "..className)
			end
		else
			error("Could not find parent class for "..className)
		end
		return ""
	end

	return getRecursive(className)
end
