local lib = starlit.mod.lib
local W = starlit.world
local M = W.material

M.element.foreach('starlit:sort', {}, function(id, m)
	if m.metal then
		M.metal.link(id, {
			name = m.name;
			composition = starlit.type.fab{element = {[id] = 1}};
			color = m.color;
			-- n.b. this is a RATIO: it will be appropriately multiplied
			-- for the object in question; e.g a normal chunk will be
			-- 100 $element, an ingot will be 1000 $element
		})
	elseif m.gas then
		M.gas.link(id, {
			name = m.name;
			composition = starlit.type.fab{element = {[id] = 1}};
			density = m.density;
		})
	elseif m.liquid then
		M.liquid.link(id, {
			name = m.name;
			composition = starlit.type.fab{element = {[id] = 1}};
			density = m.density;
		})
	end
end)

local F = string.format

local function mkEltIndicator(composition)
	local indicator = ''
	local idx = 0
	local ccount = 0
	for _ in pairs(composition) do
		ccount = ccount + 1
	end
	local indsz,indpad = 28,4
	local ofs = math.min(11, (indsz-indpad)/ccount)
	for id, amt in pairs(composition) do
		idx = idx + 1
		indicator = indicator .. F(
			':%s,3=starlit-element-%s.png',
			(indsz-indpad) - (idx*ofs), id
		)
	end
	indicator = lib.image(indicator)
	return function(s)
		return string.format('(%s^[resize:%sx%s)^[combine:%sx%s%s',
			s,
			indsz, indsz,
			indsz, indsz,
			indicator);
	end
end

M.element.foreach('starlit:gen-forms', {}, function(id, m)
	local eltID = F('%s:element_%s', minetest.get_current_modname(), id)
	local eltName = F('Elemental %s', lib.str.capitalize(m.name))
	local tt = function(t, d, g)
		return starlit.ui.tooltip {
			title = t, desc = d;
			color = lib.color(0.1,0.2,0.1);
			props = {
				{title = 'Mass', desc = lib.math.si('g', g), affinity='info'}
			}
		}
	end
	local comp = {[id] = 1}
	local iblit = mkEltIndicator(comp)
	local function img(s)
		return iblit(s:colorize(m.color):render())
	end

	m.form = m.form or {}


	if not (m.gas or m.liquid) then
		local brickID = eltID .. '_brick'
		local brickName = F('%s Brick', lib.str.capitalize(m.name))
		m.form.brick = brickID
		minetest.register_craftitem(brickID, {
			short_description = brickName;
			description = tt(brickName, F('A small brick of %s, ready to be worked by a matter compiler', m.name), 1);
			inventory_image = img(lib.image 'starlit-item-brick.png');
			wield_image = lib.image 'starlit-item-brick.png':colorize(m.color):render();
			stack_max = 500;
			groups = {element=1, brick=1};
			_starlit = {
				mass = 1;
				material = {
					kind = 'element';
					element = id;
				};
				fab = starlit.type.fab {
					element = comp;
				};
			};
		});
	end

	--[[
	local chunk = F('starlit-element-%s-powder.png', id);
	minetest.register_craftitem(eltID, {
		short_description = eltName;
		description = tt(eltName, F('A 1g chunk of elemental %s, ready to be worked by a cold matter compiler', m.name), 1);
		inventory_image = iblit(chunk);
		wield_image = powder;
		stack_max = 1000; -- 1kg
		groups = {element = 1, chunk = 1};
		_starlit = {
			mass = 1;
			material = {
				kind = 'element';
				element = id;
			};
			fab = starlit.type.fab {
				element = comp;
			};
		};
	});
	]]
end)


