-- LegacyWorlds Beta 6
-- PostgreSQL database scripts
--
-- Game updates - buildings construction and destruction
--
-- Copyright(C) 2004-2010, DeepClone Development
-- --------------------------------------------------------


CREATE OR REPLACE FUNCTION sys.process_planet_construction_updates( c_tick BIGINT )
		RETURNS VOID
		STRICT VOLATILE
		SECURITY INVOKER
	AS $$
DECLARE
	rec			RECORD;
	wu_per_pop	REAL;
	dest_work	REAL;
	dest_rec	REAL;
	cur_empire	INT;
	cur_cash	REAL;
	cur_planet	INT;
	p_finished	BOOLEAN;
	cur_wus		REAL;
	cur_acc_c	REAL;
	n_found		INT;
	n_removed	INT;
	i_work		REAL;
	i_cost		REAL;
	can_do		REAL;
	must_do		INT;
BEGIN
	-- Get constants
	wu_per_pop := sys.get_constant( 'game.work.wuPerPopUnit' );
	dest_work := sys.get_constant( 'game.work.destructionWork' );
	dest_rec := - sys.get_constant( 'game.work.destructionRecovery' );

	-- Enter update loop
	cur_empire := NULL;
	cur_planet := NULL;
	FOR rec IN SELECT p.name_id AS id , p.population AS pop ,
					( ph.current / p.population )::REAL AS happiness ,
					e.name_id AS owner , e.cash AS cash ,
					q.money AS acc_cash , q.work AS acc_work ,
					qi.queue_order AS qorder , qi.amount AS amount ,
					qi.destroy AS destroy , qi.building_id AS building ,
					b.work AS req_work , b.cost AS req_cost
				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 emp.planets ep ON ep.planet_id = p.name_id
					INNER JOIN emp.empires e ON e.name_id = ep.empire_id
					INNER JOIN verse.planet_happiness ph ON ph.planet_id = p.name_id
					INNER JOIN verse.bld_queues q ON q.planet_id = p.name_id
					INNER JOIN verse.bld_items qi ON qi.queue_id = q.planet_id
					INNER JOIN tech.buildables b ON b.name_id = qi.building_id
					INNER JOIN naming.empire_names en ON en.id = e.name_id
					LEFT OUTER JOIN users.vacations v ON v.account_id = en.owner_id
				WHERE su.update_last = c_tick AND su.update_state = 'PROCESSING'
					AND ( v.account_id IS NULL OR v.status <> 'PROCESSED' )
				ORDER BY e.name_id , p.name_id , qi.queue_order
				FOR UPDATE OF p , e , q , qi
	LOOP
		-- Update accumulated work and money for the previous planet
		IF cur_planet IS NOT NULL AND cur_planet <> rec.id THEN
			IF n_found = n_removed THEN
				cur_wus := 0;
				cur_acc_c := 0;
				PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick );
			END IF;

			UPDATE verse.bld_queues
				SET money = cur_acc_c , work = cur_wus
				WHERE planet_id = cur_planet;
			cur_cash := cur_cash - cur_acc_c;
			
			IF cur_cash < 0 THEN
				cur_cash := 0;
			END IF;

			cur_planet := NULL;
		END IF;

		-- Update cash of the previous empire
		IF cur_empire IS NOT NULL AND cur_empire <> rec.owner
		THEN
			UPDATE emp.empires SET cash = cur_cash
				WHERE name_id = cur_empire;
			cur_empire := NULL;
		END IF;

		-- If this is the first record or if the empire changed...
		IF cur_empire IS NULL THEN
			cur_empire := rec.owner;
			cur_cash := rec.cash;
		END IF;
		
		-- If this is the first record or if the planet changed...
		IF cur_planet IS NULL THEN
			cur_planet := rec.id;
			cur_cash := cur_cash + rec.acc_cash;
			cur_wus := rec.acc_work + verse.adjust_production(
				( rec.pop * wu_per_pop )::REAL ,
				rec.happiness
			);
			n_found := 1;
			n_removed := 0;
			cur_acc_c := 0;
			p_finished := FALSE;
		ELSE
			n_found := n_found + 1;
		END IF;

		-- If we're done updating this planet but there were more items...
		IF p_finished THEN
			IF n_removed > 0 THEN
				UPDATE verse.bld_items
					SET queue_order = rec.qorder - n_removed
					WHERE queue_order = rec.qorder AND queue_id = rec.id;
			END IF;
			CONTINUE;
		END IF;

		-- Compute the actual cost and required work of the item
		i_cost := rec.req_cost * ( CASE WHEN rec.destroy THEN dest_rec ELSE 1.0 END );
		i_work := rec.req_work * ( CASE WHEN rec.destroy THEN dest_work ELSE 1.0 END );
		
		-- Compute how many items can be completed
		can_do := cur_wus / i_work;
		IF i_cost > 0 AND cur_cash / i_cost < can_do THEN
			can_do := cur_cash / i_cost;
			cur_wus := i_work * can_do;
		END IF;

		-- If we can't build anything at this point...
		IF can_do < 1 THEN
			-- Set accumulated cash
			IF i_cost > 0 THEN
				cur_acc_c := can_do * i_cost;
			END IF;

			-- Still update queue item if some items were removed
			IF n_removed > 0 THEN
				UPDATE verse.bld_items
					SET queue_order = rec.qorder - n_removed
					WHERE queue_order = rec.qorder AND queue_id = rec.id;
			END IF;

			-- Done with this planet
			p_finished := TRUE;
			CONTINUE;
		END IF;

		-- Compute how many actual items can be built
		must_do := floor( can_do );
		IF must_do >= rec.amount THEN
			must_do := rec.amount;
			can_do := 0;
			n_removed := n_removed + 1;
		END IF;

		-- Handle construction / destruction
		IF rec.destroy THEN
			must_do := verse.do_destroy_buildings( rec.id , rec.building , must_do );
			PERFORM battles.remove_buildings( rec.id , rec.building , must_do , FALSE , c_tick + 1 );
		ELSE
			PERFORM verse.do_construct_buildings( rec.id , rec.building , must_do );
			PERFORM battles.add_buildings( rec.id , rec.building , must_do , c_tick + 1 );
		END IF;
		cur_cash := cur_cash - must_do * i_cost;
		cur_wus := cur_wus - must_do * i_work;

		-- Check whether we're done with this queue
		IF rec.qorder < n_removed THEN
			-- Delete queue item
			DELETE FROM verse.bld_items
				WHERE queue_order = rec.qorder AND queue_id = rec.id;
		ELSE
			-- Update queue item
			UPDATE verse.bld_items
				SET queue_order = queue_order - n_removed ,
					amount = amount - floor( can_do )
				WHERE queue_order = rec.qorder AND queue_id = rec.id;

			-- Set accumulated cash
			IF i_cost > 0 THEN
				cur_acc_c := ( can_do - floor( can_do ) ) * i_cost;
			END IF;

			p_finished := TRUE;
		END IF;
	END LOOP;

	-- If a planet was being procesed, update it and the empire
	IF cur_planet IS NOT NULL THEN
		IF n_found = n_removed THEN
			cur_wus := 0;
			cur_acc_c := 0;
			PERFORM events.empty_queue_events( cur_empire , cur_planet , FALSE , c_tick );
		END IF;

		UPDATE verse.bld_queues
			SET money = cur_acc_c , work = cur_wus
			WHERE planet_id = cur_planet;
		cur_cash := cur_cash - cur_acc_c;

		IF cur_cash < 0 THEN
			cur_cash := 0;
		END IF;

		UPDATE emp.empires SET cash = cur_cash
			WHERE name_id = cur_empire;
		cur_empire := NULL;
	END IF;
END;
$$ LANGUAGE plpgsql;

SELECT sys.register_update_type( 'Planets' , 'CivilianConstruction' ,
		'Civilian build queues are being processed.' ,
		'process_planet_construction_updates'
	);