sorcery.lathe = {
	techs = {
		cut = {dmg = true};
		intaglio = {consume = true};
	};
	tools = {
		sword = 'cut', knife = 'cut', blade = 'cut';
	};
	recipes = {};
	register = function(def)
		local recipes = sorcery.lathe.recipes
		if not recipes[def.input] then recipes[def.input] = {} end
		local rs = recipes[def.input][def.tech]
		if not rs
			then recipes[def.input][def.tech] = { def }
			else rs[#rs+1] = def
		end
	end;
	tooltech = function(tool)
		if type(tool) ~= 'string' then tool = tool:get_name() end
		for g,t in pairs(sorcery.lathe.tools) do
			if minetest.get_item_group(tool, g) ~= 0 then
				return t
			end
		end
	end;
}

local R = sorcery.lathe.recipes
sorcery.lathe.get = function(pos,idx,howmany)
	local inv = minetest.get_meta(pos):get_inventory()
	local tool = inv:get_stack('tool',1)
	local tech = sorcery.lathe.tooltech(tool)
	if not tech then return nil end
	local wkpc = inv:get_stack('workpiece',1)
	local rec = R[wkpc:get_name()][tech][idx]
	local outn = ItemStack(rec.output):get_count()
	local q = howmany / outn
	return {
		tool = tool, wkpc = wkpc;
		cost = rec.cost * q;
		qty = q, outn = outn;
		tech = tech;
		rec = rec;
		inv = inv;
	}
end

sorcery.lathe.update = function(pos)
	local inv = minetest.get_meta(pos):get_inventory()
	local tool = inv:get_stack('tool',1)
	local wkpc = inv:get_stack('workpiece',1)
	if tool:is_empty() or wkpc:is_empty() then
		if not inv:is_empty('preview') then
			for i=1, inv:get_size('preview') do
				inv:set_stack('preview',i,ItemStack())
			end
		end
		return
	end

	local tech = sorcery.lathe.tooltech(tool)
	local rec = R[wkpc:get_name()][tech]
	tech = sorcery.lathe.techs[tech]

	-- fill in the preview slots
	local j = 1
	for i=1, inv:get_size('preview') do
		local stk
		if rec[i] and minetest.registered_items[ItemStack(rec[i].output):get_name()] then
			local max = wkpc:get_count()
			if tech.dmg then
				-- TODO count remaining tool uses
			elseif tech.consume then
				max = math.min(max, tool:get_count())
			end
			if max > 0 then
				stk = ItemStack(rec[i].output)
				stk:set_count(stk:get_count() * max)
				inv:set_stack('preview',i,stk)
			end
		end
		j = j + 1
	end

	-- make sure remaining slots are clear
	for i = j, inv:get_size('preview') do
		inv:set_stack('preview',i,ItemStack())
	end

end

local box = {
	type='fixed';
	fixed = {
		-0.7, -0.5, -0.3;
		 0.57,  0.2,  0.3;
	}
}
minetest.register_node('sorcery:lathe', {
	description = 'Lathe';
	drawtype = 'mesh';
	mesh = 'sorcery-lathe.obj';
	sunlight_propagates = true;
	paramtype = 'light';
	paramtype2 = 'facedir';
	selection_box = box;
	collision_box = box;
	groups = { cracky = 2; sorcery_tech = 1; attached_node = 1 }; -- 2=liquid
	after_dig_node = sorcery.lib.node.purge_only { 'workpiece', 'tool' };
	tiles = {
		'default_wood.png';
		'default_steel_block.png';
		'default_bronze_block.png';
	};
	on_construct = function(pos)
		local m = minetest.get_meta(pos)
		local i = m:get_inventory()
		i:set_size('workpiece', 1);
		i:set_size('tool', 1);
		i:set_size('preview', 8);
		m:set_string('formspec', [[
			formspec_version[3] size[10.25,8]
			list[context;tool;1.50,1;1,1]
			list[context;workpiece;3,1;1,1]
			list[context;preview;5.25,0.25;4,2]
			list[current_player;main;0.25,3;8,4]

			listring[current_player;main] listring[context;workpiece]
			listring[current_player;main] listring[context;tool]
			listring[current_player;main] listring[context;preview]
			listring[current_player;main]
		]])
	end;

	allow_metadata_inventory_move = function() return 0 end;
	allow_metadata_inventory_put = function(pos, list, idx, stack, user)
		local inv = minetest.get_meta(pos):get_inventory()
		if list == 'tool' then
			local s_wkpc = inv:get_stack('workpiece', 1)
			local tech = sorcery.lathe.tooltech(stack)
			if tech and (s_wkpc:is_empty()
			or (R[s_wkpc:get_name()]       ~= nil and
				R[s_wkpc:get_name()][tech] ~= nil))
					then return stack:get_count() end
		elseif list == 'workpiece' then
			local s_tool = inv:get_stack('tool', 1)
			if R[stack:get_name()] then
				if s_tool:is_empty()
				or R[stack:get_name()][sorcery.lathe.tooltech(s_tool)]
					then return stack:get_count() end
			end
		end

		return 0
	end;
	allow_metadata_inventory_take = function(pos, list, idx, stack, user)
		if list == 'preview' then
			local l = sorcery.lathe.get(pos,idx,stack:get_count())
			if stack:get_count() % l.outn == 0 then
				return stack:get_count()
			else return 0 end
		else return stack:get_count() end
	end;
	on_metadata_inventory_put = sorcery.lathe.update;
	on_metadata_inventory_take = function(pos, list, idx, stack, user)
		if list == 'preview' then
			local l = sorcery.lathe.get(pos,idx,stack:get_count())

			if sorcery.lathe.techs[l.tech].consume then
				l.tool:take_item(l.cost)
			elseif sorcery.lathe.techs[l.tech].dmg then
			--TODO wear down tool
			end
			l.wkpc:take_item(l.qty)
			l.inv:set_stack('tool', 1, l.tool)
			l.inv:set_stack('workpiece', 1, l.wkpc)
			minetest.sound_play('sorcery_clank', { pos = pos, gain = 0.9 })
		end
		sorcery.lathe.update(pos)
	end;

})

minetest.register_craft {
	output = 'sorcery:lathe';
	recipe = {
		{'default:stick','basic_materials:gear_steel','default:steel_ingot'};
		{'default:bronze_ingot','basic_materials:steel_bar','default:bronze_ingot'};
		{'group:wood','','group:wood'};
	};
}