M.metal.foreach('starlit:gen-forms', {}, function(id, m)
	local baseID = F('%s:metal_%s_', minetest.get_current_modname(), id)
	local ingotID = baseID .. 'ingot'
	local ingotName = F('%s Ingot', lib.str.capitalize(m.name))
	m.form = m.form or {}
	m.form.ingot = ingotID
	local tt = function(t, d, g)
		return starlit.ui.tooltip {
			title = t, desc = d;
			color = lib.color(0.1,0.1,0.1);
			props = {
				{title = 'Mass', desc = lib.math.si('g', g), affinity='info'}
			}
		}
	end
	local mcomp = m.composition:elementalize().element
	local function comp(n)
		local t = {}
		for id, amt in pairs(mcomp) do
			t[id] = amt * n
		end
		return t
	end
	local iblit = mkEltIndicator(mcomp)
	local function img(s)
		return iblit(s:colorize(m.color):render())
	end

	minetest.register_craftitem(ingotID, {
		short_description = ingotName;
		description = tt(ingotName, F('A solid ingot of %s, ready to be worked by a large matter compiler', m.name), 1e3);
		inventory_image = img(lib.image('starlit-item-ingot.png'));
		wield_image = lib.image 'starlit-item-ingot.png':colorize(m.color):render();
		groups = {metal = 1, ingot = 1};
		stack_max = 5;
		_starlit = {
			mass = 1e3;
			material = {
				kind = 'metal';
				metal = id;
			};
			fab = starlit.type.fab {
				flag = {smelt=true};
				element = comp(1e3);
			};
		};
	});


end)

local canisterMeta = lib.marshal.metaStore {
	contents = {key = 'starlit:canister_contents', type = starlit.store.volume};
}

local function canisterDesc(stack, def)
	def = def or stack:get_definition()._starlit.canister
	local props = {
		{title = 'Volume', affinity = 'info', desc = lib.math.si('L', def.vol,nil,nil,2)};
	};
	if stack then
	--[[
		local inv = starlit.item.container(stack)
		for i,e in ipairs(inv:list 'elem') do
			local comp = e:get_definition()._starlit.fab
			table.insert(props, {
				title = comp:formula();
				desc = lib.math.si('g', e:get_count());
				affinity = 'good';
			})
		end ]]
		local itemMeta = canisterMeta(stack)
		local e = itemMeta.read 'contents'
		local mass = lib.math.si('g', e.mass, nil, nil, 2)
		local mdef, meas
		if e.kind == 'liquid' then
			mdef = M.liquid.db[e.id]
			local vol =  lib.math.si('L', e.mass * mdef.density, nil, nil, 2)
			meas = string.format("%s %s (%s %s)", vol, mdef.name, e.mass, mdef.composition:formula())
		elseif e.kind == 'gas' then
			mdef = M.gas.db[e.id]
			meas = string.format("%s %s (%s)", mass, mdef.name, mdef.composition:formula())
		end
		local comp = def.composition
		table.insert(props, {
			title = meas;
			desc = mdef.desc;
			affinity = 'info';
		})
	end
	return starlit.ui.tooltip {
		title = def.name, desc = def.desc or 'A canister that can store a charge of gas or liquid';
		color = lib.color(0.2,0.1,0.1);
		props = props;
	};	
end

starlit.item.canister = lib.registry.mk 'starlit:canister';
starlit.item.canister.foreach('starlit:item-gen', {}, function(id, c)
	minetest.register_craftitem(id, {
		short_description = c.name;
		description = canisterDesc(nil, c);
		inventory_image = c.image or 'starlit-item-element-canister.png';
		groups = {canister = 1};
		stack_max = 1;
		_starlit = {
			canister = c;
			container = {
				handle = function(stack, oldstack)
					stack:get_meta():set_string('description', canisterDesc(stack))
					return stack
				end;
				list = {
					elem = {
						key = 'starlit:canister_elem';
						accept = 'powder';
						sz = c.slots;
					};
				};
			};
		};
	})
end)

function starlit.item.canister.contents(st)
	local m = canisterMeta(st)
	return m.read 'contents'
end

function starlit.item.canister.update(st)
	st:get_meta():set_string('description', canisterDesc(st))
end

function starlit.item.canister.replace(st, rec)
	local m = canisterMeta(st)
	m.write('contents', rec)
	starlit.item.canister.update(st)
end

function starlit.item.canister.empty(st, rec)
	local m = st:get_meta()
	m:set_string('starlit:canister_contents', '')
	m:set_string('description', '')
end

function starlit.item.canister.insert(st, rec)
	local m = canisterMeta(st)
	-- TODO
	starlit.item.canister.update(st)
end

-- starlit.item.canister.meta = canisterMeta