local modes = {
	off   = {next = 'stop';  power = 0};
	stop  = {next = 'slow';  power = 0.4; factor =  0;    color = {255,126,113}};
	slow  = {next = 'lift';  power = 0.2; factor =  0.5;  color = {255,255,100}};
	lift  = {next = 'crush'; power = 0.6; factor = -0.25; color = {113,255,126}};
	crush = {next = 'off';   power = 1;   factor =  2;    color = {113,126,255}};
}
for kind, p in pairs(modes) do
	local radius = 4
	local enoughpower = function(pos,mode)
		if mode and modes[mode] == nil then return false end
		local n = modes[mode or kind]
		local l = sorcery.ley.netcaps(pos,1,nil,n.power)
		local maxfree = l.self.powerdraw + l.freepower
		return maxfree >= n.power
	end
	local setmeta = function(pos,nextmode)
		local label = 'Gravitator'
		if nextmode ~= 'off' then
			label = label .. ' (' .. nextmode .. ')'
			minetest.get_node_timer(pos):start(4)
		end
		local meta = minetest.get_meta(pos)
		meta:set_string('infotext',label)
	end
	minetest.register_node('sorcery:gravitator_' .. kind, {
		description = 'Gravitator';
		drop = 'sorcery:gravitator_off';
		paramtype2 = 'facedir';
		groups = {
			cracky = 2;
			sorcery_magitech = 1;
			sorcery_ley_device = 1;

			effect_trigger = (kind == 'off') and 0 or 1;
		};
		tiles = {
			'sorcery_gravitator_side.png';
			'sorcery_gravitator_side.png';
			'sorcery_gravitator_side.png';
			'sorcery_gravitator_side.png';
			'sorcery_gravitator_side.png';
			'sorcery_gravitator_panel_'..kind..'.png';
		};
		effect_near = p.factor and {
			impacts = {
				gravity = p.factor;
			};
			distance = radius;
			spread = 1.5;
		} or nil;
		_sorcery = {
			ley = {
				mode = 'consume', affinity = {'counterpraxic'};
				power = p.power;
			};
			on_leychange = function(pos)
				local meta = minetest.get_meta(pos)
				if kind ~= 'off' then
					if not enoughpower(pos) then
						local old = minetest.get_node(pos)
						old.name = 'sorcery:gravitator_off'
						minetest.swap_node(pos,old)
						meta:set_string('lastmode',kind)
						setmeta(pos,'off')
					end
				elseif meta:contains('lastmode') then
					local nm = meta:get_string('lastmode')
					if enoughpower(pos,nm) then
						local old = minetest.get_node(pos)
						old.name = 'sorcery:gravitator_' .. nm
						minetest.set_node(pos,old)
						setmeta(pos,nm)
					end
				end
			end;
		};
		on_construct = function(pos)
			setmeta(pos,'off')
		end;
		on_timer = function(pos)
			if p.color == nil then return false end

			local vee = {x=0,y=-1,z=0};
			minetest.add_particlespawner {
				amount = 128;
				time = 4;
				minpos = vector.subtract(pos,radius);
				maxpos = vector.add(pos,radius);
				minvel = vector.multiply(vee, p.factor*0.5);
				maxvel = vector.multiply(vee, p.factor);
				minexptime = 1;
				maxexptime = 1.3;
				minsize = 0.2, maxsize = 1.4;
				glow = 12;
				texture = sorcery.lib.image('sorcery_spark.png'):multiply(sorcery.lib.color(p.color)):render();
				animation = {
					type = 'vertical_frames';
					aspect_w = 16, aspect_h = 16;
					length = 1.4;
				}
			}
			return true;
		end;
		on_rightclick = function(pos)
			minetest.sound_play('doors_steel_door_open', {
				gain = 0.6;
				pos = pos;
			}, true)
			
			local nextmode = p.next
			while true do
				local nm = modes[nextmode]
				if nm.power == 0 then break end
				if nm.power <= p.power then break end
				if enoughpower(pos,nextmode) then break end
				nextmode = nm.next
			end

			local old = minetest.get_node(pos)
			minetest.set_node(pos, {
				name = 'sorcery:gravitator_' .. nextmode;
				param1 = old.param1;
				param2 = old.param2;
			})

			setmeta(pos,nextmode)
		end;
	})
end
