"use strict";
this.name = "ShipConfiguration_HeatSink";
this.author = "phkb";
this.copyright = "2016 phkb";
this.description = "Activation and control script for heat sink usage.";
this.licence = "CC BY-NC-SA 3.0";

this._mode = 0; // current mode of heat sinks (0 = manual, 1 = auto)
this._warnPlayerOfHeat = true; // flag to indicate that player will be reminder of dangerous heat levels
this._controlMode = 0; // control mode: 0 = normal (ie primable equipment), 1 = passive
this._tempCheck = null; // timer to do automatic heat level checks for heat sink deployment
this._amountToDump = 0.5; // max percentage of heat to be dumped (reduced by ship mass)
this._menuColor = "orangeColor"; // color of general menu items
this._itemColor = "yellowColor"; // color of special menu items (eg exit menu items)
this._disabledColor = "darkGrayColor"; // color of disabled equipment items
this._lastChoice = ""; // last selection on the config screen
//this._hsTimer = null;					// timer to monitor items in the hsDeployed array to automatically explode deployed heat sinks
this._fcbID = 0; // frame callback ID for heat control
this._heatWarning = null; // timer for informing the player of critical heat levels
this._warning1 = false;
this._warning2 = false;
this._warning3 = false;
this._warningPoint1 = 0.70;
this._warningPoint2 = 0.80;
this._warningPoint3 = 0.90;

//-------------------------------------------------------------------------------------------------------------
this.activated = function () {
	var p = player.ship;
	if (p.equipmentStatus("EQ_HEAT_SINK_CONTROL") === "EQUIPMENT_OK" || p.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") === "EQUIPMENT_OK") {
		// ok we're ready to dump
		var sc = worldScripts.ShipConfiguration_Core;
		// how much will we be dumping
		var dumpAmount = this._amountToDump * (1 - (sc.$getShipMass(p) / 500000));
		// ensure we will always have something to dump, even if it's only a little bit
		if (dumpAmount < 0.1) dumpAmount = 0.1;
		// is this actually worth it?
		if ((p.temperature - dumpAmount) < (0.234375 + (p.script._busOverload / 100))) {
			player.consoleMessage(expandDescription("[sc_heatsink_not_required]"));
			return;
		}
		sc.$playSound("deploy_heat_sink");
		worldScripts.ShipConfiguration_HeatSink.$deployHeatSink(player.ship);
		var hs = p.equipmentStatus("EQ_HEAT_SINK", true)["EQUIPMENT_OK"];
		// smaller ships will dump a larger percentage of heat
		//p.temperature -= dumpAmount;
		player.consoleMessage(expandDescription("[sc_heatsink_deployed]", {remain: hs }));
	} else {
		player.consoleMessage(expandDescription("[sc_heatsink_broken]"));
	}
}

//-------------------------------------------------------------------------------------------------------------
this.mode = function () {
	var p = player.ship;
	if (p.equipmentStatus("EQ_HEAT_SINK_CONTROL") === "EQUIPMENT_OK" || p.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") === "EQUIPMENT_OK") {
		var hs = worldScripts.ShipConfiguration_HeatSink;
		if (hs._mode === 0) {
			hs._mode = 1;
			player.consoleMessage(expandDescription("[sc_heatsink_automatic]"));
			hs._tempCheck = new Timer(hs, hs.$checkShipTemp, 3, 3);
		} else {
			hs._mode = 0;
			player.consoleMessage(expandDescription("[sc_heatsink_manual]"));
			if (hs._tempCheck && hs._tempCheck.isRunning) hs._tempCheck.stop();
		}
	} else {
		player.consoleMessage(expandDescription("[sc_heatsink_broken_mode]"));
	}
}

//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
	var sc = worldScripts.ShipConfiguration_Core;
	if (sc._disabled) {
		delete this.shipWillDockWithStation;
		delete this.shipDied;
		delete this.shipLaunchedFromStation;
		delete this.playerWillSaveGame;
		delete this.equipmentRemoved;
		delete this.playerBoughtEquipment;
		delete this.startUpComplete;
		return;
	}

	if (missionVariables.ShipConfig_HeatSinkMode) this._mode = parseInt(missionVariables.ShipConfig_HeatSinkMode);
	if (missionVariables.ShipConfig_HeatSinkControl) this._controlMode = parseInt(missionVariables.ShipControl_HeatSinkControl);

	this.$checkOutOfSyncMode();

	this.$initInterface(player.ship.dockedStation);
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function (station) {
	this.$stopTimers();
	this.$checkOutOfSyncMode();
}

