"use strict";
this.name = "planetFall2_priorityAI";
this.author = "phkb";
this.copyright = "CC-BY-NC-NA 4.0";
this.description = "Updates to various Priority AI functions for planet landing";
this.version = "1.0";

// this list sets the chances of landing at a particular type of site.
// the higher the number, the more likely it is to be chosen. 0 means it will never be chosen
this._landingPriority = {
    "planetFall2_mainSurface_capitalCity": 3,
    "planetFall2_mainSurface_militaryBase": 0,
    "planetFall2_mainSurface_leisureComplex": 2,
    "planetFall2_mainSurface_factory": 2,
    "planetFall2_mainSurface_dump": 1,
    "planetFall2_subSurface_colony": 3,
    "planetFall2_subSurface_militaryBase": 0,
    "planetFall2_subSurface_leisureComplex": 2,
    "planetFall2_subSurface_factory": 2,
    "planetFall2_subSurface_dump": 1,
    "planetFall2_moonSurface_dome": 3,
    "planetFall2_moonSurface_leisureDome": 2,
    "planetFall2_moonSurface_mine": 1,
    "planetFall2_moonSurface_prison": 0,
    "planetFall2_moonSurface_researchComplex": 1,
    "planetFall2_moonSurface_factory": 2,
    "planetFall2_moonSurface_wasteLand": 0
};

//-------------------------------------------------------------------------------------------------------------
this.startUp = function () {
    var pai = worldScripts["oolite-libPriorityAI"];
    // add our custom functions in the priority AI script.
    log(this.name, "Monkey-patching Oolite Priority AI script with updated PlanetFall2 functions for planet landings");
    pai.PriorityAIController.prototype.configurationSelectShuttleDestination = this.PF2_configurationSelectShuttleDestination;
    pai.PriorityAIController.prototype.behaviourApproachDestination = this.PF2_behaviourApproachDestination;
    pai.PriorityAIController.prototype.behaviourLandOnPlanet = this.PF2_behaviourLandOnPlanet;
    pai.PriorityAIController.prototype.configurationSetDestinationToSelectedPlanet = this.PF2_configurationSetDestinationToSelectedPlanet;
}

//-------------------------------------------------------------------------------------------------------------
this.systemWillRepopulate = function () {
    if (Math.random() < 0.005 * system.info.techlevel) {
        var stn = this.$findPlanetLaunchSite();
        if (this._target) stn = this._target;
        if (stn) {
            var role = "shuttle";
            if (stn.scriptInfo.hasOwnProperty("npc_launch_roles")) {
                var roles = stn.scriptInfo.npc_launch_roles.split(" ");
                var i = roles.length;
                while (i--) {
                    var sub = roles[i];
                    var p1, p2;
                    var perct = 1;
                    if (sub.indexOf("(") >= 0) {
                        p1 = sub.indexOf("(");
                        p2 = sub.indexOf(")");
                        perct = sub.substring(p1 + 1, p2);
                    } else {
                        p1 = sub.length;
                    }
                    if (Math.random() < parseFloat(perct)) {
                        role = sub.substring(0, p1);
                        break;
                    }
                }
            }
            system.addShips(role, 1, stn.linkedVE.position);
        }
	}
}

//-------------------------------------------------------------------------------------------------------------
this.$findPlanetLaunchSite = function() {       
    var ls = system.shipsWithRole("planetFall2_surface");
    var i = ls.length;
    while (i--) {
        var scr = ls[i].scriptInfo;
        var chance = 0;
        if (scr.hasOwnProperty("npc_traffic") && (!ls[i].hasOwnProperty("_stopNPCLaunches") || ls[i]._stopNPCLaunches == false)) {
            chance = parseFloat(scr.npc_traffic);
            if (Math.random() < chance) {
                // found one
                return ls[i];
            }
        }
    }
    return null;
}

