-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Functions that access system constants
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------



--
-- Creates or gets a constant category
--
-- Parameters:
--	ccnm	Constant category name
--
-- Returns:
--	the category's identifier
--

CREATE OR REPLACE FUNCTION sys.cog_constant_category( ccnm TEXT )
		RETURNS INT
		STRICT
		VOLATILE
		SECURITY INVOKER
	AS $$
DECLARE
	ccid	INT;
BEGIN
	BEGIN
		INSERT INTO sys.constant_categories (name)
			VALUES (ccnm)
			RETURNING id INTO ccid;
	EXCEPTION
		WHEN unique_violation THEN
			SELECT INTO ccid id FROM sys.constant_categories
				WHERE name = ccnm
				FOR UPDATE;
	END;
	
	RETURN ccid;
END;
$$ LANGUAGE plpgsql;



--
-- Creates or updates a constant with no boundaries
--
-- Parameters:
--	cnm		Constant name
--	cdesc	Constant description
--	ccnm	Constant category name
--	dval	Default value
--
-- Returns:
--	the constant's actual value
--

CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL )
		RETURNS REAL
		STRICT
		VOLATILE
		SECURITY DEFINER
	AS $$
DECLARE
	ccid	INT;
	occid	INT;
	cval	REAL;
BEGIN
	ccid := sys.cog_constant_category( ccnm );

	BEGIN
		INSERT INTO sys.constant_definitions( name , category_id , description , c_value )
			VALUES ( cnm , ccid , cdesc , dval );
		cval := dval;
	EXCEPTION
		WHEN unique_violation THEN
			SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions
				WHERE name = cnm
				FOR UPDATE;

			UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc ,
									min_value = NULL , max_value = NULL
				WHERE name = cnm;

			IF occid <> ccid THEN
			BEGIN
				DELETE FROM sys.constant_categories WHERE id = occid;
			EXCEPTION
				WHEN foreign_key_violation THEN
					-- Do nothing
			END; END IF;
	END;

	RETURN cval;
END;
$$ LANGUAGE plpgsql;

GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL ) TO :dbuser;



--
-- Creates or updates a constant with a single boundary
--
-- Parameters:
--	cnm		Constant name
--	cdesc	Constant description
--	ccnm	Constant category name
--	dval	Default value
--	bval	Bound value
--	ismin	Whether the bound value is the minimal or maximal value for the constant
--
-- Returns:
--	the constant's actual value
--

CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , bval REAL , ismin BOOLEAN )
		RETURNS REAL
		STRICT
		VOLATILE
		SECURITY DEFINER
	AS $$
DECLARE
	ccid	INT;
	occid	INT;
	cval	REAL;
	mival	REAL;
	maval	REAL;
BEGIN
	IF ismin THEN
		mival := bval;
		maval := NULL;
	ELSE
		maval := bval;
		mival := NULL;
	END IF;

	ccid := sys.cog_constant_category( ccnm );

	BEGIN
		INSERT INTO sys.constant_definitions( name , category_id , description , c_value , min_value , max_value )
			VALUES ( cnm , ccid , cdesc , dval , mival , maval );
		cval := dval;
	EXCEPTION
		WHEN unique_violation THEN
			SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions
				WHERE name = cnm
				FOR UPDATE;

			BEGIN
				UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc ,
										min_value = mival , max_value = maval
					WHERE name = cnm;
			EXCEPTION
				WHEN check_violation THEN
					UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc ,
											min_value = mival , max_value = maval , c_value = dval
						WHERE name = cnm;
					cval := dval;
			END;
					

			IF occid <> ccid THEN
			BEGIN
				DELETE FROM sys.constant_categories WHERE id = occid;
			EXCEPTION
				WHEN foreign_key_violation THEN
					-- Do nothing
			END; END IF;
	END;

	RETURN cval;
END;
$$ LANGUAGE plpgsql;

GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , BOOLEAN ) TO :dbuser;