//-------------------------------------------------------------------------------------------------------------
this.shipDied = function (whom, why) {
	this.$stopTimers();
}

//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation = function (station) {
	var sc = worldScripts.ShipConfiguration_Core;
	if (sc._heatControl === true) {
		// if we're in active mode, start a timer to check the temp now
		if (this._mode === 1) this._tempCheck = new Timer(this, this.$checkShipTemp, 2, 2);
		// set up the frame callback for doing the heat transfer
		var ps = player.ship.script;
		ps.thirdPartyHeat = 0;
		ps._warningPoint1 = this._warningPoint1;
		ps._warningPoint2 = this._warningPoint2;
		ps._warningPoint3 = this._warningPoint3;
		ps._warning1 = false;
		ps._warning2 = false;
		ps._warning3 = false;
		if (this._fcbID === 0) {
			this._fcbID = addFrameCallback(this.$shipConfig_temperatureFCB.bind(this));
		}
		if (this._warnPlayerOfHeat === true) {
			// set up timer for heat warning sounds/notifications
			this._heatWarning = new Timer(this, this.$warnPlayerOfHeat, 2, 2);
		}
	}
}

this.$shipConfig_temperatureFCB = function sc_fcb (delta) {
	var that = sc_fcb;
	var _p = (that._p = that._p || player.ship);

	if (delta === 0) return;
	//var p = player.ship;
	var ps = _p.script;
	if (!_p || !ps) return;
	// temp is impacted by laser temp, use of injectors and use of cloak
	var scale = ps._heat_sink_factor;
	//var ship_rate = p.script._heat_rate;
	// apply the minimum temp based on the bus overload level, equip extensions installed, and other factors
	if (_p.temperature < (0.234375 + (ps._busOverload / 100) + (ps._equipExt / 100) + ps._equipmentClassHeat)) {
		_p.temperature = 0.234375 + (ps._busOverload / 100) + (ps._equipExt / 100) + ps._equipmentClassHeat;
	}
	// add temp based on equipment activity, slowing the rate down from 0.5 to 1.0
	// special case - is system is going nova, don't make it too much harder
	var exch_rate = (_p.temperature > 0.5 ? (1.5 - _p.temperature) : 1) * (system.sun && system.sun.hasGoneNova ? 0.5 : 1);
	var amt = (((_p.laserHeatLevelAft + _p.laserHeatLevelForward + _p.laserHeatLevelPort + _p.laserHeatLevelStarboard +
		(_p.isCloaked ? 0.8 : 0) +
		((_p.injectorsEngaged || ps._ficcEngaged === true) ? ((_p.injectorBurnRate / 0.25)) : 0) +
		(ps.thirdPartyHeat && ps.thirdPartyHeat > 0 ? ps.thirdPartyHeat : 0) // third party heat properties
	) * exch_rate) / 3) * (delta / (5 / scale))
	_p.temperature += amt;
}

//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
	missionVariables.ShipConfig_HeatSinkMode = this._mode;
	missionVariables.ShipConfig_HeatSinkControl = this._controlMode;
}

//-------------------------------------------------------------------------------------------------------------
this.equipmentRemoved = function (equipment) {
	if (equipment === "EQ_HEAT_SINK" && player.ship.docked) this.$initInterface(player.ship.dockedStation);
}

//-------------------------------------------------------------------------------------------------------------
this.playerBoughtEquipment = function (equipment) {
	if (equipment === "EQ_HEAT_SINK") this.$initInterface(player.ship.dockedStation);
}

