"use strict";
this.name = "PlanetFall2_Transit";
this.author = "Thargoid, phkb, with bits from Eric Walch, Frame and Svengali";
this.copyright = "Creative Commons Attribution - Non-Commercial - Share Alike 3.0 license with clauses - see readme.txt.";
this.description = "Allows player to move between planetary locations without manually launching and redocking";

this._pf;
this._default = "";
this._hairSpace = String.fromCharCode(31);
this._hairSpaceLength = defaultFont.measureString(this._hairSpace);
this._ellip = "…";

//-------------------------------------------------------------------------------------------------------------
this.startUpComplete = function () {
    this._pf = worldScripts.PlanetFall2;
    // make sure we have the variable set
    if (!missionVariables.PlanetFall2_DockedStation && player.ship.dockedStation.hasRole("planetFall2_surface")) {
        missionVariables.PlanetFall2_DockedStation = player.ship.dockedStation.dataKey;
    }
    this.shipDockedWithStation(player.ship.dockedStation);
}

//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation = function (station) {
    if (station.hasRole("planetFall2_surface") && this._pf._config.transit.allowed) {
        this._cleanupTimer = new Timer(this, this.$clearUpF4Interfaces, 1, 0);
        // count the number of sites on this planet
        var sub = this.$surfaceSites();
        if (sub.length == 1) {
            station.setInterface(this.name, null);
            station.setInterface(this.name + "_2", null);
            return;
        }
        this.$initInterface(station);
    } else {
        station.setInterface(this.name, null);
        station.setInterface(this.name + "_2", null);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$surfaceSites = function (excl) {
    var pl = this._pf.$getPlanetFromCoords(player.ship.dockedStation.linkedPlanetPos)
    var stns = system.shipsWithRole("planetFall2_surface");
    var sub = [];
    var i = stns.length;
    while (i--) {
        if (this._pf.$getPlanetFromCoords(stns[i].linkedPlanetPos) == pl && stns[i].allegiance != "restricted") {
            if (!excl || stns[i] != excl) sub.push(stns[i]);
        }
    }
    return sub;
}

//-------------------------------------------------------------------------------------------------------------
this.$initInterface = function $initInterface(station) {
    station.setInterface(this.name, {
        title: expandMissionText("planetFall2_transit_interface_title"),
        category: expandMissionText("planetFall2_transit_interface_category"),
        summary: expandMissionText("planetFall2_transit_interface_summary"),
        callback: this.$showStationList.bind(this)
    });
    if (missionVariables.PlanetFall2_DockedStation != station.dataKey) {
        station.setInterface(this.name + "_2", {
            title: expandMissionText("planetFall2_transfer_interface_title"),
            category: expandMissionText("planetFall2_transit_interface_category"),
            summary: expandMissionText("planetFall2_transfer_interface_summary"),
            callback: this.$transferShip.bind(this)
        });
    } else {
        station.setInterface(this.name + "_2", null);
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$showStationList = function () {
    var curChoices = {};
    var text = "";
    var col1 = 23;
    var col2 = 2
    var col3 = 30 - (col1 + col2);
    var tffee = parseInt(this._pf._config.shipTransfer.fee * this._pf._config.shipTransfer.governmentFactor[system.government]);
    var tm = this._pf._config.shipTransfer.time;
    var fee = parseInt(this._pf._config.transit.fee * this._pf._config.transit.governmentFactor[system.government]);
    
    // free transit costs for citizens
    if (worldScripts.Diplomacy_060_Citizenships) {
        var dc = worldScripts.Diplomacy_060_Citizenships;
        if (dc.$hasPlayerCitizenship(galaxyNumber, system.ID)) fee = 0;
    }
    // free transit costs for home system members with enough standing
    if (worldScripts.HomeSystem) {
        var hs = worldScripts.HomeSystem;
        if (hs.$checkLevel(system.ID, "dock_fee") === true) fee = 0;
    }

    text = expandMissionText("planetFall2_location", { name: player.ship.dockedStation.displayName }) + "\n";
    text += expandMissionText("planetFall2_transit_info", {
        cost: (fee > 0 ? expandMissionText("planetFall2_transit_cost", { amount: formatCredits(fee, false, true) }) : expandMissionText("planetFall2_transit_free"))
    });

    var top = 13;
    if (player.ship.hudAllowsBigGui) top = 19;

    if (missionVariables.PlanetFall2_DockedStation == player.ship.dockedStation.dataKey) {
        text += expandMissionText("planetFall2_ship_location", { fee: formatCredits(tffee, false, true), time: tm.toFixed(1) });
        top -= 2;
    } else {
        text += expandMissionText("planetFall2_ship_elsewhere", { fee: formatCredits(tffee, false, true), time: tm.toFixed(1) });
    }
    var sites = this.$surfaceSites(player.ship.dockedStation);

    curChoices["00_A"] = {
        text: this.$padText(expandMissionText("planetFall2_destination"), col1 + col2) + this.$padText(expandMissionText("planetFall2_travel_time"), col3, true),
        color: "0 0.6 0 1",
        alignment: "LEFT",
        unselectable: true
    };
    for (var i = 0; i < sites.length; i++) {
        curChoices["0" + i.toString() + "_SITE"] = {
            text: this.$padText(sites[i].displayName, col1) +
                this.$padText((missionVariables.PlanetFall2_DockedStation == sites[i].dataKey ? "*" : ""), col2) +
                this.$padText(expandMissionText("planetFall2_time", { mins: this.$travelTime(sites[i]).toString() }), col3, true),
            color: (player.credits < fee && missionVariables.PlanetFall2_DockedStation != sites[i].dataKey ? "darkGrayColor" : "greenColor"),
            alignment: "LEFT",
            unselectable: (player.credits < fee && missionVariables.PlanetFall2_DockedStation != sites[i].dataKey ? true : false)
        };
    }
    var extra = 0;
    if (missionVariables.PlanetFall2_DockedStation != player.ship.dockedStation.dataKey) {
        extra += 1;
        curChoices["90_A"] = {
            text: expandMissionText("planetFall2_ship_here"),
            color: "grayColor",
            alignment: "LEFT",
            unselectable: true
        };
    }

    if (fee > 0 && player.credits < fee * 2 && player.credits >= fee) {
        extra += 1;
        curChoices["91_A"] = {
            text: expandMissionText("planetFall2_insufficient_funds"),
            color: "whiteColor",
            unselectable: true
        };
    }

    for (var i = 0; i < (top - (sites.length + extra)); i++) {
        curChoices["98_SPACER_" + i.toString()] = {
            text: "",
            unselectable: true
        };
    }

    curChoices["99_EXIT"] = expandMissionText("planetFall2_exit");
    if (this._default == "") this._default = "99_EXIT";

    var opts = {
        screenID: "oolite-planetfall-dockside-map",
        titleKey: "planetFall2_transit_interface_title",
        overlay: { name: "planetFall2_train_ovr.png", height: 546 },
        allowInterrupt: true,
        exitScreen: "GUI_SCREEN_INTERFACES",
        initialChoicesKey: this._default,
        choices: curChoices,
        message: text
    };
    mission.runScreen(opts, this.$screenHandler, this);
}

//-------------------------------------------------------------------------------------------------------------
this.$screenHandler = function (choice) {
    if (choice == null) return;

    if (choice.indexOf("_SITE") >= 0) {
        if (!missionVariables.PlanetFall2_DockedStation) {
            missionVariables.PlanetFall2_DockedStation = player.ship.dockedStation.dataKey;
        }
        delete player.ship.dockedStation._dockedViaED;
        var idx = parseInt(choice.substring(0, 2));
        var sub = this.$surfaceSites(player.ship.dockedStation);

        // change the player for the trip
        var fee = parseInt(this._pf._config.transit.fee * this._pf._config.transit.governmentFactor[system.government]);
        if (fee > player.credits) fee = player.credits;
        player.credits -= fee;

        this.$beginJourney(sub[idx]);
        return;
    }
    if (choice != "99_EXIT") {
        this.$showStationList();
    }
}

//-------------------------------------------------------------------------------------------------------------
// returns traveltime in minutes
this.$travelTime = function (dest) {
    var point1 = player.ship.dockedStation.linkedVE;
    var point2 = dest.linkedVE;
    // this is the direct distance between two points
    var dist = this.$distance(this._pf.$getPlanetFromCoords(player.ship.dockedStation.linkedPlanetPos), point1.position, point2.position);
    // because the journey is unlikely to be perfectly straight, lets add some variation.
    // something between 1.5 and 2.5
    var mult = system.scrambledPseudoRandomNumber(point1._seed + point2._seed) + 1;
    dist *= mult;
    return Math.floor(((dist / 1000) / this.$getTrainSpeed() * 60));
}

//-------------------------------------------------------------------------------------------------------------
// gets distance between two points on a sphere
this.$distance = function (planet, point1, point2) {
    var p1 = Vector3D(point1.x - planet.position.x, point1.y - planet.position.y, point1.z - planet.position.z);
    var p2 = Vector3D(point2.x - planet.position.x, point2.y - planet.position.y, point2.z - planet.position.z);
    return planet.radius * Math.acos((p1.dot(p2)) / (planet.radius * planet.radius));
}

//-------------------------------------------------------------------------------------------------------------
this.$getTrainSpeed = function () {
    var tlFactor = this._pf.$getTLFactor("main"); // we'll just use the main planet's TL factor for this
    return this._pf._config.transit.trainSpeed * tlFactor;
}

//-------------------------------------------------------------------------------------------------------------
this.$transferShip = function () {
    var curChoices = {};
    var text = "";
    var fee = parseInt(this._pf._config.shipTransfer.fee * this._pf._config.shipTransfer.governmentFactor[system.government]);
    var tm = this._pf._config.shipTransfer.time;

    text = expandMissionText("planetFall2_transfer_service", { cost: formatCredits(fee, false, true), time: tm.toFixed(1) });
    curChoices["01_YES"] = {
        text: expandMissionText("planetFall2_yes"),
        unselectable: (player.credits < fee ? true : false)
    };
    curChoices["02_NO"] = {
        text: expandMissionText("planetFall2_no"),
        unselectable: false
    };

    var opts = {
        screenID: "oolite-planetfall-dockside-map",
        titleKey: "planetFall2_transfer_interface_title",
        overlay: { name: "planetFall2_rocket.png", height: 546 },
        allowInterrupt: true,
        exitScreen: "GUI_SCREEN_INTERFACES",
        choices: curChoices,
        message: text
    };
    mission.runScreen(opts, this.$transferHandler, this);
}

//-------------------------------------------------------------------------------------------------------------
this.$transferHandler = function (choice) {
    if (!choice || choice == "02_NO") return;

    if (choice == "01_YES") {
        var fee = parseInt(this._pf._config.shipTransfer.fee * this._pf._config.shipTransfer.governmentFactor[system.government]);
        player.credits -= fee;
        var tm = this._pf._config.shipTransfer.time * 3600;
        clock.addSeconds(tm);
        player.consoleMessage(expandMissionText("planetFall2_ship_transferred", { cost: formatCredits(fee, false, true) }));

        // repoint eds at the new station
        var station = player.ship.dockedStation;
        station.setInterface(this.name + "_2", null);
        missionVariables.PlanetFall2_DockedStation = station.dataKey;

        var ed = worldScripts.ExternalDockSystem._externalDocks;
        for (var i = 0; i < ed.length; i++) {
            if (ed[i].station.dataKey == station.dataKey) {
                // set the property on the new station
                station._dockedViaED = ed[i];
            } else {
                // remove it from any other station
                if (ed[i].station.hasOwnProperty("_dockedViaED")) {
                    delete ed[i].station._dockedViaED;
                }
            }
        }

    }
}

//-------------------------------------------------------------------------------------------------------------
// appends space to currentText to the specified length in 'em'
this.$padText = function _pfShipyards_padText(currentText, desiredLength, leftSwitch, centreSwitch) {
    var that = _pfShipyards_padText;
    var hairSpace = (that.hairSpace = that.hairSpace || this._hairSpace);
    var ellip = (that.ellip = that.ellip || this._ellip);
    var hairSpaceLength = (that.hairSpaceLength = that.hairSpaceLength || this._hairSpaceLength);
    var measure = (that.measure = that.measure || defaultFont.measureString);

    if (currentText == null) currentText = "";
    var currentLength = measure(currentText.replace(/%%/g, "%"));
    // calculate number needed to fill remaining length
    var padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
    if (padsNeeded < 1) {
        // text is too long for column, so start pulling characters off
        var tmp = currentText;
        do {
            tmp = tmp.substring(0, tmp.length - 2) + ellip;
            if (tmp === ellip) break;
        } while (measure(tmp.replace(/%%/g, "%")) > desiredLength);
        currentLength = measure(tmp.replace(/%%/g, "%"));
        padsNeeded = ~~((desiredLength - currentLength) / hairSpaceLength);
        currentText = tmp;
    }
    // quick way of generating a repeated string of that number
    if (!leftSwitch || leftSwitch === false) {
        if (!centreSwitch || centreSwitch === false) {
            return currentText + new Array(padsNeeded).join(hairSpace);
        } else {
            return currentText + new Array(parseInt(padsNeeded / 2)).join(hairSpace);
        }
    } else {
        if (!centreSwitch || centreSwitch === false) {
            return new Array(padsNeeded).join(hairSpace) + currentText;
        } else {
            return new Array(parseInt(padsNeeded / 2)).join(hairSpace) + currentText;
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillLaunchFromStation_train = function () {
    player.ship.hudHidden = true;
    this.$playSound("depart");

    this.planetFallLaunch = true;
    // create the image behind the player initially, to give it time to load
    var fx = system.addVisualEffect("planetFall2_trainFX1", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
    // then put it in front of the player.
    fx.position = player.ship.position.add(player.ship.vectorForward.multiply(this.fx_launch_dist));
}

//-------------------------------------------------------------------------------------------------------------
this.shipLaunchedFromStation_train = function () {
    if (this.destination && this.destination.isValid) {
        this.destination.dockOK = true;
        this.destination.performedDockRequest = true;
        this.destination.dockPlayer();
    }
}

//-------------------------------------------------------------------------------------------------------------
this.shipWillDockWithStation_train = function (station) {
    // just turn off docking fees for this dock, rather than doing anything else funky
    if (worldScripts["Docking Fees"]) {
        worldScripts["Docking Fees"]._simulator = true;
    }
    this.$playSound("arrive");

    player.addMessageToArrivalReport(expandMissionText("planetFall2_arrive_system", { name: station.displayName }));
    this.background = "planetFall2_train_" + (Math.floor(Math.random() * 7) + 1) + ".png";
    this.overlay = "";

    var p = player.ship;
    this.$clearStationState();

    this.fx_mult = 1.0;
    // initially place the image behind the player to give it time to load in.
    var fx = system.addVisualEffect("planetFall2_trainFX2", Vector3D(25, 25, 25).fromCoordinateSystem("psu"));
    fx.orientation = p.orientation;
    // then put it in front of the player
    fx.position = p.position.add(p.vectorForward.multiply(this.fx_launch_dist));
}

//-------------------------------------------------------------------------------------------------------------
this.shipDockedWithStation_train = function (station) {
    worldScripts.PlanetFall2_Transit.$resetEvents();
    this.destination = null;
    var p = player.ship;
    p.hudHidden = false;
    p.hud = this.savedHUD;
    this.savedHUD = "";

    // repoint eds at the new station
    var ed = worldScripts.ExternalDockSystem._externalDocks;
    for (var i = 0; i < ed.length; i++) {
        if (ed[i].station.dataKey == station.dataKey) {
            p.dockedStation._dockedViaED = ed[i];
        } else {
            // remove it from any other station
            if (ed[i].station.hasOwnProperty("_dockedViaED")) {
                delete ed[i].station._dockedViaED;
            }
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$resetEvents = function () {
    this._pf.shipWillLaunchFromStation = this._pf.hold_shipWillLaunchFromStation;
    this._pf.shipLaunchedFromStation = this._pf.hold_shipLaunchedFromStation;
    this._pf.shipWillDockWithStation = this._pf.hold_shipWillDockWithStation;
    delete this._pf.shipDockedWithStation;

    var eds = worldScripts.ExternalDockSystem;
    eds.shipWillLaunchFromStation = eds.hold_shipWillLaunchFromStation;
    delete eds.hold_shipWillLaunchFromStation;

    if (worldScripts.VimanaX_HUD) {
        var vx = worldScripts.VimanaX_HUD;
        vx.shipDockedWithStation = vx.hold_shipDockedWithStation;
        delete vx.hold_shipDockedWithStation;
        vx.shipWillLaunchFromStation = vx.hold_shipWillLaunchFromStation;
        delete vx.hold_shipWillLaunchFromStation;
    }

    if (worldScripts.hudselector) {
        var hs = worldScripts.hudselector;
        hs.shipWillLaunchFromStation = hs.hold_shipWillLaunchFromStation;
        delete hs.hold_shipWillLaunchFromStation;
        hs.shipLaunchedFromStation = hs.hold_shipLaunchedFromStation;
        delete hs.hold_shipLaunchedFromStation;
        hs.shipWillDockWithStation = hs.hold_shipWillDockWithStation;
        delete hs.hold_shipWillDockWithStation;
    }

    if (worldScripts.CommsLogMFD) {
        var cl = worldScripts.CommsLogMFD;
        cl.shipLaunchedFromStation = cl.hold_shipLaunchedFromStation;
        cl.shipWillDockWithStation = cl.hold_shipWillDockWithStation;
        delete cl.hold_shipLaunchedFromStation;
        delete cl.hold_shipWillDockWithStation;
    }
}

//-------------------------------------------------------------------------------------------------------------
this.$beginJourney = function (destination) {
    this._pf.destination = destination;
    var time = (this.$travelTime(destination) + 15) * 60; // convert to seconds
    clock.addSeconds(time);

    // set up events for train travel
    this._pf.hold_shipWillLaunchFromStation = this._pf.shipWillLaunchFromStation;
    this._pf.hold_shipLaunchedFromStation = this._pf.shipLaunchedFromStation;
    this._pf.hold_shipWillDockWithStation = this._pf.shipWillDockWithStation;
    this._pf.shipWillLaunchFromStation = this.shipWillLaunchFromStation_train;
    this._pf.shipLaunchedFromStation = this.shipLaunchedFromStation_train;
    this._pf.shipWillDockWithStation = this.shipWillDockWithStation_train;
    this._pf.shipDockedWithStation = this.shipDockedWithStation_train;

    var eds = worldScripts.ExternalDockSystem;
    eds.hold_shipWillLaunchFromStation = eds.shipWillLaunchFromStation;
    delete eds.shipWillLaunchFromStation;

    if (worldScripts.VimanaX_HUD) {
        var vx = worldScripts.VimanaX_HUD;
        vx.hold_shipDockedWithStation = vx.shipDockedWithStation;
        delete vx.shipDockedWithStation;
        vx.hold_shipWillLaunchFromStation = vx.shipWillLaunchFromStation;
        delete vx.shipWillLaunchFromStation;
    }

    if (worldScripts.hudselector) {
        var hs = worldScripts.hudselector;
        hs.hold_shipWillLaunchFromStation = hs.shipWillLaunchFromStation;
        delete hs.shipWillLaunchFromStation;
        hs.hold_shipLaunchedFromStation = hs.shipLaunchedFromStation;
        delete hs.shipLaunchedFromStation;
        hs.hold_shipWillDockWithStation = hs.shipWillDockWithStation;
        delete hs.shipWillDockWithStation;
    }

    // prevent commslog MFD from transmitting the "launched in"/"docked in" messages
    if (worldScripts.CommsLogMFD) {
        var cl = worldScripts.CommsLogMFD;
        cl.hold_shipLaunchedFromStation = cl.shipLaunchedFromStation;
        cl.hold_shipWillDockWithStation = cl.shipWillDockWithStation;
        delete cl.shipLaunchedFromStation;
        delete cl.shipWillDockWithStation;
    }

    this._pf.fx_mult = 2.0;
    this._pf.savedHUD = player.ship.hud;
    player.ship.hud = "planetFall2_hud.plist";
    // "launch" the player onto the train!
    player.ship.launch();
}

//-------------------------------------------------------------------------------------------------------------
// removes some interfaces that wouldn't make sense if the player isn't local to their ship anymore
this.$clearUpF4Interfaces = function $clearUpF4Interfaces() {
    var stn = player.ship.dockedStation;
    if (!stn) return;
    if (stn.hasRole("planetFall2_surface") && missionVariables.PlanetFall2_DockedStation != stn.dataKey) {
        stn.setInterface("LaserArrangement", null);
        stn.setInterface("LMSS_Core", null);
    }
}