/*

oolite-nova-mission.js

Script for nova mission.


Oolite
Copyright © 2004-2013 Giles C Williams and contributors

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.

*/


/*jslint white: true, undef: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
/*global Timer, expandDescription, galaxyNumber, guiScreen, mission, missionVariables, player, system*/


"use strict";


this.name			= "oolite-nova";
this.author			= "Eric Walch, Jens Ayton, Kaks";
this.copyright		= "© 2008-2013 the Oolite team.";


this._endTheMission = function ()
{
	missionVariables.nova = "NOVA_HERO";  // even if not a hero, other scripts expect this string at mission end.
	mission.setInstructions(null);
	this._cleanUp();
};


this._cleanUp = function ()
{
	// mission is over, we don't need most of the event handlers.
	// this.shipExitedWitchspace is still needed after the nova mission.
	delete this.shipWillEnterWitchspace;
	delete this.shipWillExitWitchspace;
	delete this.systemWillPopulate;
	delete this.missionScreenOpportunity;
	delete this.shipLaunchedEscapePod;
	delete this.shipLaunchedFromStation;
};


// used when player enters nova system during nova mission.
this._sendShipsAwayForMission = function ()
{
	if (missionVariables.nova !== "TWO_HRS_TO_ZERO")
	{
		this.novaMissionTimer.stop();
	}
	else
	{
		system.sendAllShipsAway();
		if (!this.buoyLoaded)
		{
			this.witchBuoy = system.shipsWithPrimaryRole("buoy-witchpoint")[0];
			this.buoyLoaded = true;
		}
		if (this.witchBuoy && this.witchBuoy.isValid)
		{
			this.witchBuoy.commsMessage(expandDescription("[oolite-nova-distress-call]"));
		}
	}
};


// used when player enters nova system after nova mission.
this._sendShipsAway = function ()
{
	if (!system.sun.hasGoneNova)
	{
		this.novaTimer.stop();
		return;
	}
	else
	{
		system.sendAllShipsAway();
	}
};


// Destroy all stations (and carriers) in the system. If we just blow up the
// main one, the player can eject, be rescued and buy fuel without triggering
// the escape pod failure state.
this._blowUpAllStations = function ()
{
	system.filteredEntities(this, function (entity)
	{
		if (entity.isStation)
		{
			entity.explode();
		}
	});
};


this._flareUp = function ()
{
	system.info.corona_hues = 1;
	// This flare up (0.3 to 0.5 flare) will last between 10 and 30 seconds
	this._flareTarget = 0.3 + Math.random() * 0.2;
	this._flareCallback = addFrameCallback(this._flareTransition.bind(this));
	this._flareChange(this._flareDown, Math.random() * 20 + 10);
};


this._flareDown = function ()
{
	system.info.corona_hues = 0.8;
	// This quiet moment (0.1 to 0.25 flare) will last between 30 seconds and 2 minutes
	this._flareTarget = 0.1 + Math.random() * 0.15;
	this._flareCallback = addFrameCallback(this._flareTransition.bind(this));
	this._flareChange(this._flareUp, Math.random() * 90 + 30);
};


this._flareChange = function (callFunc, callDelay)
{
	this.flareTimer.stop();
	delete this.flareTimer;
	this.flareTimer = new Timer(this, callFunc, callDelay);
};


this._flareTransition = function(delta)
{
		var current = system.info.corona_flare;
		if (current < this._flareTarget)
		{
				current += delta/10;
		}
		else
		{
				current -= delta/10;
		}
		system.info.corona_flare = current;
		if (this._flareTarget > 0.275 && current > this._flareTarget)
		{
				removeFrameCallback(this._flareCallback);
				delete this._flareCallback;
		}
		else if (this._flareTarget < 0.275 && current < this._flareTarget)
		{
				removeFrameCallback(this._flareCallback);
				delete this._flareCallback;
		}
}

/**** Event handlers ****/

this.startUp = function ()
{
	// Remove all event handlers once the mission is over.
	if (missionVariables.nova === "NOVA_HERO")
	{
		this._cleanUp();
	}
	delete this.startUp;
};


