local spark_quick_put_enable = minetest.settings:get_bool("spark_quick_put_enabled")

local whitelistPut = { fuel = true, source = true, charge = true }
local whitelistTake = { charge = true, product = true }

local maxStackSize = tonumber(minetest.settings:get("default_stack_max"))
local maxIncrement = function(stack1)
	return (maxStackSize - stack1:get_count()) * -1
end

-- TODO: move this to sparkapi
-- This should combine stack1 with stack2, respecting per-item metadata like genomes
-- Just take random ones :D, if something else is wanted it can be done more explicitly
local combineStack = function(stack1, stack2)
	if stack1:get_name() == stack2:get_name() then
		local count1 = stack1:get_count()
		local count2 = stack2:get_count()
		local newcount1 = count1 + count2
		local newcount2 = 0
		if newcount1 > maxStackSize then
			newcount2 = newcount1 - maxStackSize
			newcount1 = maxStackSize
		end
		stack1:set_count(newcount1)
		stack2:set_count(newcount2)
		return stack1, stack2
	elseif stack1:get_name() == "" then
		return stack2, stack1
	else
		return stack1, stack2
	end
end

-- This functionality relies on allow_metadata_inventory_put
-- and allow_metadata_inventory_take beeing defined correctly
-- fallback code would be quite icky to write...
local putItem = function(position, node, puncher, pointed)
	local noderef = minetest.registered_nodes[node.name]
	local putfunc = noderef.allow_metadata_inventory_put
	local wieldItem = puncher:get_wielded_item()
	local inventory = minetest.get_meta(position):get_inventory()
	if not noderef or not putfunc or not wieldItem or not inventory then return false end

	for listName in pairs(inventory:get_lists()) do
		if whitelistPut[listName] then
			local transstack = 0
			if putfunc then
				transstack = putfunc(position, listName, nil, wieldItem, puncher)
			end
			if transstack ~= 0 then
				local leftover = inventory:add_item(listName, wieldItem)
				puncher:set_wielded_item(leftover)
				noderef.on_metadata_inventory_put(position)
				return true
			end
		end
	end
	return false
end

local takeItem = function(position, node, puncher, pointed)
	local noderef = minetest.registered_nodes[node.name]
	local takefunc = noderef.allow_metadata_inventory_take
	local wieldItem = puncher:get_wielded_item()
	local inventory = minetest.get_meta(position):get_inventory()
	if not noderef or not takefunc or not wieldItem or not inventory then return false end

	for listName in pairs(inventory:get_lists()) do
		if whitelistTake[listName] then
			local result = false
			for index = 1, inventory:get_size(listName) do
				wieldItem = puncher:get_wielded_item()
				local item = inventory:get_stack(listName, index)
				if (wieldItem:get_name() == "" and item:get_name() ~= "") or wieldItem:get_name() == item:get_name() then
					local maxAmmount = takefunc(position, listName, index, item, player)
					local ammount = math.min(maxAmmount, maxIncrement(wieldItem))
					if ammount ~= 0 then
						local stack1, stack2 = combineStack(wieldItem, item)
						puncher:set_wielded_item(stack1)
						inventory:set_stack(listName, index, stack2)
						result = true
					end
				end
			end
			if result then return result end
		end
	end
	return false
end


minetest.register_on_punchnode(function(position, node, puncher, pointed)
	if not putItem(position, node, puncher, pointed) then
		return takeItem(position, node, puncher, pointed)
	else
		return true
	end
end)
