local Queue
if worldeditadditions_core then
	Queue = dofile(worldeditadditions_core.modpath.."/utils/queue.lua")
else
	Queue = require("queue")
end

--- A least-recently-used cache implementation.
-- @class	worldeditadditions_core.LRU
local LRU = {}
LRU.__index = LRU

--- Creates a new LRU cache.
-- Optimal sizes: 8, 16, 32, 64 or any value above
-- @param	max_size=32		number	The maximum number of items to store in the cache.
-- @returns	LRU				A new LRU cache.
function LRU.new(max_size)
	if not max_size then max_size = 32 end
	local result = {
		max_size = max_size,
		cache = {  },
		size = 0,
		queue = Queue.new()
	}
	setmetatable(result, LRU)
	return result
end

--- Determines whether the given key is present in this cache object.
-- Does NOT update the most recently used status of said key.
-- @param	key		string	The key to check.
-- @returns	bool	Whether the given key exists in the cache or not.
function LRU:has(key)
	return self.cache[key] ~= nil
end

--- Gets the value associated with the given key.
-- @param	key		string	The key to retrieve the value for.
-- @returns	any|nil	The value associated with the given key, or nil if it doesn't exist in this cache.
function LRU:get(key)
	if not self.cache[key] then return nil end
	
	-- Put it to the end of the queue
	self.queue:remove_index(self.cache[key].index)
	self.cache[key].index = self.queue:enqueue(key)
	
	return self.cache[key].value
end

--- Adds a given key-value pair to this cache.
-- Note that this might (or might not) result in the eviction of another item.
-- @param	key		string	The key of the item to add.
-- @param	value	any		The value to associate with the given key.
-- @returns nil
function LRU:set(key, value)
	if self.cache[key] ~= nil then
		-- It's already present in the cache - update it
		-- Put it to the end of the queue
		self.queue:remove_index(self.cache[key].index)
		local new_index = self.queue:enqueue(key)
		-- Update the cache entry
		self.cache[key] = {
			value = value,
			index = new_index
		}
	else
		-- It's not in the cache -- add it
		self.cache[key] = { value = value, index = self.queue:enqueue(key) }
		
		self.size = self.size + 1
		if self.size > self.max_size then
			-- The cache is full, delete the oldest item
			local oldest_key = self.queue:dequeue()
			self.cache[oldest_key] = nil
			self.size = self.size - 1
		end
	end
end

return LRU