--
-- Creates or updates a constant with both boundaries
--
-- Parameters:
--	cnm		Constant name
--	cdesc	Constant description
--	ccnm	Constant category name
--	dval	Default value
--	mival	Minimal value
--	maval	Maximal value
--
-- Returns:
--	the constant's actual value
--

CREATE OR REPLACE FUNCTION sys.uoc_constant( cnm TEXT , cdesc TEXT , ccnm TEXT , dval REAL , mival REAL , maval REAL )
		RETURNS REAL
		STRICT
		VOLATILE
		SECURITY DEFINER
	AS $$
DECLARE
	ccid	INT;
	occid	INT;
	cval	REAL;
BEGIN
	ccid := sys.cog_constant_category( ccnm );

	BEGIN
		INSERT INTO sys.constant_definitions( name , category_id , description , c_value , min_value , max_value )
			VALUES ( cnm , ccid , cdesc , dval , mival , maval );
		cval := dval;
	EXCEPTION
		WHEN unique_violation THEN
			SELECT INTO occid , cval category_id , c_value FROM sys.constant_definitions
				WHERE name = cnm
				FOR UPDATE;

			BEGIN
				UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc ,
										min_value = mival , max_value = maval
					WHERE name = cnm;
			EXCEPTION
				WHEN check_violation THEN
					UPDATE sys.constant_definitions SET category_id = ccid , description = cdesc ,
											min_value = mival , max_value = maval , c_value = dval
						WHERE name = cnm;
					cval := dval;
			END;
					

			IF occid <> ccid THEN
			BEGIN
				DELETE FROM sys.constant_categories WHERE id = occid;
			EXCEPTION
				WHEN foreign_key_violation THEN
					-- Do nothing
			END; END IF;
	END;

	RETURN cval;
END;
$$ LANGUAGE plpgsql;

GRANT EXECUTE ON FUNCTION sys.uoc_constant( TEXT , TEXT , TEXT , REAL , REAL , REAL ) TO :dbuser;



--
-- Updates a constant's value
--
-- Parameters:
--	cnm		Constant name
--	nval	New value
--	aid		Administrator attempting to update the constant
--
-- Returns:
--	TRUE on success, FALSE on failure
--

CREATE OR REPLACE FUNCTION sys.set_constant( cnm TEXT , nval REAL , aid INT )
		RETURNS BOOLEAN
		STRICT
		VOLATILE
		SECURITY DEFINER
	AS $$
DECLARE
	success	BOOLEAN;
BEGIN
	BEGIN
		UPDATE sys.constant_definitions SET c_value = nval
			WHERE name = cnm;
		success := FOUND;
	EXCEPTION
		WHEN check_violation THEN
			success := FALSE;
	END;
	
	PERFORM admin.write_log( aid , 'INFO'::log_level , 'Constant "' || cnm || '" changed to ' || nval );
	RETURN success;
END;
$$ LANGUAGE plpgsql;

GRANT EXECUTE ON FUNCTION sys.set_constant( TEXT , REAL , INT ) TO :dbuser;



--
-- Gets a constant's value
--
-- Parameters:
--	cnm		Constant name
--

CREATE OR REPLACE FUNCTION sys.get_constant( cnm TEXT )
	RETURNS REAL
	STRICT STABLE
	SECURITY DEFINER
AS $$
	SELECT c_value FROM sys.constant_definitions WHERE name = $1;
$$ LANGUAGE SQL;



--
-- Constants view
--

CREATE VIEW sys.constants_view
	AS SELECT cat.name AS category , cns.name AS name , cns.description AS description ,
				cns.c_value AS value , cns.min_value AS min , cns.max_value AS max
			FROM sys.constant_definitions cns
				INNER JOIN sys.constant_categories cat
					ON cat.id = cns.category_id
			ORDER BY cat.name , cns.name;

GRANT SELECT ON sys.constants_view TO :dbuser;
