-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Functions that control and compute empire mining
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------


/*
 * Prepare for an update on empire mining settings
 * 
 * This function creates a temporary table mimicking the structure of
 * emp.mining_settings, and stores default settings into it.
 * 
 * Parameters:
 *		_empire_id		The empire's identifier
 *
 * Returns:
 *		?				True if the empire exists, false otherwise
 */
DROP FUNCTION IF EXISTS emp.mset_update_start( INT );
CREATE FUNCTION emp.mset_update_start( _empire_id INT )
		RETURNS BOOLEAN
		STRICT VOLATILE
		SECURITY DEFINER
	AS $mset_update_start$
BEGIN

	CREATE TEMPORARY TABLE mset_update(
		empire_id			INT ,
		resource_name_id	INT ,
		empmset_weight		INT
	) ON COMMIT DROP;

	INSERT INTO mset_update
		SELECT _mset.empire_id , _mset.resource_name_id , 2
			FROM emp.empires _empire
				INNER JOIN emp.mining_settings _mset
					ON _empire.name_id = _mset.empire_id
			WHERE _empire.name_id = _empire_id
			FOR SHARE OF _empire
			FOR UPDATE OF _mset;

	RETURN FOUND;

END;
$mset_update_start$ LANGUAGE PLPGSQL;

REVOKE EXECUTE
	ON FUNCTION emp.mset_update_start( INT )
	FROM PUBLIC;
GRANT EXECUTE
	ON FUNCTION emp.mset_update_start( INT )
	TO :dbuser;


/*
 * Prepare for an update on planet-specific mining settings
 * 
 * This function creates a temporary table mimicking the structure of
 * emp.planet_mining_settings, and stores default settings into it, using the
 * planet's list of resource provider as the source.
 * 
 * Parameters:
 *		_empire_id		The empire's identifier
 *		_planet_id		The planet's identifier
 *
 * Returns:
 *		?				True if the empire exists and owns the planet, false
 *							otherwise
 */
DROP FUNCTION IF EXISTS emp.mset_update_start( INT , INT );
CREATE FUNCTION emp.mset_update_start( _empire_id INT , _planet_id INT )
		RETURNS BOOLEAN
		STRICT VOLATILE
		SECURITY DEFINER
	AS $mset_update_start$
BEGIN

	CREATE TEMPORARY TABLE mset_update(
		empire_id			INT ,
		planet_id			INT ,
		resource_name_id	INT ,
		empmset_weight		INT
	) ON COMMIT DROP;
	
	PERFORM 1
		FROM emp.empires _empire
			INNER JOIN emp.planets _emp_planet
				ON _empire.name_id = _emp_planet.empire_id
			INNER JOIN verse.planets _planet
				ON _planet.name_id = _emp_planet.planet_id
			INNER JOIN verse.resource_providers _resprov
				ON _resprov.planet_id = _planet.name_id
		WHERE _empire.name_id = _empire_id
				AND _planet.name_id = _planet_id
		FOR SHARE OF _empire, _emp_planet , _planet , _resprov;
	IF NOT FOUND THEN
		RETURN FALSE;
	END IF;
	
	PERFORM 1
		FROM emp.planet_mining_settings
		WHERE empire_id = _empire_id AND planet_id = _planet_id
		FOR UPDATE;

	INSERT INTO mset_update
		SELECT _empire_id , _planet_id , resource_name_id , 2
			FROM verse.resource_providers
			WHERE planet_id = _planet_id;

	RETURN TRUE;

END;
$mset_update_start$ LANGUAGE PLPGSQL;

REVOKE EXECUTE
	ON FUNCTION emp.mset_update_start( INT , INT )
	FROM PUBLIC;
GRANT EXECUTE
	ON FUNCTION emp.mset_update_start( INT , INT )
	TO :dbuser;



/*
 * Update the weight of some resource
 * 
 * This function updates the weight of a resource in the temporary table. It
 * must be called after emp.mset_update_start() has initialised the table.
 *
 * Parameters:
 *		_resource_id		The resource's identifier
 *		_weight				The setting's new value
 *
 * Returns:
 *		?					True if the resource exists, false otherwise.
 */
DROP FUNCTION IF EXISTS emp.mset_update_set( INT , INT );
CREATE FUNCTION emp.mset_update_set( _resource_id INT , _weight INT )
		RETURNS BOOLEAN
		STRICT VOLATILE
		SECURITY DEFINER
	AS $mset_update_set$
BEGIN

	UPDATE mset_update
		SET empmset_weight = _weight
		WHERE resource_name_id = _resource_id;
	RETURN FOUND;

END;
$mset_update_set$ LANGUAGE PLPGSQL;


REVOKE EXECUTE
	ON FUNCTION emp.mset_update_set( INT , INT )
	FROM PUBLIC;
GRANT EXECUTE
	ON FUNCTION emp.mset_update_set( INT , INT )
	TO :dbuser;



/*
 * Apply a pending update to empire or planet mining settings
 * 
 * This function is called once mining settings (whether empire-wise or
 * planet-specific) have been uploaded. It will apply all changes to the
 * actual mining settings table.
 * 
 * Returns:
 *		?			True if the update was applied, false if one of the
 *						weights was invalid.
 */
DROP FUNCTION IF EXISTS emp.mset_update_apply( );
CREATE FUNCTION emp.mset_update_apply( )
		RETURNS BOOLEAN
		STRICT VOLATILE
		SECURITY DEFINER
	AS $mset_update_apply$

DECLARE
	_empire	INT;
	_planet	INT;

BEGIN
	BEGIN

		-- Get empire and planet identifier (will cause exception if this is
		-- not a planet settings update).
		SELECT INTO _empire , _planet
				empire_id , planet_id
			FROM mset_update
			LIMIT 1;

		DELETE FROM emp.planet_mining_settings
			WHERE empire_id = _empire AND planet_id = _planet;
		INSERT INTO emp.planet_mining_settings (
					empire_id , planet_id , resource_name_id ,
					emppmset_weight
			) SELECT empire_id , planet_id ,
					resource_name_id ,	empmset_weight
				FROM mset_update;

	EXCEPTION

		-- These are empire-wide settings
		WHEN undefined_column THEN
			UPDATE emp.mining_settings _settings
				SET empmset_weight = _update.empmset_weight
				FROM mset_update _update
				WHERE _update.empire_id = _settings.empire_id
					AND _update.resource_name_id = _settings.resource_name_id;
	END;
	RETURN TRUE;

EXCEPTION

	-- One of the weights was invalid
	WHEN check_violation THEN
		RETURN FALSE;

END;
$mset_update_apply$ LANGUAGE PLPGSQL;


REVOKE EXECUTE
	ON FUNCTION emp.mset_update_apply( )
	FROM PUBLIC;
GRANT EXECUTE
	ON FUNCTION emp.mset_update_apply( )
	TO :dbuser;