this.missionScreenOpportunity = function ()
{
	if (!player.ship.docked)
	{
		return;
	}
	
	function choiceEvaluation(choice)
	{
		if (choice === "YES")
		{
			player.ship.useSpecialCargo(expandDescription("[oolite-nova-refugees]"));
			mission.setInstructionsKey("oolite_nova_info");
			missionVariables.nova = "NOVA_ESCAPE_HERO";
			player.ship.launch();
			this._blowUpAllStations();
			system.sun.goNova(30);
		}
		else
		{
			// choice == "NO", or null when player launched without making a choice.
			missionVariables.nova = "NOVA_ESCAPE_COWARD";
			player.commsMessage(expandDescription("[oolite-nova-coward]"), 4.5);
			system.sun.goNova(9);	// barely enough time to jump out of the system.
		}
		missionVariables.novacount = null;
	}
	
	if (player.ship.dockedStation.isMainStation)
	{
		if (galaxyNumber === 3)
		{
			if (!missionVariables.nova && !missionVariables.novacount)
			{
				missionVariables.novacount = 0;
			}
			if (missionVariables.nova === "TWO_HRS_TO_ZERO")
			{
				mission.runScreen({
					titleKey: "oolite_nova_title",
					messageKey: "oolite_nova_brief",
					background: "solar.png",
					choicesKey: "oolite_nova_yesno",
					screenID: "oolite-nova-briefing"
				},
				choiceEvaluation);
				
				this.novaMissionTimer.stop();
			}
		}
		if (galaxyNumber === 3 || galaxyNumber === 4)
		{
			if (missionVariables.nova === "NOVA_ESCAPED_SYSTEM")
			{
				player.ship.removeAllCargo();
				mission.runScreen({
					titleKey: "oolite_nova_title",
					messageKey: "oolite_nova_hero",
					background: "solar.png",
					screenID: "oolite-nova-hero"
				});
				player.ship.manifest["gem_stones"] += 100;
				this._endTheMission();
			}
			else if (missionVariables.nova === "NOVA_ESCAPE_POD")
			{
				player.ship.removeAllCargo();  // can only be done while docked.
				mission.runScreen(
				{
					titleKey: "oolite_nova_title",
					messageKey: "oolite_nova_disappointed",
					background: "solar.png",
					screenID: "oolite-nova-disappointed"
				});
				this._endTheMission();
			}
			else if (missionVariables.nova === "NOVA_ESCAPE_OTHER")
			{
				mission.runScreen({
					titleKey: "oolite_nova_title",
					messageKey: "oolite_nova_ignored",
					background: "solar.png",
					screenID: "oolite-nova-ignored"
				});
				this._endTheMission();
			}
			else if (missionVariables.nova === "NOVA_ESCAPE_COWARD" && !system.sun.isGoingNova && !system.sun.hasGoneNova)
			{
				player.decreaseContractReputation();
				player.decreasePassengerReputation();
				mission.runScreen({
					titleKey: "oolite_nova_title",
					messageKey: "oolite_nova_disappointed",
					background: "solar.png",
					screenID: "oolite-nova-coward"
				});
				this._endTheMission();
			}
		}
	}
	else if (missionVariables.nova === "TWO_HRS_TO_ZERO")
	{
		// this is the the nova system, but not the main station.
		player.ship.launch();
		player.commsMessage(expandDescription("[oolite-nova-visit-main]"));
	}
};


this.shipLaunchedEscapePod = function ()
{
	if (missionVariables.nova === "NOVA_ESCAPED_SYSTEM")
	{
		missionVariables.nova = "NOVA_ESCAPE_POD";
	}
};


this.shipWillEnterWitchspace = function ()
{
	if (this.willGoNova)
	{
		system.info.sun_gone_nova = true;
		system.info.sun_radius = this._novaRadius;
		system.info.corona_flare = 0.3;
		system.info.corona_hues = 0.05;
		delete this.willGoNova;
		delete this._novaRadius;
		// did the player leave the nova system without docking at the main station?
		if (missionVariables.nova === "TWO_HRS_TO_ZERO")
		{
			missionVariables.nova = "NOVA_ESCAPE_OTHER";
		}
	}
};


this.shipWillExitWitchspace = function ()  
{
	if (missionVariables.nova === "NOVA_ESCAPE_HERO")
	{
		missionVariables.nova = "NOVA_ESCAPED_SYSTEM";
	}
	else if (missionVariables.nova === "TWO_HRS_TO_ZERO")
	{
		// the populator has started the nova mission
		player.ship.fuelLeakRate = 25;
		this.willGoNova = true;
		this._novaRadius = system.sun.radius + 600000;
		player.consoleMessage(expandDescription("[danger-fuel-leak]"), 4.5);
		this.buoyLoaded = false;  // w-bouy is not in system yet.
		if (this.novaMissionTimer)
		{
			this.novaMissionTimer.start();
		}
		else
		{
			this.novaMissionTimer = new Timer(this, this._sendShipsAwayForMission, 5, 30);
		}
	}
};


this.systemWillPopulate = function() // call this as soon as possible so other scripts can see it will go nova.
{
	// make sure we don't increment the count when reloading a savegame
	if (!missionVariables.nova && galaxyNumber === 3 && player.ship.status != "STATUS_DOCKED")
	{
		if (missionVariables.novacount !== null) // " !== undefined" always returns true for missionVariables!
		{
			missionVariables.novacount++;
		}
		if (player.ship.equipmentStatus("EQ_GAL_DRIVE") === "EQUIPMENT_OK" && missionVariables.novacount > 3 && !missionVariables.nova && !system.isInterstellarSpace)
		{
			missionVariables.nova = "TWO_HRS_TO_ZERO";
			system.sun.goNova(7200);
			if (system.info.corona_flare < 0.15) {
				system.info.corona_flare = 0.15;
			}
			/* the main populator script might have run first. If so, remove
			 * the ships it added. If it runs after, it'll notice the
			 * impending nova and not add these lines in the first place */
			var populator = system.populatorSettings;
			var keys = Object.keys(populator);
			var key;
			while (key = keys.shift())
			{
				if (key.match(/^oolite-/) && populator[key].priority > 20)
				{
					// remove it
					system.setPopulator(key,null);
				}
			}

		}
	}
}

this.shipLaunchedFromStation = function ()
{
	if (system.sun && (system.sun.isGoingNova || system.sun.hasGoneNova) && missionVariables.nova === "NOVA_ESCAPE_COWARD")
	{
		this._blowUpAllStations();
	}
};


this.shipExitedWitchspace = function ()
{
	if (system.sun)
	{
		if (this.flareTimer)
		{
			this.flareTimer.stop();
			delete this.flareTimer;
		}
		if (this._flareCallback)
		{
				removeFrameCallback(this._flareCallback);
				delete this._flareCallback;
		}

		if (system.sun.isGoingNova || system.sun.hasGoneNova)
		{
			if (this.novaTimer)
			{
				this.novaTimer.start();
			}
			else
			{
				this.novaTimer = new Timer(this, this._sendShipsAway, 5, 60);
			}
		}
		if (system.sun.isGoingNova) 
		{
			// The first flare up will begin in between 30 seconds and 1 minute.
			this.flareTimer = new Timer(this, this._flareUp,  Math.random() * 30 + 30);
		}
	}
};