//-------------------------------------------------------------------------------------------------------------
this.PF2_configurationSelectShuttleDestination = function () {
    var possibles = system.planets.concat(system.stations);
    var destinations1 = [];
    var destinations2 = [];
    for (var i = 0; i < possibles.length; i++) {
        var possible = possibles[i];
        // travel at least a little way
        if (!possible.isShip || !possible.hasRole("planetFall2_surface")) {
            var distance = this.distance(possible);
        } else {
            var distance = this.distance(possible.linkedVE);
        }
        if (distance > possible.collisionRadius + 10000) {
            // must be friendly destination and not moving too fast
            if (possible.isPlanet || (this.friendlyStation(possible) && (possible.maxSpeed < this.ship.maxSpeed / 5))) {
                if (distance > system.mainPlanet.radius * 5) {
                    destinations2.push(possible);
                } else {
                    destinations1.push(possible);
                }
            }
        }
    }
    // no nearby destinations
    if (destinations1.length == 0) {
        destinations1 = destinations2;
    }
    // no destinations
    if (destinations1.length == 0) {
        return;
    }
    var destination = destinations1[Math.floor(Math.random() * destinations1.length)];
    if (destination.isPlanet) {
        // see if we've been given a landing site already
        var site = this.getParameter("oolite_landingSite");
        if (site) {
            // if so, make sure the planet matches the landing site
            var pl = worldScripts.PlanetFall2.$getPlanetFromLandingSite(site);
            // if it doesn't switch planets to this one
            if (destination != pl) destination = pl;
        } else {
            // if not, choose one now.
            site = worldScripts.planetFall2_priorityAI._chooseLandingSiteOnPlanet(destination);
        }
        // in case there are no landing sites on the chosen planet
        if (!site) return;
        this.setParameter("oolite_selectedPlanet", destination);
        this.setParameter("oolite_selectedStation", null);
        this.setParameter("oolite_landingSite", site);

        this.communicate("oolite_landingSite", site.linkedVE, 4);
    }
    else {
        this.setParameter("oolite_selectedStation", destination);
        this.communicate("oolite_selectedStation", destination, 4);
        this.setParameter("oolite_selectedPlanet", null);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.PF2_behaviourApproachDestination = function () {
    var handlers = {};
    this.responsesAddStandard(handlers);

    handlers.shipAchievedDesiredRange = this.responseComponent_standard_shipAchievedDesiredRange;

    var waypoints = this.getParameter("oolite_waypoints");
    if (waypoints != null) {
        this.ship.destination = waypoints[waypoints.length - 1];
        this.ship.desiredRange = 100;
    }
    var blocker = this.ship.checkCourseToDestination();
    if (blocker) {
        if (blocker.isPlanet || blocker.isSun) {
            var dist = this.distance(blocker);
            if (dist < blocker.radius * 1.3) {
                if (waypoints == null) {
                    waypoints = [];
                }
                waypoints.push(this.ship.position.subtract(blocker.position.subtract(this.ship.position)));
                this.ship.destination = waypoints[waypoints.length - 1];
                this.ship.desiredRange = 100;
            }
            else if (this.distance(blocker) < blocker.radius * 3) {
                if (waypoints == null) {
                    waypoints = [];
                }
                waypoints.push(this.ship.getSafeCourseToDestination());
                this.ship.destination = waypoints[waypoints.length - 1];
                this.ship.desiredRange = 100;
            }
        }
        else if (blocker.isShip) {
            if (this.distance(blocker) < this.scannerRange) {
                if (!blocker.group || !blocker.group.leader == this.ship) {
                    // our own escorts are not a blocker!
                    if (waypoints == null) {
                        waypoints = [];
                    }
                    waypoints.push(this.ship.getSafeCourseToDestination());
                    this.ship.destination = waypoints[waypoints.length - 1];
                    this.ship.desiredRange = 100;
                }
            }
        }
    }
    this.setParameter("oolite_waypoints", waypoints);
    this.applyHandlers(handlers);
    this.ship.performFlyToRangeFromDestination();
}

//-------------------------------------------------------------------------------------------------------------
this.PF2_behaviourLandOnPlanet = function () {
    this.ship.desiredSpeed = this.ship.maxSpeed / 4;
    //this.ship.performLandOnPlanet();
    this.ship.reactToAIMessage("LANDED_ON_PLANET");
    this.ship.AIScriptWakeTime = 0; // cancel reconsiderations
    this.applyHandlers({}); // cancel interruptions
    this.communicate("oolite_landingOnPlanet", {}, 4);
    // dock ship at location
    this.ship.remove(true); // this is a simulation, after all!
}

//-------------------------------------------------------------------------------------------------------------
this.PF2_configurationSetDestinationToSelectedPlanet = function () {
    var planet = this.getParameter("oolite_selectedPlanet");
    if (planet) {
        var site = this.getParameter("oolite_landingSite");
        if (site) {
            this.ship.destination = site.linkedVE;
            this.ship.desiredRange = 50;
            this.ship.desiredSpeed = this.cruiseSpeed();
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this._chooseLandingSiteOnPlanet = function (planet) {
    var ls = worldScripts.PlanetFall2.$getPlanetLandingSites(planet);
    var choices = [];
    for (var i = 0; i < ls.length; i++) {
        var num = this._landingPriorityForKey(ls[i].dataKey);
        for (var j = 1; j <= num; j++) choices.push(ls[i]);
    }
    // pick one
    return choices[Math.floor(Math.random() * choices.length)];
}

//-------------------------------------------------------------------------------------------------------------
this._landingPriorityForKey = function (shipKey) {
    var keys = Object.keys(this._landingPriority);
    for (var i = 0; i < keys.length; i++) {
        if (shipKey.indexOf(keys[i]) >= 0) return this._landingPriority[keys[i]];
    }
    return 0;
}
