"use strict";
this.name = "GalCopBB_WBSA";
this.author = "phkb";
this.copyright = "2017 phkb";
this.description = "Control of the Witchpoint Beacon Security Access device";
this.license = "CC BY-NC-SA 4.0";

/*
*60 - Hacking witchpoints
	System authorities in system X are concerned about the flow of pirate traffic through their system. They want to hack into the witchpoint beacons of all systems within a 7LY range, that will enable them to monitor traffic flows into their system, outside of GalCop's purview.
		- will require getting within 200m of witchpoint marker, targeting the marker and initiating the special equipment (prime, activate)

*61 - Restoring witchpoints
	GalCop has become aware of an illegal data stream emanating from witchpoint markers around system X. You need to go to each of the systems listed, and clean the illegal code from the units. 
		- will require getting within 200m of witchpoint marker, targeting the marker and initiating the special equipment (prime, activate)
		- will only be available once mission 60 has been performed at a system
*/

this._debug = false;
this._uploadCount = 0; // percentage of upload completed
this._uploadTimer = null; // timer to perform upload
this._mode = 0; // 0 = hijack mode, 1 = reset mode
this._seenByPolice = false;
this._seenByHunters = false;
this._wpHacks = []; // list of systems who have had their witchpoint beacon hacked (missions 60-61)

//-------------------------------------------------------------------------------------------------------------
this.startUp = function () {
	var gcm = worldScripts.GalCopBB_Missions;
	// add these mission types into the main control
	var list = [60, 61];
	gcm._availableMissionTypes = gcm._availableMissionTypes.concat(list);
	this._debug = gcm._debug;
	// exclude some equipment items from being sold/stored by ShipConfig
	var sc = worldScripts.ShipConfiguration_Core;
	if (sc) {
		sc._noSell.push("EQ_GCM_WBSA");
	}
}

//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
	if (missionVariables.GalCopBBMissions_HackedWP) {
		this._wpHacks = JSON.parse(missionVariables.GalCopBBMissions_HackedWP);
		delete missionVariables.GalCopBBMissions_HackedWP;
	}
}

