"use strict";
this.name = "GalCopBB_Missions_MFD";
this.author = "phkb";
this.copyright = "2017 phkb";
this.description = "Controls the output the MFD";
this.license = "CC BY-NC-SA 4.0";

this._lineLength = 14;
this._mfdID = -1;
this._target = null; // holds a reference to the target with whom comms is happening
this._offerTimeout = 90; // number of seconds to wait for response
this._offerTimer = null; // timer for mission offer
this._timeoutCounter = 0;
this._currentMFDText = "";
this._displayPoint = 0;
this._holdData = {};
this._subMessageTimer = null;
this._originalMsg = "";
this._final = false;
this._autoAccept = false;
this._declineMessageTimer = null;
this._declineType = false;
this._acceptMessageTimer = null;
this._acceptType = false;
this._disablReplyOptions = false;
this._escapePod = null;

//-------------------------------------------------------------------------------------------------------------
this.shipWillEnterWitchspace = function (cause, destination) {
	if (this._offerTimer && this._offerTimer.isRunning) {
		this.$stopTimers();
		worldScripts.GalCopBB_Missions.$declinePendingMission();
		this.$removeBCReplyOptions();
	}
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation = function (station) {
	if (worldScripts.GalCopBB_Missions._simulator === true) return;
	if (this._offerTimer && this._offerTimer.isRunning) {
		// make sure we don't leave any half-accepted missions on the boards
		this.$stopTimers();
		worldScripts.GalCopBB_Missions.$declinePendingMission();
		this.$removeBCReplyOptions();
	}
}

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

//-------------------------------------------------------------------------------------------------------------
this.$stopTimers = function $stopTimers() {
	if (this._offerTimer && this._offerTimer.isRunning) {
		this._offerTimer.stop();
		this._offerTimer = null;
	}
	if (this._subMessageTimer && this._subMessageTimer.isRunning) {
		this._subMessageTimer.stop();
		this._subMessageTimer = null;
	}
	if (this._declineMessageTimer && this._declineMessageTimer.isRunning) {
		this._declineMessageTimer.stop();
		this._declineMessageTimer = null;
	}
	this._declineType = false;
}

//-------------------------------------------------------------------------------------------------------------
// breaks text up into appropriate lengths for an MFD
this.$processText = function $processText(msg) {
	var line = "";
	// the replace here should ensure all newline commands are at the end of a word, and not in the middle of one
	var words = msg.replace(new RegExp("\n", 'g'), "\n ").split(" ");
	var word = "";
	var output = "";

	for (var i = 0; i < words.length; i++) {
		word = words[i].trim();
		// make sure we have a word to add before trying to add it
		if (word !== "") {
			if (defaultFont.measureString(line + " " + word) <= this._lineLength) {
				line += (line === "" ? "" : " ") + word;
				// if the word ended in a newline command, add the line to the output and reset
				if (word.indexOf("\n", word.length - 2) !== -1) {
					output += line;
					line = "";
				}
			} else {
				output += line + "\n";
				line = word;
				// if the word ended in a newline command, add the line to the output and reset
				if (word.indexOf("\n", word.length - 2) !== -1) {
					output += line;
					line = "";
				}
			}
		}
	}
	output += line;

	// update MFD so that new text goes on the bottom.
	var lines = this._currentMFDText.split("\n");
	if (this._currentMFDText === "") lines = [];
	var newlines = output.split("\n");

	for (var i = 0; i < newlines.length; i++) {
		lines.push(newlines[i]);
	}

	var final = "";
	if (lines.length <= 10) {
		final = lines.join("\n");
	} else {
		for (var i = lines.length - 10; i < lines.length; i++) {
			final += (final === "" ? "" : "\n") + lines[i];
		}
	}

	this._currentMFDText = final;

	return final;
}

//-------------------------------------------------------------------------------------------------------------
// updates the text of the MFD
this.$updateMFD = function $updateMFD(msg, useComms, src, autoAccept) {
	var p = player.ship;

	if (this._originalMsg === "") this._originalMsg = msg;
	if (autoAccept && autoAccept === true) {
		this._autoAccept = autoAccept;
	} else {
		this._autoAccept = false;
	}

	var msglist = msg.split("\n");
	var currmsg = msglist[this._displayPoint];
	// if this is the final message, just select the last one
	if (this._final === true) {
		currmsg = msglist[msglist.length - 1];
	}

	// if the hud is hidden don't try an update - it will get confusing as to which mfd slot is open or not.
	if (p.hudHidden === false) {
		// if useComms has been set to true, disable the MFD to force comms method instead
		if (useComms === true) {
			this._mfdID = -1;
		} else {
			// find the slot currently set for this MFD
			this.$findMFDID();
			// if we haven't got a set slot (this._mfdID === -1) or the set slot we had is now unavailable...
			if (this._mfdID === -1 ||
				(p.multiFunctionDisplayList[this._mfdID] && p.multiFunctionDisplayList[this._mfdID] !== "" && p.multiFunctionDisplayList[this._mfdID] !== this.name)) {
				// find a free slot
				// first, make sure we reset our slot id marker (in the case where the previous one is in use)
				this._mfdID = -1;
				// search for a free slot
				for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
					if (!p.multiFunctionDisplayList[i] || p.multiFunctionDisplayList[i] === "") {
						this._mfdID = i;
						break;
					}
				}
			}
		}

		// we have a free slot, so force the mfd to display
		if (this._mfdID !== -1) {
			// set the text in the MFD
			var output = this.$processText(currmsg);
			p.setMultiFunctionText(this.name, output, false);
			p.setMultiFunctionDisplay(this._mfdID, this.name);
		} else {
			if (useComms === true && src && src.isInSpace) {
				if (player.ship.position.distanceTo(src) < player.ship.scannerRange) {
					// yay! comms is working!
					src.commsMessage(currmsg, p);
				} else {
					// out of range
					// got back a step, and try again shortly
					this._displayPoint -= 1;
				}
			} else {
				// oh well, make it a console message
				player.consoleMessage(currmsg, 20);
			}
		}
	}

	if (this._final === false) {
		this._displayPoint += 1;
		if (this._displayPoint < msglist.length) {
			this._holdData.msg = msg;
			this._holdData.useComms = useComms;
			this._holdData.src = src;
			this._subMessageTimer = new Timer(this, this.$processNextMessage, 5, 0);
			// return at this point so the accept/reject items only appear when all the messages are displayed.
			return;
		}
	}

	this._holdData = {};
	// get a local reference to the ship that is making the offer
	if (src) this._target = src;
	if (this._disablReplyOptions === false) this.$displayBCReplyOptions();
}

