-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Game updates - fleet arrivals
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------


CREATE OR REPLACE FUNCTION sys.process_fleet_arrivals_updates( c_tick BIGINT )
		RETURNS VOID
		STRICT VOLATILE
		SECURITY INVOKER
	AS $$
DECLARE
	rec		RECORD;
	lstat	BOOLEAN;
	f_ids	BIGINT[];
BEGIN
	-- Lock all records
	PERFORM 1
		FROM sys.updates su
			INNER JOIN verse.planets_updates vu
				USING ( update_id , updtype_id , updtgt_id )
			INNER JOIN verse.planets p
				USING ( name_id )
			INNER JOIN fleets.fleets f ON f.location_id = p.name_id
			INNER JOIN fleets.movements fm ON fm.fleet_id = f.id
			INNER JOIN emp.empires e ON e.name_id = f.owner_id
		WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
					AND f.status = 'AVAILABLE' AND fm.time_left = 1
		FOR UPDATE;

	-- Update attack status according to planet owners and enemy lists
	FOR rec IN SELECT ep.empire_id AS planet_owner , p.name_id AS planet ,
					f.owner_id AS fleet_owner , ( v.status = 'PROCESSED' AND b.id IS NULL ) AS on_vacation ,
					bool_or( f.attacking ) AS attacking
				FROM sys.updates su
					INNER JOIN verse.planets_updates vu
						USING ( update_id , updtype_id , updtgt_id )
					INNER JOIN verse.planets p
						USING ( name_id )
					INNER JOIN fleets.fleets f ON f.location_id = p.name_id
					INNER JOIN fleets.movements fm ON fm.fleet_id = f.id
					LEFT OUTER JOIN emp.planets ep ON ep.planet_id = p.name_id
					LEFT OUTER JOIN naming.empire_names en ON en.id = ep.empire_id
					LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id
					LEFT OUTER JOIN battles.battles b
						ON b.location_id = p.name_id AND b.last_tick IS NULL
				WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
						AND f.status = 'AVAILABLE' AND fm.time_left = 1
				GROUP BY p.name_id , ep.empire_id , f.owner_id , v.status , b.id
	LOOP
		-- Fleets owned by the planet's owner are never attacking, same for fleets arriving on
		-- planets that are on vacation
		IF rec.fleet_owner = rec.planet_owner OR rec.on_vacation THEN
			UPDATE fleets.fleets f SET attacking = FALSE
				FROM fleets.movements m
				WHERE f.status = 'AVAILABLE' AND f.owner_id = rec.fleet_owner
					AND f.location_id = rec.planet AND m.fleet_id = f.id AND m.time_left = 1;
			CONTINUE;
		END IF;

		-- Check enemy lists
		PERFORM * FROM emp.enemies
			WHERE empire = rec.planet_owner AND enemy = rec.fleet_owner;
		IF FOUND
		THEN
			-- Fleet owner in the planet owner's EL
			UPDATE fleets.fleets f SET attacking = TRUE
				FROM fleets.movements m
				WHERE f.status = 'AVAILABLE' AND f.owner_id = rec.fleet_owner
					AND f.location_id = rec.planet AND m.fleet_id = f.id AND m.time_left = 1;
			CONTINUE;
		END IF;

		-- If one of the arriving fleets is attacking, or if the local fleets are already attacking,
		-- then switch all local or arriving fleets to attack
		SELECT INTO lstat f.attacking
			FROM fleets.fleets f
				LEFT OUTER JOIN fleets.movements fm ON fm.fleet_id = f.id
			WHERE f.owner_id = rec.fleet_owner AND f.location_id = rec.planet AND fm IS NULL
			GROUP BY f.attacking;
		IF ( FOUND AND lstat ) OR rec.attacking
		THEN
			SELECT INTO f_ids array_agg( f.id ) FROM fleets.fleets f
				WHERE f.owner_id = rec.fleet_owner AND f.location_id = rec.planet;
			PERFORM fleets.set_mode( rec.fleet_owner , f_ids , TRUE );
			CONTINUE;
		END IF;
	END LOOP;
	
	-- Prepare fleet arrival events
	CREATE TEMPORARY TABLE fleet_arrivals(
		loc_id		INT ,
		loc_name	VARCHAR(20) ,
		own_id		INT ,
		own_name	VARCHAR(20) ,
		name		VARCHAR(64) ,
		power		BIGINT ,
		mode		BOOLEAN ,
		src_id		INT ,
		src_name	VARCHAR(20)
	);
	INSERT INTO fleet_arrivals
		SELECT f.location_id , ln.name , f.owner_id , fon.name ,
				f.name , fs.power , f.attacking , fm.source_id , sn.name
			FROM sys.updates su
					INNER JOIN verse.planets_updates vu
						USING ( update_id , updtype_id , updtgt_id )
					INNER JOIN verse.planets p
						USING ( name_id )
				INNER JOIN fleets.fleets f ON f.location_id = p.name_id
				INNER JOIN fleets.movements fm ON fm.fleet_id = f.id
				INNER JOIN fleets.stats_view fs ON fs.id = f.id
				INNER JOIN naming.empire_names fon ON fon.id = f.owner_id
				INNER JOIN naming.map_names ln ON ln.id = f.location_id
				INNER JOIN naming.map_names sn ON sn.id = fm.source_id
			WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
						AND f.status = 'AVAILABLE' AND fm.time_left = 1;

	-- Delete movement records, set redeployment penalties, update battles
	FOR rec IN SELECT f.id AS fleet , fs.flight_time AS flight_time ,
					f.attacking AS attacking , b.id AS battle ,
					f.location_id AS location
				FROM sys.updates su
					INNER JOIN verse.planets_updates vu
						USING ( update_id , updtype_id , updtgt_id )
					INNER JOIN verse.planets p
						USING ( name_id )
					INNER JOIN fleets.fleets f ON f.location_id = p.name_id
					INNER JOIN fleets.movements fm ON fm.fleet_id = f.id
					INNER JOIN fleets.stats_view fs ON fs.id = f.id
					LEFT OUTER JOIN battles.battles b
						ON b.location_id = p.name_id AND b.last_tick IS NULL 
				WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
							AND f.status = 'AVAILABLE' AND fm.time_left = 1
	LOOP
		DELETE FROM fleets.movements
			WHERE fleet_id = rec.fleet;
		UPDATE fleets.fleets
			SET status = 'REDEPLOYING' ,
				penalty = 1 + rec.flight_time * ( CASE WHEN rec.attacking THEN 40 ELSE 10 END )
			WHERE id = rec.fleet;

		-- Add fleets to battle (will not be executed if battle is NULL)
		PERFORM battles.add_fleet( rec.battle , rec.fleet , FALSE , c_tick );
	END LOOP;

	-- Send fleet arrival events
	PERFORM events.commit_fleet_arrivals( c_tick );
END;
$$ LANGUAGE plpgsql;


SELECT sys.register_update_type( 'Planets' , 'FleetArrivals' ,
		'Fleets which were one update away are arriving at their destinations.' ,
		'process_fleet_arrivals_updates'
	);