//-------------------------------------------------------------------------------------------------------------
this.playerWillSaveGame = function () {
	// save any data we currently have
	if (this._wpHacks.length > 0) missionVariables.GalCopBBMissions_HackedWP = JSON.stringify(this._wpHacks);
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillEnterWitchspace = function (cause, destination) {
	// once a witchpoint has been hacked, there is a high chance of a misjump (but not from interstellar space)
	if (this._wpHacks.length > 0 && cause !== "galactic jump") {
		for (var i = 0; i < this._wpHacks.length; i++) {
			if (this._wpHacks[i] === destination && system.ID !== -1 && Math.random() > 0.7) player.ship.scriptedMisjump = true;
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.playerEnteredNewGalaxy = function (galNumber) {
	this._wpHacks.length = 0;
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillExitWitchspace = function () {
	this._seenByHunters = false;
	this._seenByPolice = false;
	if (this._uploadTimer && this._uploadTimer.isRunning) {
		this._uploadTimer.stop();
		this._uploadTimer = null;
	}
}

//-------------------------------------------------------------------------------------------------------------
this.mode = function () {

}

//-------------------------------------------------------------------------------------------------------------
this.activated = function () {
	var wbsa = worldScripts.GalCopBB_WBSA;
	if (wbsa._uploadTimer && wbsa._uploadTimer.isRunning) {
		wbsa._uploadTimer.stop();
		delete wbsa._uploadTimer;
		player.consoleMessage(expandDescription("[gcm_security_access_stopped]"));
		worldScripts.GalCopBB_Missions.$playSound("stop");
		return;
	}

	var p = player.ship;

	// is the equipment OK?
	if (p.equipmentStatus("EQ_GCM_WBSA") !== "EQUIPMENT_OK") {
		worldScripts.GalCopBB_Missions.$playSound("stop");
		return;
	}
	// are any of the stop conditions met?
	if (wbsa.$checkConstraints() === false) {
		worldScripts.GalCopBB_Missions.$playSound("stop");
		return;
	}

	var mode = wbsa.$checkWBSAMode();
	// if we try to use the device in a system not contracted to
	if (mode === -1) {
		player.consoleMessage(expandDescription("[gcm_security_access_invalid]"));
		worldScripts.GalCopBB_Missions.$playSound("stop");
		return;
	}

	player.consoleMessage(expandDescription("[gcm_security_access_started]"));
	worldScripts.GalCopBB_Missions.$playSound("activate");

	// have to start again each time you stop the upload
	wbsa._uploadCount = 0;
	if (wbsa._uploadTimer && wbsa._uploadTimer.isRunning) wbsa._uploadTimer.stop();
	wbsa._uploadTimer = new Timer(wbsa, wbsa.$scanProcess, 3, 3);
}

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

	var wbsa = worldScripts.GalCopBB_WBSA;

	if (wbsa.$checkConstraints() === false) {
		wbsa._uploadTimer.stop();
		wbsa._uploadTimer = null;
		player.consoleMessage(expandDescription("[gcm_security_access_stopped]"));
		return;
	}

	var p = player.ship;
	var msg = "";

	// is there any police vessel in range?
	var police = this.$findLawVessels(p);
	if (this._mode === 0 && police.length > 0 && this._seenByPolice === false) {
		this._seenByPolice = true;
		msg = expandDescription("[gcm_wbsa_detected_police]");
		penalty = (Math.random() * 20) + 10;
		p.setBounty(player.bounty + penalty, "seen by police");
		//this.$sendEmail(penalty);
		police[0].commsMessage(msg, p);
		worldScripts.GalCopBB_WBSA.$witchpointHackMissionFailed();
	}

	// are there any hunters in range? 
	var hunters = this.$findHunters(p);
	var mode = wbsa.$checkWBSAMode();
	if (mode === 0 && hunters.length > 0 && wbsa._seenByHunters === false && wbsa._seenByPolice === false) {
		wbsa._seenByHunters = true;
		msg = expandDescription("[gcm_wbsa_detected_hunter]");
		hunters[0].commsMessage(msg, p);
		for (var i = 0; i < hunters.length; i++) {
			hunters[i].target = p;
			hunters[i].performAttack();
		}
	}

	wbsa._uploadCount += 2;
	player.consoleMessage(expandDescription("[gcm_upload_progress]", { complete: wbsa._uploadCount }), 2);

	if (wbsa._uploadCount >= 100) {
		wbsa._uploadTimer.stop();
		wbsa._uploadTimer = null;
		if (mode === 0) wbsa.$witchpointHackMissionComplete();
		if (mode === 1) wbsa.$witchpointRestoreMissionComplete();
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$checkConstraints = function $checkConstraints() {
	var p = player.ship;

	// do we have a witchpoint beacon targeted?
	if (p.target.hasRole("buoy-witchpoint") == false) {
		player.consoleMessage(expandDescription("[gcm_security_access_no_target]"));
		return false;
	}
	if (p.isCloaked) {
		player.consoleMessage(expandDescription("[gcm_security_access_cloaked]"));
		return false;
	}
	if (p.position.distanceTo(p.target) > (p.scannerRange * 0.02)) {
		//log(this.name, "dist = " + p.position.distanceTo(p.target));
		player.consoleMessage(expandDescription("[gcm_security_access_out_of_range]"));
		return false;
	}

	return true;
}

//-------------------------------------------------------------------------------------------------------------
this.$witchpointHackMissionComplete = function $witchpointHackMissionComplete() {
	// add the system to the list of hacked systems
	// this can be done regardless of whether the player was spotted by police or not.
	var gcm = worldScripts.GalCopBB_Missions;
	this._wpHacks.push(system.ID);
	var bb = worldScripts.BulletinBoardSystem;
	var list = gcm.$getListOfMissions(true, 60);
	for (var i = 0; i < list.length; i++) {
		if (system.ID === list[i].destination &&
			list[i].expiry > clock.adjustedSeconds &&
			list[i].data.quantity < list[i].data.targetQuantity) {

			list[i].data.quantity = 1;
			bb.$updateBBMissionPercentage(list[i].ID, 1);

			gcm.$logMissionData(list[i].ID);
			player.consoleMessage(expandDescription("[goal_updated]"));
			break;
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$witchpointHackMissionFailed = function $witchpointHackMissionFailed() {
	var gcm = worldScripts.GalCopBB_Missions;
	var list = gcm.$getListOfMissions(true, 60);
	for (var i = 0; i < list.length; i++) {
		if (system.ID === list[i].destination) {
			// reduce the target quantity, so that the mission complete criteria can never be met, forcing the player to terminate the mission instead.
			list[i].data.targetQuantity = 0;
			break;
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$witchpointRestoreMissionComplete = function $witchpointRestoreMissionComplete() {
	var gcm = worldScripts.GalCopBB_Missions;
	var bb = worldScripts.BulletinBoardSystem;
	var list = gcm.$getListOfMissions(true, 61);
	for (var i = 0; i < list.length; i++) {
		if (system.ID === list[i].destination &&
			list[i].expiry > clock.adjustedSeconds &&
			list[i].data.quantity < list[i].data.targetQuantity) {

			list[i].data.quantity = 1;
			bb.$updateBBMissionPercentage(list[i].ID, 1);

			// remove the system from the list of hacks
			this._wpHacks.splice(this._wpHacks.indexOf(system.ID), 1);

			gcm.$logMissionData(list[i].ID);
			player.consoleMessage(expandDescription("[goal_updated]"));
			break;
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$checkWBSAMode = function $checkWBSAMode() {
	var gcm = worldScripts.GalCopBB_Missions;
	var id = gcm.$getActiveMissionIDByType(60);
	var type = 0;
	if (id === -1) {
		id = gcm.$getActiveMissionIDByType(61);
		if (id != -1) {
			type = 1;
		} else {
			type = -1;
		}
	}
	return type;
}

//-------------------------------------------------------------------------------------------------------------
// find all police or main stations within 15500km of of ship
this.$findLawVessels = function $findLawVessels(npc) {
	function _ships(entity) {
		return entity.isShip && entity.isPolice && !entity.isPlayer && !entity.isStation && !entity.isMainStation;
	}
	return system.filteredEntities(this, _ships, npc, 21500);
}

//-------------------------------------------------------------------------------------------------------------
this.$findHunters = function $findHunters(npc) {
	function _hunters(entity) {
		return entity.isShip && Ship.roleIsInCategory(entity.primaryRole, "oolite-hunter");
	}
	return system.filteredEntities(this, _hunters, npc, 15000);
}

//-------------------------------------------------------------------------------------------------------------
this.$acceptedMission = function $acceptedMission(missID) {
	var bb = worldScripts.BulletinBoardSystem;
	var item = bb.$getItem(missID);
	var gcm = worldScripts.GalCopBB_Missions;

	if (this._debug) log(this.name, "accepted mission id = " + missID);

	if (!item) {
		log(this.name, "!!ERROR: BB returned null value from $getItem on mission ID " + missID);
		return;
	}
	gcm.$updateLastMissionDate(item.source, item.data.missionType);
	gcm.$updateGeneralSettings(item);

	// give player the witchpoint marker security access device
	if (item.data.missionType === 60 || item.data.missionType === 61) {
		player.ship.awardEquipment("EQ_GCM_WBSA");
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$completedMission = function $completedMission(missID) {
	var p = player.ship;
	var bb = worldScripts.BulletinBoardSystem;
	var item = bb.$getItem(missID);
	var gcm = worldScripts.GalCopBB_Missions;
	var sbm = worldScripts.Smugglers_BlackMarket;

	// update mission history
	gcm.$updateSuccessHistoryReputation(item);

	// *** type 60 & 61 - hacking/repairing witchpoint markers
	if (item.data.missionType === 60 || item.data.missionType === 61) {
		if (p.equipmentStatus("EQ_GCM_WBSA") === "EQUIPMENT_OK" || p.equipmentStatus("EQ_GCM_WBSA") === "EQUIPMENT_DAMAGED") {
			p.removeEquipment("EQ_GCM_WBSA");
			if (sbm) sbm.$removeSaleItem("EQ_GCM_WBSA:" + missID);
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$confirmCompleted = function $confirmCompleted(missID) {
	return "";
}

//-------------------------------------------------------------------------------------------------------------
this.$terminateMission = function $terminateMission(missID) {
	var bb = worldScripts.BulletinBoardSystem;
	var item = bb.$getItem(missID);
	var sbm = worldScripts.Smugglers_BlackMarket;
	var gcm = worldScripts.GalCopBB_Missions;

	// adjust reputation only when the terminatePenalty flag is set to true 
	if (item.data.terminatePenalty === true) {
		// update mission history
		gcm.$updateFailedHistoryReputation(item);
	}

	// *** type 60 & 61 - hacking/repairing witchpoint markers
	if (item.data.missionType === 60 || item.data.missionType === 61) {
		var eqsts = player.ship.equipmentStatus("EQ_GCM_WBSA");
		if (eqsts === "EQUIPMENT_OK" || eqsts === "EQUIPMENT_DAMAGED") {
			player.ship.removeEquipment("EQ_GCM_WBSA");
			if (sbm) sbm.$removeSaleItem("EQ_GCM_WBSA:" + missID);
		}
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$failedMission = function $failedMission(missID) {
	var bb = worldScripts.BulletinBoardSystem;
	var sbm = worldScripts.Smugglers_BlackMarket;
	var gcm = worldScripts.GalCopBB_Missions;
	var eq = "";

	if (!sbm) {
		// if there's no blackmarket option, just remove the equipment
		this.$terminateMission(missID);
		return;
	}

	var item = bb.$getItem(missID);
	// update mission history
	gcm.$updateFailedHistoryReputation(item);

	if (item.data.missionType === 60 || item.data.missionType === 61) {
		var eqsts = player.ship.equipmentStatus("EQ_GCM_WBSA");
		if (eqsts === "EQUIPMENT_OK" || eqsts === "EQUIPMENT_DAMAGED") eq = "EQ_GCM_WBSA";
	}

	if (eq != "") gcm._equipmentFromFailedMissions.push({
		missionType: item.data.missionType,
		source: item.source,
		equip: eq,
		date: clock.adjustedSeconds
	});
}

//-------------------------------------------------------------------------------------------------------------
this.$updateManifestEntry = function $updateManifestEntry(missID) {
	var gcm = worldScripts.GalCopBB_Missions;
	gcm.$updateManifestEntry(missID);
}

//-------------------------------------------------------------------------------------------------------------
this.$missionAvailability = function $missionAvailability(missID, missType, origSysID) {
	return worldScripts.GalCopBB_Missions.$missionAvailability(missID, missType, origSysID);
}

//-------------------------------------------------------------------------------------------------------------
// 60 - hack witchpoint beacon
this.$missionType60_Values = function $missionType60_Values(workTime, routeTime, routeDistance, destSysInfo) {
	var result = {};
	result["quantity"] = 1;
	result["price"] = parseInt((parseInt(Math.random() * 500) + 1000) / 10) * 10 +
		worldScripts.GalCopBB_CoreMissionValues.$calcPlayerBonus(500); // plus a possible bonus price, based on player score 
	result["expiry"] = clock.adjustedSeconds + routeTime + workTime; // transit time + 1 hour to complete
	result["penalty"] = parseInt(result.price * 2); // failure is costly in this case
	return result;
}

//-------------------------------------------------------------------------------------------------------------
// 61 - restore witchpoint beacon
this.$missionType61_Values = function $missionType61_Values(workTime, routeTime, routeDistance, destSysInfo) {
	var result = {};
	result["quantity"] = 1;
	result["price"] = parseInt((parseInt(Math.random() * 500) + 200) / 10) * 10 +
		worldScripts.GalCopBB_CoreMissionValues.$calcPlayerBonus(200); // plus a possible bonus price, based on player score 
	result["expiry"] = clock.adjustedSeconds + routeTime + workTime; // transit time + 1 hour to complete
	result["penalty"] = parseInt(result.price / 4);
	return result;
}