//-------------------------------------------------------------------------------------------------------------
// re-run the update function so the next message in the list can be displayed
this.$processNextMessage = function $processNextMessage() {
	this.$updateMFD(this._holdData.msg, this._holdData.useComms, this._holdData.src, this._autoAccept);
}

//-------------------------------------------------------------------------------------------------------------
// records the index of the MFD that currently holds the mfd
this.$findMFDID = function $findMFDID() {
	var p = player.ship;
	for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
		if (p.multiFunctionDisplayList[i] === this.name) this._mfdID = i;
	}
}

//-------------------------------------------------------------------------------------------------------------
// hides all instances of the MFD
this.$autoHideMFD = function $autoHideMFD() {
	var p = player.ship;
	if (p && p.multiFunctionDisplayList) {
		for (var i = 0; i < p.multiFunctionDisplayList.length; i++) {
			if (p.multiFunctionDisplayList[i] === this.name) {
				p.setMultiFunctionDisplay(i, "");
			}
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
// add the secondary mission accept/decline options to broadcast comms
this.$displayBCReplyOptions = function $displayBCReplyOptions() {
	if (this._autoAccept === true) {
		worldScripts.GalCopBB_Missions.$acceptPendingMission();
		this.$turnOffMFD();
		return;
	}
	var bc = worldScripts.BroadcastCommsMFD;
	if (bc.$checkMessageExists("gcm_accept_mission") === true || bc.$checkMessageExists("gcm_decline_mission") === true) return;
	bc.$createMessage({
		messageName: "gcm_accept_mission",
		callbackFunction: this.$acceptNewMission.bind(this),
		displayText: expandDescription("[gcm_accept_mission]"),
		messageText: "",
		transmissionType: "broadcast",
		deleteOnTransmit: true,
		delayCallback: 1
	});
	bc.$createMessage({
		messageName: "gcm_decline_mission",
		callbackFunction: this.$declineNewMission.bind(this),
		displayText: expandDescription("[gcm_decline_mission]"),
		messageText: "",
		transmissionType: "broadcast",
		deleteOnTransmit: true,
		delayCallback: 1
	});
	// reset the timer counter
	this._timeoutCounter = 0;
	// start a timer to wait for player response
	this._offerTimer = new Timer(this, this.$removeOffer, 1, 1);
}

//-------------------------------------------------------------------------------------------------------------
this.$acceptNewMission = function $acceptNewMission() {
	if (this._target) {
		player.ship.commsMessage(expandDescription("[gcm_accept_secondary]"));
	} else {
		player.consoleMessage(expandDescription("[gcm_accepted_mission]"));
		if (this._mfdID !== -1) {
			//this._final = true;
			this.$updateMFD(this._originalMsg + "\n>> " + expandDescription("[gcm_accept_secondary]"), false, null);
		}
	}
	worldScripts.GalCopBB_Missions.$acceptPendingMission();
	this.$removeBCReplyOptions();
	this._acceptMessageTimer = new Timer(this, this.$sendAcceptComms, 5, 0);
}

//-------------------------------------------------------------------------------------------------------------
this.$sendAcceptComms = function $sendAcceptComms() {
	if (this._acceptType == false) {
		if (this._target) {
			this._target.commsMessage(expandDescription("[gcm_accept_response]"), player.ship);
		} else {
			if (this._mfdID !== -1) {
				this._final = true;
				this._disablReplyOptions = true;
				this.$updateMFD(this._originalMsg + "\n" + expandDescription("[gcm_accept_response]"), false, null);
			}
		}
	}
	// turn off the MFD (if it was used)
	this.$turnOffMFD();
}

//-------------------------------------------------------------------------------------------------------------
this.$declineNewMission = function $declineNewMission(send_message) {
	if (send_message == null) {
		this._declineType = false;
		if (this._target) {
			player.ship.commsMessage(expandDescription("[gcm_decline_secondary]"));
		} else {
			player.consoleMessage(expandDescription("[gcm_declined_mission]"));
			if (this._mfdID !== -1) {
				//this._final = true;
				this.$updateMFD(this._originalMsg + "\n>> " + expandDescription("[gcm_decline_secondary]"), false, null);
			}
		}
	} else {
		this._declineType = true;
	}
	this.$removeBCReplyOptions();
	this._declineMessageTimer = new Timer(this, this.$sendDeclineComms, 5, 0);
}

//-------------------------------------------------------------------------------------------------------------
this.$sendDeclineComms = function $sendDeclineComms() {
	if (this._declineType == false) {
		if (this._target) {
			this._target.commsMessage(expandDescription("[gcm_decline_response]"), player.ship);
		} else {
			if (this._mfdID !== -1) {
				this._final = true;
				this._disablReplyOptions = true;
				this.$updateMFD(this._originalMsg + "\n" + expandDescription("[gcm_decline_response]"), false, null);
			}
		}
	}
	worldScripts.GalCopBB_Missions.$declinePendingMission();
	// turn off the MFD (if it was used)
	this.$turnOffMFD();
}

//-------------------------------------------------------------------------------------------------------------
this.$turnOffMFD = function $turnOffMFD() {
	// turn off the MFD (if it was used)
	this._currentMFDText = "";
	this._originalMsg = "";
	this._final = false;
	this._displayPoint = 0;
	this._target = null;
	if (this._mfdID !== -1) {
		if (this._subMessageTimer && this._subMessageTimer.isRunning) this._subMessageTimer.stop();
		this._subMessageTimer = new Timer(this, this.$autoHideMFD, 3, 0);
	}
	this._disablReplyOptions = false;
}

//-------------------------------------------------------------------------------------------------------------
this.$removeBCReplyOptions = function $removeBCReplyOptions() {
	this._offerTimer.stop();
	this._offerTimer = null;
	var bc = worldScripts.BroadcastCommsMFD;
	if (bc.$checkMessageExists("gcm_accept_mission") === true) bc.$removeMessage("gcm_accept_mission");
	if (bc.$checkMessageExists("gcm_decline_mission") === true) bc.$removeMessage("gcm_decline_mission");

	// clean up the escape pod entity, if present
	if (this._escapePod && this._escapePod.script) {
		delete this._escapePod.script.shipWasDumped;
		if (this._escapePod.script.$gcmovr_shipWasDumped) {
			this._escapePod.script.shipWasDumped = this._escapePod.script.$gcmovr_shipWasDumped;
			delete this._escapePod.script.$gcmovr_shipWasDumped;
		}
	}
	this._escapePod = null;
}

//-------------------------------------------------------------------------------------------------------------
this.$removeOffer = function $removeOffer() {
	this._timeoutCounter += 1;
	// have we timed out
	if (this._timeoutCounter >= this._offerTimeout) {
		this.$declineNewMission();
		return;
	}
	// if the offer came from another ship, is that ship still in range?
	if (this._target && (this._target.isValid === false || player.ship.position.distanceTo(this._target) > player.ship.scannerRange)) {
		this.$declineNewMission(true);
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$gcmmfd_shipWasDumped = function $gcmmfd_shipWasDumped(dumper) {
	if (this.ship.script.$gcmovr_shipWasDumped) this.ship.script.$gcmovr_shipWasDumped(dumper);

	worldScripts.GalCopBB_Missions_MFD.$stopTimers();
	worldScripts.GalCopBB_Missions.$declinePendingMission();
	worldScripts.GalCopBB_Missions_MFD.$removeBCReplyOptions();
}