"use strict";
this.name = "Warzone_Ship_Script";
this.author = "phkb, m4r35n357";
this.copyright = "© 2011 m4r35n357 (Ian Smith), Creative Commons: attribution, non-commercial, sharealike.";
this.description = "Warzone ship script";

this._escortsAttacking = false; // initialize

//-------------------------------------------------------------------------------------------------------------
// helpers
this.$longName = function (ship) {
    if (ship && ship.isValid) {
        if (ship === player.ship) {
            return "*PLAYER*";
        } else {
            return ship.displayName;
        }
    } else {
        return "[DEAD SHIP]";
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$safeExitAI = function (ship) {
    while (ship.hasSuspendedAI) {
        ship.exitAI();
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$intercept = function (ship, whom) {
    ship.target = whom;
    ship.setAI("interceptAI.plist");
    ship.reactToAIMessage("ATTACK_SHIP");
}

//-------------------------------------------------------------------------------------------------------------
this.$escortAttack = function (whom) {
    log(this.name + ".debug", this.$longName(this.ship) + ": Escorts, attack " + this.$longName(whom));
    if (this._escortsAttacking) {
        // already attacking, switch target
        for (var i = 0; i < this.ship.escorts.length; i++) {
            var escort = this.ship.escorts[i]
            if (escort.target !== whom) {
                log(this.name + ".debug", "  " + this.$longName(escort) + " now attacking " + this.$longName(whom));
                this.$safeExitAI(escort);
                this.$intercept(escort, whom);
            }
        }
    } else {
        // new target
        for (var i = 0; i < this.ship.escorts.length; i++) {
            var escort = this.ship.escorts[i];
            log(this.name + ".debug", "  " + this.$longName(escort) + " attacking " + this.$longName(whom));
            this.$intercept(escort, whom);
        }
        this._escortsAttacking = true;
    }
}

//-------------------------------------------------------------------------------------------------------------
// AI extension callbacks
this.$scanForTarget = function () {
    var targetFilter = function (entity) {
        return (entity._faction && (entity._faction.title !== this.ship._faction.title)) ||
            (entity.isPlayer && this.ship._faction.playerIsEnemy) ||
            (entity.isShip && entity.isPolice);
    };
    if (this.ship.position.distanceTo(this.ship.savedCoordinates) > 25600) {
        log(this.name + ".debug", this.$longName(this.ship) + " out of range, returning to battle: ");
        this.ship.reactToAIMessage("NOTHING_FOUND");
    } else {
        var targetsInRange = system.filteredEntities(this, targetFilter, this.ship, this.ship.scannerRange);
        log(this.name + ".debug", this.$longName(this.ship) + ": " + targetsInRange.length + "/" + system.filteredEntities(this, targetFilter).length + " in range");
        if (targetsInRange.length > 0) {
            // all ships
            if (this.ship._faction.playerHasKilled) {
                this.ship.target = player.ship;
            } else {
                this.ship.target = targetsInRange[Math.floor(Math.random() * targetsInRange.length)];
            }
            log(this.name + ".debug", this.$longName(this.ship) + " selected target: " + this.$longName(this.ship.target));
            this.ship.reactToAIMessage("TARGET_FOUND");
            // ships with escorts
            if (this.ship.escorts && (this.ship.escorts.length > 0)) {
                this.$escortAttack(this.ship.target);
            }
        } else {
            log(this.name + ".debug", this.$longName(this.ship) + " failed to find a target");
            this.ship.reactToAIMessage("NOTHING_FOUND");
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$help = function () {
    if (!this.ship.target || !this.ship.target.isValue) return;
    log(this.name + ".debug", this.$longName(this.ship) + ": Please help me, attack " + this.$longName(this.ship.target));
    if ((this.ship.target === player.ship) && !this.ship._faction.playerHasKilled) {
        this.ship.commsMessage("Foe identified as " + player.name + ", piloting a " + player.ship.name + ". Please assist!");
    }
    var buddies = system.filteredEntities(this, function (entity) {
        return entity._faction && (entity._faction.title === this.ship._faction.title);
    });
    for (var i = 0; i < buddies.length; i++) {
        var buddy = buddies[i];
        if (!buddy._isEscort && !buddy.hasHostileTarget && !(buddy === this.ship)) {
            buddy.target = this.ship.target;
            buddy.reactToAIMessage("TARGET_FOUND");
            log(this.name + ".debug", this.$longName(buddy) + " assisting . . . ");
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$newState = function () {
    switch (this.ship.AIState) {
        case "NO_WORMHOLE_FOUND":
        case "ENTER_WORMHOLE":
        case "EXIT_SYSTEM":
        case "FIND_ENEMIES":
        case "FLEE":
            log(this.name + ".debug", this.$longName(this.ship) + " entering state: " + this.ship.AIState);
            break;
        case "ATTACK_SHIP":
            log(this.name + ".debug", this.$longName(this.ship) + " entering state: " + this.ship.AIState + ", target: " + this.$longName(this.ship.target));
            break;
        case "RETURN_TO_BATTLE":
            log(this.name + ".debug", this.$longName(this.ship) + " entering state: " + this.ship.AIState);
            if (this.$checkForWin()) {
                if (this.ship.escorts && (this.ship.escorts.length > 0)) {
                    for (var i = 0; i < this.ship.escorts.length; i++) {
                        this.ship.escorts[i].switchAI("escortAI.plist");
                    }
                }
                if (this.ship._faction.systemID == system.ID) {
                    log(this.name + ".debug", "battle won, " + this.$longName(this.ship) + " heading for station");
                    this.ship.switchAI("warzoneEndAI.plist");
                } else {
                    // for non-indigenous ships, we need to jump them out.
                    log(this.name + ".debug", "battle won, " + this.$longName(this.ship) + " heading home to " + System.systemNameForID(this.ship._faction.systemID));
                    // send them home after a delay
                    this.ship.destinationSystem = this.ship._faction.systemID;
                    this._timer = new Timer(this, this.$tryLeaving.bind(this), 7, 0);
                }
            }
            break;
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$tryLeaving = function $tryLeaving() {
    if (this._timer && this._timer.isRunning) this._timer.stop();
    if (!this.ship.isValid) return;
    // if something has happened since the end of the battle and getting to this point
    if (this.ship.hasHostileTarget) return;
    this.ship.switchAI("warzoneReturnAI.plist");
    this.$leaveSystem();
}

//-------------------------------------------------------------------------------------------------------------
this.$leaveSystem = function() {
    var found = this.$scanForWormhole();
    if (found) {
        this.ship.performFlyToRangeFromDestination();
        this._timer = new Timer(this, this.$keepGoing.bind(this), 3, 0);
        return;
    }
    if (this.ship.hasHyperspaceMotor) {
        if (!this.ship.exitSystem(this.ship.destinationSystem)) {
            // this shouldn't be needed, but just in case
            this._timer = new Timer(this.$tryAgain.bind(this), 3, 0);
        }
        return;
    } else {
        this._timer = new Timer(this, this.$checkAgain.bind(this), 3, 0);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$keepGoing = function $keepGoing() {
    this._timer.stop();
    if (!this.ship.isValid) return;
    if (this.ship.hasHostileTarget) {
        // keep coming back here until the new issue is resolved
        this._timer = new Timer(this, this.$keepGoing.bind(this), 3, 0);
        return;
    }
    this.ship.destination = this.ship._holdDestination;
    this.ship.desiredRange = 1;
    this.ship.performFlyToRangeFromDestination();
    this._timer = new Timer(this, this.$keepGoing.bind(this), 3, 0);
}

//-------------------------------------------------------------------------------------------------------------
this.$tryAgain = function $tryAgain() {
    this._timer.stop();
    if (!this.ship.isValid) return;
    if (!this.ship.exitSystem(this.ship.destinationSystem)) {
        this._timer = new Timer(this.$tryAgain.bind(this), 3, 0);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$checkAgain = function $checkAgain() {
    this._timer.stop();
    if (!this.ship.isValid) return;
    var found = this.$scanForWormhole();
    if (found) {
        this.ship.performFlyToRangeFromDestination();
        this._timer = new Timer(this, this.$keepGoing.bind(this), 3, 0);
        return;
    }
    this._timer = new Timer(this, this.$checkAgain.bind(this), 3, 0);
}

//-------------------------------------------------------------------------------------------------------------
this.$scanForWormhole = function() {
    log(this.name + ".debug", this.ship.displayName + " -- scanning for wormhole");
    var w = system.wormholes;
    var i = w.length;
    while (i--) {
        var wh = w[i];
        if (wh.destination == this.ship.destinationSystem && this.ship.position.distanceTo(wh) < (player.ship.scannerRange * 3)) {
            log(this.name + ".debug", this.ship.displayName + " -- found wormhole");
            this.ship.destination = wh.position;
            this.ship.desiredRange = 1;
            this.ship._holdDestination = wh.position;
            return true;
        }
    }
    log(this.name + ".debug", this.ship.displayName + " -- no wormhole found");
    return false;
}

//-------------------------------------------------------------------------------------------------------------
this.$exitSystem = function() {
    log(this.name + ".debug", this.ship.displayName + " -- exiting system");
    this.ship.exitSystem(this.ship.homeSystem);
}

//-------------------------------------------------------------------------------------------------------------
this.$checkForWin = function() {
    return (system.countShipsWithRole(this.ship._faction.oppositeRole) == 0);
}

//-------------------------------------------------------------------------------------------------------------
// Regular callbacks
this.shipBeingAttacked = function (whom) {
    // all ships
    if (whom && whom._faction && (this.ship._faction === whom._faction)) {
        if (whom._isEscort) {
            whom.reactToAIMessage("TARGET_LOST");
        } else {
            if (!whom.isPlayer) whom.reactToAIMessage("FRIENDLY_FIRE");
        }
        this.ship.reactToAIMessage("FRIENDLY_FIRE");
        log(this.name + ".debug", "Friendly fire incident against " + this.$longName(this.ship) + " by " + this.$longName(whom) + "!");
    } else {
        log(this.name + ".extra.debug", this.$longName(this.ship) + " being attacked by " + this.$longName(whom));
        if ((whom === player.ship) && !this.ship._faction.playerIsEnemy) {
            this.ship._faction.playerIsEnemy = true;
            log(this.name + ".debug", this.$longName(player.ship) + " is now an enemy of: " + this.ship._faction.title);
            this.ship.commsMessage("Unknown foe detected, piloting a " + player.ship.name);
        }
        // ships with escorts
        if (this.ship.escorts && (this.ship.escorts.length > 0)) {
            this.$escortAttack(whom);
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.shipTargetLost = function (target) {
    // ships with escorts
    if (this.ship.escorts && (this.ship.escorts.length > 0)) {
        log(this.name + ".debug", this.$longName(this.ship) + ": Escorts, heel!");
        if (this._escortsAttacking) {
            for (var i = 0; i < this.ship.escorts.length; i++) {
                var escort = this.ship.escorts[i];
                log(this.name + ".debug", "  " + this.$longName(escort) + " returning to escort duty");
                this.$safeExitAI(escort);
            }
            this._escortsAttacking = false;
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.shipDied = function (whom, why) {
    if (this._timer && this._timer.isRunning) this._timer.stop();
    // all ships
    log(this.name + ".debug", this.$longName(this.ship) + " killed by " + this.$longName(whom) + " (" + why + ")");
    if (whom === player.ship) {
        this.ship._faction.playerHasKilled = true;
        log(this.name + ".debug", this.$longName(player.ship) + " is now a mortal enemy of: " + this.ship._faction.title);
        this.ship.commsMessage("Avenge me, destroy " + player.name + "!!!");
    }
    // ships with escorts
    if (this.ship.escorts && (this.ship.escorts.length > 0)) {
        for (var i = 0; i < this.ship.escorts.length; i++) {
            var escort = this.ship.escorts[i];
            log(this.name + ".debug", "  " + this.$longName(escort) + " joining battle!");
            this.ship._isEscort = false;
            escort.switchAI("warzoneAI.plist");
            escort.setScript("warzone_ship_script.js");
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillEnterWitchspace = function() {
    if (this._timer && this._timer.isRunning) this._timer.stop();
}
