local hitbox = {
	type = 'fixed';
	fixed = {
		-0.4, -0.5, -0.5;
		 0.4,  0.2,  0.5;
	};
}
local kegcaption = function(m)
	local liqid = m:get_string('liquid')
	if liqid ~= '' then
		local liq = sorcery.register.liquid.db[liqid]
		if not liq then log.err('missing entry for liquid',liqid) return end
		local measure = liq.measure or function(u)
			return string.format('%s drams', u*63.9)
		end

		return {
			title = string.format('Keg of %s', liq.name);
			color = sorcery.lib.color(liq.color);
			props = {
				{title = 'Contains', desc = measure(m:get_int('charge'))};
			}
		};
	else return { title = 'Empty Keg', props = {} } end
end
local log = sorcery.logger('keg')
minetest.register_node('sorcery:keg', {
	description = 'Keg';
	drawtype = 'mesh';
	mesh = 'sorcery-keg.obj';
	sunlight_propagates = true;
	paramtype = 'light';
	paramtype2 = 'facedir';
	groups = { choppy = 2; sorcery_container = 2 }; -- 2=liquid
	tiles = {
		'default_bronze_block.png';
		'default_wood.png';
		'default_steel_block.png';
	};
	selection_box = hitbox;
	collision_box = hitbox;
	drop = {
		-- preserve_metadata will not work without this!
		max_items = 1;
		items = {
			{ items = { 'sorcery:keg' } };
		};
	};
	preserve_metadata = function(pos,node,meta,drops)
		if meta.liquid and meta.liquid ~= '' then
			local m = drops[1]:get_meta()
			m:from_table({fields = meta})
			local cap = kegcaption(m)
			m:set_string('description', sorcery.lib.ui.tooltip(cap))
			m:set_string('short_description', cap.title)
		end
	end;
	after_place_node = function(pos, placer, stack, tgt)
		local meta = minetest.get_meta(pos)
		local stackmeta = stack:get_meta()
		meta:from_table(stackmeta:to_table())
	end;
	on_construct = function(pos)
		local m = minetest.get_meta(pos)
		m:set_string('infotext', 'Empty Keg')
	end;
	on_rightclick = function(pos, node, user, stack)
		local m = minetest.get_meta(pos)
		local update = function()
			local c = kegcaption(m)
			local str = c.title
			for _,p in pairs(c.props) do
				str = str .. string.format('\n(%s: %s)', p.title, p.desc)
			end
			m:set_string('infotext', str)
		end
		local noise = function(amt)
			minetest.sound_play('default_water_footstep', {
				gain = 0.5 + amt / 9.0;
				pitch = 1.3 - amt / 12.0;
				pos = pos;
			}, true)
		end

		if stack:is_empty() then return end

		local ctr = sorcery.itemclass.get(stack, 'container')
		if (not ctr) or not ctr.hold == 'liquid' then return end

		if ctr.has and
			(m:get_string('liquid') == ctr.has or not m:contains('liquid')) then
			if not ctr.empty then log.err(stack:get_name(), 'does not specify its empty counterpart container') return end


			local add = ctr.charge * stack:get_count()
			local chg = m:get_int('charge')
			m:set_int('charge', chg + add)
			m:set_string('liquid', ctr.has)
			noise(chg + add)

			local liq = sorcery.register.liquid.db[ctr.has]
			if liq then
				update()
				log.act(string.format('%s added %u units of %s to a keg', user:get_player_name(), add, ctr.has))
			else log.err('no liquid entry for',ctr.has) end

			return ItemStack {
				name = ctr.empty;
				count = stack:get_count();
			}
		elseif not ctr.has and m:get_string('liquid') ~= '' then
			local reg = sorcery.register.liquid.db[m:get_string('liquid')]
			if not reg then log.err('missing definition for liquid', m:get_string('liquid')) return end

			local filled = reg.containers[stack:get_name()]
			if filled then
				local fs = sorcery.itemclass.get(filled, 'container')
				if not fs then log.err(filled,'is named as filled container but does not have the required itemclass definition') return end
				local chg = fs.charge * stack:get_count()
				local avail = m:get_int('charge')
				
				if avail >= chg then
					local liqid = m:get_string('liquid')
					local liq = sorcery.register.liquid.db[liqid]
					log.act(string.format('%s removed %u units of %s from a keg', user:get_player_name(), chg, liqid))
					if avail == chg then
						m:set_string('liquid','')
						m:set_int('charge',0)
					else m:set_int('charge', avail - chg) end
					noise(chg)
					update()

					-- fancy visuals
					local color = sorcery.lib.color(liq.color or {255,255,255})
					local spritz = sorcery.lib.image('sorcery_droplet.png')
					local drop = sorcery.lib.image('sorcery_drop.png')
					spritz = spritz:blit(spritz:multiply(color))
					drop   = drop:blit  (drop:multiply  (color))
					local facing = minetest.facedir_to_dir(minetest.get_node(pos).param2)
					local noz = vector.add(pos, vector.rotate(
						vector.new(0.0,0,-0.48),
						vector.dir_to_rotation(facing)
					))
					local minnoz = vector.offset(noz, -0.03, -0.32, -0.03);
					local maxnoz = vector.offset(noz,  0.03, -0.32,  0.03);
					minetest.add_particlespawner {
						amount = 15 * chg, time = 0.4*chg;
						texture = spritz:render();
						minpos = minnoz, maxpos = maxnoz;
						minvel = vector.new(0,0,0);
						maxvel = vector.new(0,-0.1,0);
						minacc = vector.new(0,-0.1,0);
						maxacc = vector.new(0,-0.13,0);
						minsize = 0.4, maxsize = 1;
						glow = 14; -- FIXME liquid glow prop
						minexptime = 0.5, maxexptime = 0.5;
						animation = {
							type = 'sheet_2d';
							frames_w = 14;
							frames_h = 1;
							frame_length = 0.5/14;
						}
					}
					minetest.after(0.2, function()
						minetest.add_particlespawner {
							amount = math.random(5,11) * chg, time = 0.45 * chg;
							texture = drop:render();
							minpos = vector.offset(minnoz, 0,-0.05,0);
							maxpos = vector.offset(maxnoz, 0,-0.05,0);
							minvel = vector.new(0,-0.1,0);
							maxvel = vector.new(0,-0.4,0);
							minacc = vector.new(0,-0.15,0);
							maxacc = vector.new(0,-0.18,0);
							minsize = 0.3, maxsize = 0.5;
							glow = 14; -- FIXME liquid glow prop
							minexptime = 1, maxexptime = 1.5;
							animation = {
								type = 'sheet_2d';
								frames_w = 10;
								frames_h = 1;
								frame_length = 1.5/10;
							}
						}
					end)

					return ItemStack {
						name = filled;
						count = stack:get_count();
					}
				end
			end

		end
	end;
})
