-- IndustrialTest
-- Copyright (C) 2023 mrkubax10

-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.

-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.

-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.

local machine={}

industrialtest.internal.mclAfterDigNode=function(pos,oldmeta,lists)
	-- Taken from https://git.minetest.land/MineClone2/MineClone2/src/branch/master/mods/ITEMS/mcl_furnaces/init.lua#L538
	local meta=minetest.get_meta(pos)
	local meta2=meta
	meta:from_table(oldmeta)
	local inv=meta:get_inventory()
	for _,listname in ipairs(lists) do
		local stack=inv:get_stack(listname,1)
		if not stack:is_empty() then
			local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
			minetest.add_item(p, stack)
		end
	end
	meta:from_table(meta2:to_table())
end

industrialtest.internal.chargeFromPowerStorageItem=function(meta,inv)
	local shouldRerunTimer=false
	local shouldUpdateFormspec=false
	local powerStorageSlot=inv:get_stack("powerStorage",1)
	if not powerStorageSlot:is_empty() then
		local stackMeta=powerStorageSlot:get_meta()
		if industrialtest.api.transferPower(stackMeta,meta,stackMeta:get_int("industrialtest.powerFlow"))>0 then
			shouldUpdateFormspec=true
			shouldRerunTimer=stackMeta:get_int("industrialtest.powerAmount")>0 and not industrialtest.api.isFullyCharged(meta)
			industrialtest.api.updateItemPowerText(powerStorageSlot)
			inv:set_stack("powerStorage",1,powerStorageSlot)
		end
	end
	return shouldRerunTimer,shouldUpdateFormspec
end

function industrialtest.internal.registerMachine(config)
	local definition={
		description=config.displayName,
		on_construct=function(pos)
			machine.onConstruct(pos,config)
		end,
		on_destruct=function(pos)
			machine.onDestruct(pos,config)
		end,
		on_timer=function(pos,elapsed)
			local shouldRerunTimer,_=machine.onTimer(pos,elapsed,config)
			return shouldRerunTimer
		end,
		allow_metadata_inventory_move=function(pos,fromList,fromIndex,toList,toIndex,count)
			return machine.allowMetadataInventoryMove(pos,fromList,fromIndex,toList,toIndex,count,config)
		end,
		allow_metadata_inventory_put=function(pos,listname,index,stack,player)
			return machine.allowMetadataInventoryPut(pos,listname,index,stack,player,config)
		end,
		allow_metadata_inventory_take=function(pos,listname,index,stack,player)
			return machine.allowMetadataInventoryTake(pos,listname,index,stack,player,config)
		end,
		on_metadata_inventory_put=function(pos,listname,index,stack,player)
			machine.onMetadataInventoryPut(pos,listname,index,stack)
			if config.onMetadataInventoryPut then
				config.onMetadataInventoryPut(pos,listname,index,stack,player)
			end
		end,
		on_metadata_inventory_move=function(pos,fromList,fromIndex,toList,toIndex,count)
			machine.onMetadataInventoryMove(pos,fromList,fromIndex,toList,toIndex)
			if config.onMetadataInventoryPut then
				config.onMetadataInventoryMove(pos,fromList,fromIndex,toList,toIndex,count)
			end
		end,
		on_metadata_inventory_take=function(pos,listname,index,stack,player)
			machine.onMetadataInventoryTake(pos,listname,index,stack)
			if config.onMetadataInventoryTake then
				config.onMetadataInventoryTake(pos,listname,index,stack,player)
			end
		end,
		_industrialtest_updateFormspec=function(pos)
			machine.updateFormspec(pos,config)
		end,
		_industrialtest_getFormspec=function(pos)
			if config.withoutFormspec then
				return ""
			end
			return machine.getFormspec(pos,config)
		end
	}
	definition.groups._industrialtest_wrenchUnmountable=1
	if config.requiresWrench then
		definition.drop="industrialtest:machine_block"
	end
	if config.customKeys then
		for key,value in pairs(config.customKeys) do
			definition[key]=value
		end
	end
	if config.groups then
		for key,value in pairs(config.groups) do
			definition.groups[key]=value
		end
	end
	minetest.register_node("industrialtest:"..config.name,definition)
	if config.registerActiveVariant then
		definition=table.copy(definition)
		definition.description=nil
		definition.on_timer=function(pos,elapsed)
			local meta=minetest.get_meta(pos)
			local inv=meta:get_inventory()
			local shouldRerunTimer=false
			local shouldUpdateFormspec=false

			if config.activeOnTimer then
				shouldRerunTimer,shouldUpdateFormspec=config.activeOnTimer(pos,elapsed,meta,inv)
			end

			local def=minetest.registered_nodes[minetest.get_node(pos).name]
			if def.groups and def.groups._industrialtest_hasPowerInput and not industrialtest.api.isFullyCharged(meta) then
				local networks=industrialtest.api.isAttachedToNetwork(meta)
				if networks then
					for _,network in ipairs(networks) do
						minetest.get_node_timer(network):start(industrialtest.updateDelay)
					end
				end
			end

			if shouldUpdateFormspec then
				machine.updateFormspec(pos,config)
			end

			return shouldRerunTimer
		end
		if not definition.drop then
			definition.drop="industrialtest:"..config.name
		end
		if config.activeCustomKeys then
			for key,value in pairs(config.activeCustomKeys) do
				definition[key]=value
			end
		end
		if industrialtest.mclAvailable then
			definition.groups.not_in_creative_inventory=1
			definition._doc_items_create_entry=false
		end
		minetest.register_node("industrialtest:"..config.name.."_active",definition)
	end
	industrialtest.api.addTag("industrialtest:"..config.name,"usesTimer")
end