//-------------------------------------------------------------------------------------------------------------
this.$stopTimers = function $stopTimers() {
	if (this._tempCheck && this._tempCheck.isRunning) this._tempCheck.stop();
	this.$stopFCB();
	if (this._heatWarning && this._heatWarning.isRunning) this._heatWarning.stop();
	var ps = player.ship.script;
	if (ps) {
		ps._warning1 = false;
		ps._warning2 = false;
		ps._warning3 = false;
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$stopFCB = function $stopFCB() {
	if (this._fcbID != 0) {
		if (isValidFrameCallback(this._fcbID)) removeFrameCallback(this._fcbID);
		this._fcbID = 0;
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$warnPlayerOfHeat = function $warnPlayerOfHeat() {
	var p = player.ship;
	var ps = p.script;
	if (!p || !ps) return;
	if (p.temperature >= ps._warningPoint1 && ps._warning1 === false) {
		worldScripts.ShipConfiguration_Core.$playSound("booster_warning");
		player.consoleMessage(expandDescription("[sc_heat_warning]"), 5);
		ps._warning1 = true;
		return;
	}
	if (p.temperature < ps._warningPoint1 && ps._warning1 === true) ps._warning1 = false;

	
	if (p.temperature >= ps._warningPoint2 && ps._warning2 === false) {
		worldScripts.ShipConfiguration_Core.$playSound("booster_warning");
		player.consoleMessage(expandDescription("[sc_heat_warning]"), 5);
		ps._warning2 = true;
		return;
	}
	if (p.temperature < ps._warningPoint2 && ps._warning2 === true) ps._warning2 = false;

	// for third warning, play sound repeatedly
	if (p.temperature >= ps._warningPoint3) {
		worldScripts.ShipConfiguration_Core.$playSound("booster_warning");
		if (ps._warning3 === false) {
			player.consoleMessage(expandDescription("[sc_heat_critical]"), 5);
			ps._warning3 = true;
		}
		return;
	}
	if (p.temperature < ps._warningPoint3 && ps._warning3 === true) ps._warning3 = false;
}

//-------------------------------------------------------------------------------------------------------------
this.$checkShipTemp = function $checkShipTemp() {
	var p = player.ship;
	if (p.equipmentStatus("EQ_HEAT_SINK_CONTROL") != "EQUIPMENT_OK" && p.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") != "EQUIPMENT_OK") return;
	if (p.temperature > 0.75) {
		this.activated();
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$initInterface = function $initInterface(station) {
	if (player.ship.equipmentStatus("EQ_HEAT_SINK") === "EQUIPMENT_OK") {
		station.setInterface(this.name, {
			title: expandDescription("[sc_heat_interface_title]"),
			category: expandDescription("[interfaces-category-ship-systems]"),
			summary: expandDescription("[sc_heat_interface_summary]"),
			callback: this.$heatSinkControl.bind(this)
		});
	} else {
		station.setInterface(this.name, null);
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$heatSinkControl = function $heatSinkControl() {

	var curChoices = {};
	var text = "";
	var def = "";

	var col1 = 10;
	var damaged = false;

	var sc = worldScripts.ShipConfiguration_Core;
	var p = player.ship;
	var hs = sc.$countHeatSinks();

	text = sc.$padTextRight(expandDescription("[sc_heatsink_count]"), col1) + hs + "\n";
	var dmg = p.equipmentStatus("EQ_HEAT_SINK", true)["EQUIPMENT_DAMAGED"];
	if (dmg > 0) {
		text += sc.$padTextRight(expandDescription("[sc_heatsink_damaged]"), col1) + dmg + "\n";
	}
	text += "\n";

	text += sc.$padTextRight(expandDescription("[sc_heatsink_mode]"), col1) + (this._mode === 0 ? expandDescription("[sc_heatsink_mode_manual]") : expandDescription("[sc_heatsink_mode_auto]")) + "\n";
	text += sc.$padTextRight(" ", col1) + (this._mode === 0 ? expandDescription("[sc_heatsink_mode_manual_desc]") : expandDescription("[sc_heatsink_mode_auto_desc]"));
	if (this._mode === 1) text += sc.$padTextRight(" ", col1) + expandDescription("[sc_heatsink_mode_warning]");

	text += sc.$padTextRight(expandDescription("[sc_heatsink_controlmode]"), col1) + (this._controlMode === 0 ? expandDescription("[sc_heatsink_active]") : expandDescription("[sc_heatsink_passive]")) + "\n";
	text += sc.$padTextRight(" ", col1) + (this._controlMode === 0 ? expandDescription("[sc_heatsink_control_visible]") : expandDescription("[sc_heatsink_control_invisible]")) + "\n";
	if (player.ship.equipmentStatus("EQ_HEAT_SINK_CONTROL") === "EQUIPMENT_DAMAGED" || player.ship.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") === "EQUIPMENT_DAMAGED") {
		text += expandDescription("[sc_heatsink_control_damaged]");
		damaged = true;
	}

	if (this._controlMode === 0 && damaged === false) {
		curChoices["01_CHANGE_MODE"] = {
			text: expandDescription("[sc_heatsink_change_mode]", {mode: (this._mode === 0 ? expandDescription("[sc_heatsink_mode_auto]") : expandDescription("[sc_heatsink_mode_manual]"))}),
			color: this._menuColor
		};
	} else {
		curChoices["01_CHANGE_MODE"] = {
			text: expandDescription("[sc_heatsink_change_mode]", {mode: (this._mode === 0 ? expandDescription("[sc_heatsink_mode_auto]") : expandDescription("[sc_heatsink_mode_manual]"))}),
			color: this._disabledColor,
			unselectable: true
		};
	}
	if (damaged === false) {
		curChoices["02_CHANGE_CONTROL"] = {
			text: expandDescription("[sc_heatsink_change_control]", {mode: (this._controlMode === 0 ? expandDescription("[sc_heatsink_passive]") : expandDescription("[sc_heatsink_active]"))}),
			color: this._menuColor
		};
	} else {
		curChoices["02_CHANGE_CONTROL"] = {
			text: expandDescription("[sc_heatsink_change_control]", {mode: (this._controlMode === 0 ? expandDescription("[sc_heatsink_passive]") : expandDescription("[sc_heatsink_active]"))}),
			color: this._disabledColor,
			unselectable: true
		};
	}
	curChoices["99_EXIT"] = {
		text: "[sc-return]",
		color: this._itemColor
	};

	def = "99_EXIT";
	if (this._lastChoice != "") def = this._lastChoice;

	var opts = {
		screenID: "oolite-shipconfig-heatsinks-map",
		title: expandDescription("[sc_heat_interface_title]"),
		allowInterrupt: true,
		overlay: {
			name: "shipconfig_heatsink.png",
			height: 546
		},
		exitScreen: "GUI_SCREEN_INTERFACES",
		choices: curChoices,
		initialChoicesKey: def,
		message: text
	};

	mission.runScreen(opts, this.$heatSinkScreenHandler, this);
}

//-------------------------------------------------------------------------------------------------------------
this.$heatSinkScreenHandler = function $heatSinkScreenHandler(choice) {

	if (!choice) return;

	this._lastChoice = choice;

	if (choice === "01_CHANGE_MODE") {
		if (this._mode === 0) {
			this._mode = 1;
		} else {
			this._mode = 0;
		}
	}
	if (choice === "02_CHANGE_CONTROL") {
		if (this._controlMode === 0) {
			if (player.ship.equipmentStatus("EQ_HEAT_SINK_CONTROL") === "EQUIPMENT_OK") {
				player.ship.removeEquipment("EQ_HEAT_SINK_CONTROL");
				player.ship.awardEquipment("EQ_HEAT_SINK_CONTROL_PASSIVE");
				this._controlMode = 1;
				this._mode = 1;
			}
		} else {
			if (player.ship.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") === "EQUIPMENT_OK") {
				this._controlMode = 0;
				player.ship.removeEquipment("EQ_HEAT_SINK_CONTROL_PASSIVE");
				player.ship.awardEquipment("EQ_HEAT_SINK_CONTROL");
			}
		}
	}

	if (choice != "99_EXIT") this.$heatSinkControl();
}

//-------------------------------------------------------------------------------------------------------------
// deploys a HS object from a ship
this.$deployHeatSink = function $deployHeatSink(ship) {
	var sc = worldScripts.ShipConfiguration_Core;
	var dumpAmount = this._amountToDump * (1 - (sc.$getShipMass(ship) / 500000));
	if (dumpAmount < 0.1) dumpAmount = 0.1;
	// create a heat sink object that appears briefly on the scanner
	// not using .spawn as there is a chance that won't create an object
	// system.addShips("heatsink", 1, ship.position.add(ship.vectorUp.multiply((ship.boundingBox.y + 5) * -1)), 0)[0]; // p.spawn("heatsink", 1); 
	// new method
	ship.ejectSpecificItem("heatsink");
	// smaller ships will dump a larger percentage of heat
	ship.removeEquipment("EQ_HEAT_SINK");
	ship.temperature -= dumpAmount;
}

//-------------------------------------------------------------------------------------------------------------
// check for out of sync equipment control mode
this.$checkOutOfSyncMode = function $checkOutOfSyncMode() {
	var p = player.ship;
	if (this._controlMode == 0) {
		if (p.equipmentStatus("EQ_HEAT_SINK_CONTROL_PASSIVE") != "EQUIPMENT_UNAVAILABLE") this._controlMode = 1;
	} else {
		if (p.equipmentStatus("EQ_HEAT_SINK_CONTROL") != "EQUIPMENT_UNAVAILABLE") this._controlMode = 0;
	}
}