dataManagerConstructor = {
	new = function (self)
		local dataManager = {
			collection = {}, -- Optimised for fast loops
			registery = {} -- Optimised to speed up finding the right item
		}
		
		local methods = self.methods
		-- The following can also be done with just a meta table, but that would make the methods slower. Making an instance is just something you do once.
		for i=1, #methods do
			local method = methods[i]
			dataManager[method.key] = method.func
		end
		
		return dataManager
	end,
	methods = {		
		{
			key = "clone",
			func = function (self) 
				local newCollection = {}
				local newRegistery = {}
				
				local dataManager = {
					collection = newCollection,
					registery = newRegistery
				}
				
				local collection = self.collection
				for i=1, #collection do
					local item = collection[i]
					local key = item.key
					local newItem = {
						key  = key,
						value = item.value
					}
					newCollection[i] = newItem
					newRegistery[key] = newItem
				end
				
				local methods = dataManagerConstructor.methods
				for i=1, #methods do
					local method = methods[i]
					dataManager[method.key] = method.func
				end
				
				return dataManager 
			end
		},
		{
			key = "setData",
			func = function (self, key, value)
				local registery = self.registery
				if key ~= nil and not registery[key] then
					local item = {
						key = key,
						value = value
					}
					registery[key] = item
					local collection = self.collection
					collection[#collection + 1] = item
					return self, true
				end
				return self, false
			end
		},
		{
			key = "getData",
			func = function (self, key)
				if key ~= nil then
					local item = self.registery[key]
					if item then
						return item.value
					end
				end
				return false
			end
		},
		{
			key = "clear", 
			func = function (self)
				self.collection = {}
				self.registery = {}
				return self
			end
		},
		{
			key = "getNext",
			func = function (self, index)
				local collection = self.collection
				if index == 0 then
					index = nil
				end
				local foundIndex, item = next(collection, index)
				if item then
					return item.key, item.value, foundIndex
				end
			end
		},
		{
			key = "forEach",
			func = function (self, callBackFunc, inverted)
				local collection = self.collection
				if not inverted then
					for i=1, #collection do
						local item = collection[i]
						callBackFunc(item.key, item.value)
					end
				else
					for i=#collection, 1, -1 do
						local item = collection[i]
						callBackFunc(item.key, item.value)
					end
				end
				return true
			end
		},
		{
			key = "getKeys",
			func = function (self)
				local keys = {}
				local collection = self.collection
				for i=1, #collection do
					keys[i] = collection[i].key
				end
				return keys
			end
		},		
		{
			key = "sort",
			func = function (self, func)
				
				local collection = self.collection
				table.sort(collection, func)
				return true
			end
		},
		{
			key = "getAllData",
			func = function (self, reduceData)
				local collection = self.collection
				-- Format: {key = ..., value = ...}
				local newCollection = {}
				for i=1, #collection do
					local item = collection[i]
					if reduceData and type(reduceData) == "function" then
						
						newCollection[#newCollection + 1] = {key = item.key, value = reduceData(item.value)}
					else
						newCollection[#newCollection + 1] = {key = item.key, value = item.value}
					end
				end
				return newCollection
			end
		},
		{
			key = "addAllData",
			func = function (self, collection)
				for i=1, #collection do
					local item = collection[i]
					self:setData(item.key, item.value)
				end
				return self, true
			end
		},
		{
			key = "removeData",
			func = function (self, key)
				local registery = self.registery
				if key ~= nil then
					local item = registery[key]
					if item then
						registery[key] = nil
						local collection = self.collection
						for i=1, #collection do
							if collection[i] == item then
								table.remove(collection, i)
								break
							end
						end
						return self, true
					end
				end
				return self, false
			end
		},
	}
}
