/*
 * This is a primitive initial attempt at an AI player.
 * The design isn't great and maybe the whole thing should be rewritten -
 * the aim here is just to have something that basically works, and to
 * learn more about what's really needed for a decent AI design.
 *
 * The basic idea is we have a collection of independent modules
 * (EconomyManager, etc) which produce a list of plans.
 * The modules are mostly stateless - each turn they look at the current
 * world state, and produce some plans that will improve the state.
 * E.g. if there's too few worker units, they'll do a plan to train
 * another one. Plans are discarded after the current turn, if they
 * haven't been executed.
 *
 * Plans are grouped into a small number of PlanGroups, and for each
 * group we try to execute the highest-priority plans.
 * If some plan groups need more resources to execute their highest-priority
 * plan, we'll distribute any unallocated resources to that group's
 * escrow account. Eventually they'll accumulate enough to afford their plan.
 * (The purpose is to ensure resources are shared fairly between all the
 * plan groups - none of them should be starved even if they're trying to
 * execute a really expensive plan.)
 */

/*
 * Lots of things we should fix:
 *
 *  * Find entities with no assigned role, and give them something to do
 *  * Keep some units back for defence
 *  * Consistent terminology (type vs template etc)
 *  * ...
 *
 */


function JuBotAI(settings)
{
//	warn("Constructing JuBotAI for player "+settings.player);

	BaseAI.call(this, settings);

	this.turn = 0;

	this.modules = [
		new EconomyManager(),
		new MilitaryAttackManager(),
	];

	this.planGroups = {
		economyPersonnel: new PlanGroup(),
		economyConstruction: new PlanGroup(),
		militaryPersonnel: new PlanGroup(),
	};
}

JuBotAI.prototype = new BaseAI();

JuBotAI.prototype.ShareResources = function(remainingResources, unaffordablePlans)
{
	// Share our remaining resources among the plangroups that need
	// to accumulate more resources, in proportion to their priorities

	for each (var type in remainingResources.types)
	{
		// Skip resource types where we don't have any spare
		if (remainingResources[type] <= 0)
			continue;

		// Find the plans that require some of this resource type,
		// and the sum of their priorities
		var ps = [];
		var sumPriority = 0;
		for each (var p in unaffordablePlans)
		{
			if (p.plan.getCost()[type] > p.group.getEscrow()[type])
			{
				ps.push(p);
				sumPriority += p.priority;
			}
		}

		// Avoid divisions-by-zero
		if (!sumPriority)
			continue;

		// Share resources by priority, clamped to the amount the plan actually needs
		for each (var p in ps)
		{
			var amount = Math.floor(remainingResources[type] * p.priority / sumPriority);
			var max = p.plan.getCost()[type] - p.group.getEscrow()[type];
			p.group.getEscrow()[type] += Math.min(max, amount);
		}
	}
};

JuBotAI.prototype.OnUpdate = function()
{
	// Run the update every n turns, offset depending on player ID to balance the load
	if ((this.turn + this.player) % 4 == 0)
	{
		var gameState = new GameState(this);

		// Find the resources we have this turn that haven't already
		// been allocated to an escrow account.
		// (We need to do this before executing any plans, because those will
		// distort the escrow figures.)
		var remainingResources = gameState.getResources();
		for each (var planGroup in this.planGroups)
			remainingResources.subtract(planGroup.getEscrow());

		Engine.ProfileStart("plan setup");

		// Compute plans from each module
		for each (var module in this.modules)
			module.update(gameState, this.planGroups);

//		print(uneval(this.planGroups)+"\n");

		Engine.ProfileStop();
		Engine.ProfileStart("plan execute");

		// Execute as many plans as possible, and keep a record of
		// which ones we can't afford yet
		var unaffordablePlans = [];
		for each (var planGroup in this.planGroups)
		{
			var plan = planGroup.executePlans(gameState, this.modules);
			if (plan)
				unaffordablePlans.push({"group": planGroup, "priority": plan.priority, "plan": plan.plan});
		}

		Engine.ProfileStop();

		this.ShareResources(remainingResources, unaffordablePlans);

//		print(uneval(this.planGroups)+"\n");

		// Reset the temporary plan data
		for each (var planGroup in this.planGroups)
			planGroup.resetPlans();
	}
//	if (this.turn == 0){
//		this.chat("Good morning. Please prepare for annihilation. Jubal apologises for any inconvenience likely to be caused by your imminent demise.");
//		}
	this.turn++;
};
