"use strict";

// worldScripts.world_builder

this.name = "world_builder";

this._currentMenuKey    = null;
this._currentBackground = null;
this._currentLayer      = 2;
this._currentOwner      = this.oolite_manifest_identifier;
this._propertyToChange  = null;

/* ========================================================
	ALL THE PROPERTY-SPECIIC HELP MESSAGES
=========================================================== */

this._messageTexts = function () {
    const messages = {
        name: "Enter a new value for 'name'.\n" +
              "- A text string naming the planet.\n" +
              "- Example: 'Alpha Centauri', 'Tionisla'.",

        economy: "Enter a new value for 'economy'.\n" +
                 "- Valid range: 0 to 7 (integer).\n" +
                 "- Represents the economic type of the system.\n" +
                 "- Default descriptions, if economy_description is not set,\n" +
                 "- are in descriptions.plist, not in planetinfo.plist:\n" +
                 "- 0: Rich Industrial\n" +
                 "- 1: Average Industrial\n" +
                 "- 2: Poor Industrial\n" +
                 "- 3: Mainly Industrial\n" +
                 "- 4: Mainly Agricultural\n" +
                 "- 5: Rich Agricultural\n" +
                 "- 6: Average Agricultural\n" +
                 "- 7: Poor Agricultural",

        economy_description: "Enter a new value for 'economy_description'.\n" +
                             "- A free-form text string describing the economy.\n" +
                             "- Example: 'Rich Industrial', 'Average Agricultural'.",

        government: "Enter a new value for 'government'.\n" +
                    "- Valid range: 0 to 7 (integer).\n" +
                    "- Represents the government type of the system.\n" +
                    "- Example: 0 = Anarchy, 7 = Corporate State.\n" +
                    "- Default descriptions, if government_description is not set,\n" +
                    "- are in descriptions.plist, not in planetinfo.plist:\n" +
                    "- 0: Anarchy\n" +
                    "- 1: Feudal\n" +
                    "- 2: Multi-Government\n" +
                    "- 3: Dictatorship\n" +
                    "- 4: Communist\n" +
                    "- 5: Confederacy\n" +
                    "- 6: Democracy\n" +
                    "- 7: Corporate State",

        government_description: "Enter a new value for 'government_description'.\n" +
                                "- A free-form text string describing the government.\n" +
                                "- Example: 'Corporate State', 'Feudal'.",

        techlevel: "Enter a new value for 'techlevel'.\n" +
                   "- Valid range: 0 to 15 (integer).\n" +
                   "- Represents the technological sophistication of the planet.\n" +
                   "- On F7, this is displayed as techlevel + 1 (e.g., setting 0 displays as 1).",

        population: "Enter a new value for 'population'.\n" +
                    "- Valid range: 0 to 100 (integer).\n" +
                    "- Represents the population in hundreds of millions.\n" +
                    "- On F7, this is displayed as 'Population: X.X Billion' (e.g., population = 14 becomes 'Population: 1.4 Billion').",

        population_description: "Enter a new value for 'population_description'.\n" +
                                "- Overrides the default text used to describe the population.\n" +
                                "- Example: '7 Castaways', '13 Billion'.",

        inhabitant: "Enter a new value for 'inhabitant' (singular phrase).\n" +
                    "- A free-form text string describing the inhabitants.\n" +
                    "- Example: 'Human Colonist', 'Rodent-Ruined Reptile'.\n" +
                    "- Remember to stay aligned with inhabitants (plural phrase).",

        inhabitants: "Enter a new value for 'inhabitants' (plural phrase).\n" +
                     "- A free-form text string describing the inhabitants.\n" +
                     "- Example: 'Human Colonists', 'Rodent-Ruined Reptiles'.\n" +
                     "- Remember to also update inhabitant (singular phrase).",

        productivity: "Enter a new value for 'productivity'.\n" +
                      "- A whole number representing gross productivity in MegaCredits (MCr).\n" +
                      "- On F7, this is displayed as 'Gross Productivity: X MCr'.\n" +
                      "- Its role in game mechanics is unclear; it may be purely cosmetic.",

        radius: "Enter a new value for 'radius'.\n" +
                "- Valid range: 3000 to 7000 (integer). (Limits unconfirmed.)\n" +
                "- The radius of the planet. On F7, this is displayed as kilometres.\n" +
                "- The radius in game is 1/100th of this.\n" +
                "- Pro-tip: setting radius to 0 suppresses the image on F7 screen.",

        description: "Enter a new value for 'description'.\n" +
                     "- A free-form text string describing the planet.\n" +
                     "- Use this field creatively to add flavour to your worlds.\n" +
                     "- Example: 'This is a dull planet.', 'This world is scourged by disease, civil war and solar flares.'",

        visits: "The value for 'visits' is maintained by Explorers' Club, version 1.5 or later.\n" +
                "- Counts the number of times the player has visited this system.",

        corona_flare: "Enter a new value for 'corona_flare'.\n" +
                      "- Sets the overall size of the corona in proportion to its sun.\n" +
                      "- Valid range: 0.0 (invisibly small) to 1.0 (huge).\n" +
                      "- Example: '0.075' creates a moderately sized corona.",

        corona_hues: "Enter a new value for 'corona_hues'.\n" +
                     "- Specifies whether the corona should have visible bands of colors within the corona.\n" +
                     "- Valid range: 0.0 (monochromatic) to 1.0 (vivid alternating colors).\n" +
                     "- Example: '0.6' creates vivid but not overly contrasting color bands.",

        corona_shimmer: "Enter a new value for 'corona_shimmer'.\n" +
                        "- Specifies how quickly the corona colors change.\n" +
                        "- Valid range: 0.0 (very slow) to 1.0 (very fast).\n" +
                        "- Example: '0.4' creates a moderate shimmer effect.",

        sun_color: "Enter a new value for 'sun_color'.\n" +
                   "- Sets the color of a system's sun.\n" +
                   "- Can be any color specifier or named color (e.g., 'blueColor', 'redColor').\n" +
                   "- The specified color is blended with 50% white, so it will never be fully saturated.\n" +
                   "- Dark colors will appear brighter due to this blending.\n" +
                   "- Example: 'blueColor' creates a bright blue sun.",

        sun_distance: "Enter a new value for 'sun_distance'.\n" +
                      "- Sets the distance between the sun and the main planet in meters.\n" +
                      "- Ignored if 'sun_distance_modifier' is set.\n" +
                      "- Example: '924122' sets the sun at approximately 924 kilometers from the planet.",

        sun_distance_multiplier: "Enter a new value for 'sun_distance_multiplier'.\n" +
                                 "- Multiplies the distance between the sun and the main planet by this factor.\n" +
                                 "- Ignored if 'sun_distance_modifier' is set.\n" +
                                 "- Example: '2' doubles the default distance between the sun and the planet.",

        sun_distance_modifier: "Enter a new value for 'sun_distance_modifier'.\n" +
                               "- Sets the approximate distance between a system's sun and its main planet.\n" +
                               "- The standard distance is 20 planetary radii. Lower values (e.g., 10 or less) may cause delays when generating systems due to potential collisions.\n" +
                               "- In Oolite 1.81 or later, 'sun_distance_multiplier' is more useful.\n" +
                               "- Example: '15.0' sets the sun at 15 times the planet's radius.",

        sun_gone_nova: "Enter a new value for 'sun_gone_nova'.\n" +
                       "- Sets whether the system's sun has gone nova.\n" +
                       "- Valid values: 'YES' or 'NO'.\n" +
                       "- Example: 'YES' creates a nova sun in the system.",

        sun_name: "Enter a new value for 'sun_name'.\n" +
                  "- Stores the name of a system's sun.\n" +
                  "- This feature is only implemented in Oolite version 1.79 onwards.\n" +
                  "- Example: 'Alpha Centauri' names the sun accordingly.",

        sun_radius: "Enter a new value for 'sun_radius'.\n" +
                    "- Sets the radius of a system's sun in kilometers.\n" +
                    "- Valid range: 1000 to 1000000.\n" +
                    "- Example: '100000' creates a sun with a radius of 100,000 kilometers.",

        sun_vector: "Enter a new value for 'sun_vector'.\n" +
                    "- Specifies the direction of the sun relative to the main planet.\n" +
                    "- Format: A vector with three components (x, y, z).\n" +
                    "- Example: '-0.717 -0.668 0.201' defines the sun's position.",

        default: "You are setting the '" + this._propertyToChange + "' property.\n" +
                 "Sorry, no out-of-range validation will be done - you should know what you are doing."
    };

    // Return the appropriate message based on this._propertyToChange
    return messages[this._propertyToChange] || messages.default;
};

/* ========================================================
	DEFINITIONS OF ALL THE SHORT-CUT MENUS
=========================================================== */

this._menuItems = {
    world_builder: [
        "Enter the property to change (case-sensitive), or enter 'HELP'. Below are some of the available properties:",
        "name",
        "economy",
        "economy_description",
        "government",
        "government_description",
        "techlevel",
        "population",
        "population_description",
        "inhabitants",
        "productivity",
        "radius",
        "description"
    ],
    HELP: [
        "Enter a keyword (ALL-CAPS) for a menu of relevant properties to change:",
        "PEOPLE",
        "PLANET",
        "ATMOSPHERE",
        "SKY",
        "STATION",
        "SUN",
        "READONLY"
    ],
    EXPERT: [
        "Enter a keyword (ALL-CAPS) for a menu of relevant properties to change:",
        "EXTRAS",
        "LAYER",
        "OWNER",
        "SYSTEM",
        "READONLY"
    ],
    OWNER: [
        "Enter the oolite_manifest_identifier (case-sensitive) of a currently loaded OXP. Below are some recently used:",
        "oolite.oxp.Wildeblood.World_Builder",
        "oolite.oxp.Wildeblood.Thargoidifier",
        "oolite.oxp.Wildeblood.Lost_In_Space",
        "oolite.oxp.Wildeblood.Dynooverse",
        "oolite.oxp.Wildeblood.Witches_of_Middlemap",
        "org.oolite.oolite.debug"
    ],
    LAYER: [ // This menu is exceptional: header comment is last item, instead of first - this is deliberate.
        "DEFAULT",
        "STATIC",
        "DYNAMIC",
        "PRIORITY",
        "Enter the layer at which system information over-rides should take effect. Only enter a number, not a word:"
    ],
    PEOPLE: [
        "Enter any property to change (case-sensitive). Below are some of the available properties:",
        "description",
        "economy",
        "economy_description",
        "government",
        "government_description",
        "inhabitant",
        "inhabitants",
        "name",
        "population",
        "population_description",
        "productivity",
        "techlevel"
    ],
    PLANET: [
        "Enter any property to change (case-sensitive). Below are SOME of the planet-related properties:",
        "illumination_color",
        "land_color",
        "land_fraction",
        "planet_distance",
        "planet_distance_multiplier",
        "polar_land_color",
        "polar_sea_color",
        "radius",
        "rotational_velocity",
        "rotation_speed",
        "rotation_speed_factor",
        "sea_color",
        "terminator_threshold_vector",
        "texture",
        "texture_hsb_color",
        "texture_normspec"
    ],
    ATMOSPHERE: [
        "Enter any property to change (case-sensitive). Below are SOME of the atmosphere-related properties:",
        "air_color",
        "air_color_mix_ratio",
        "air_density",
        "atmosphere_rotational_velocity",
        "cloud_alpha",
        "cloud_color",
        "cloud_fraction",
        "has_atmosphere",
        "polar_cloud_color"
    ],
    EXTRAS: [
        "Enter any property to change (case-sensitive). Below are some extra planet-related properties:",
        "planet_distance_multiplier",
        "planet_name",
        "rotational_velocity",
        "rotation_speed_factor",
        "texture",
        "texture_hsb_color",
        "texture_normspec"
    ],
    SKY: [
        "Enter any property to change (case-sensitive). Below are all the sky-related properties:",
        "ambient_level",
        "nebula_color_1",
        "nebula_color_2",
        "nebula_count_multiplier",
        "sky_blur_alpha",
        "sky_blur_cluster_chance",
        "sky_blur_scale",
        "sky_color_1",
        "sky_color_2",
        "sky_n_blurs",
        "sky_n_stars",
        "sky_rgb_colors",
        "star_count_multiplier"
    ],
    STATION: [
        "Enter any property to change (case-sensitive). Below are all the station-related properties:",
        "market_script",
        "station",
        "station_roll",
        "station_vector",
        "stations_require_docking_clearance"
    ],
    SUN: [
        "Enter any property to change (case-sensitive). Below are all the sun-related properties:",
        "corona_flare",
        "corona_hues",
        "corona_shimmer",
        "sun_color",
        "sun_distance",
        "sun_distance_modifier",
        "sun_distance_multiplier",
        "sun_gone_nova",
        "sun_name",
        "sun_radius",
        "sun_vector"
    ],
    SYSTEM: [
        "Enter any property to change (case-sensitive). Below are some system-related properties:",
        "concealment",
        "populator",
        "random_seed",
        "repopulator"
    ],
    READONLY: [
        "View read-only properties by selecting an option below:",
        "coordinates",
        "galaxyID",
        "systemID",
        "visits",
        "sun_gone_nova"
    ]
};

/* ========================================================
		SETTING THE INTERFACE ON F4 SCREEN
=========================================================== */

this.startUp = function () {
    if (worldScripts.world_builder_menu) {
        this._menuItems = worldScripts.world_builder_menu._menuItems;
    }
    this._applyInterface();
    delete this.startUp;
};

this.infoSystemChanged = this.shipWillExitWitchspace = function () {
    this._applyInterface();
};

this._applyInterface = function () {
    if (system.mainStation) {
        system.mainStation.setInterface("world_builder", {
            title: "World Builder",
            category: expandDescription("[interfaces-category-uncategorised]"),
            summary: "Improve a world, any world. Currently improving " + System.systemNameForID(player.ship.infoSystem) + ".",
            callback: this._changeWorld.bind(this)
        });
    }
};

/* ========================================================
		FIRST USER-INPUT SCREEN
=========================================================== */

this._changeWorld = function (menuKey) {
    var menuLines = this._menuItems[menuKey];
    if (!menuLines) {
        log(this.name, "Error: Menu " + menuKey + " not found.");
        return;
    }
    this._currentMenuKey = menuKey;
    this._currentBackground = {name: "wb_bg_" + menuKey + ".png", height: 496};
    var message = menuLines[0] + "\n\n";
    for (let i = 1; i < menuLines.length; i++) {
        message += (i + ". " + menuLines[i] + "\n");
    }
    var sysID = player.ship.infoSystem;
    var parameters = {
        title: "Rebuilding World " + sysID + ", " + System.systemNameForID(sysID),
        message: message,
        screenID: "world_builder",
        background: this._currentBackground,
        allowInterrupt: false, // Conflicts with text-entry.
        textEntry: true
    };
    if (menuKey === "world_builder") {
        parameters.music = "dt_manipulating_property_values.ogg";
    }
    mission.runScreen(parameters, this._changeWorld2.bind(this));
};

/* ========================================================
		PROCESSING THE USER-INPUT
=========================================================== */

this._changeWorld2 = function (userInput) {
    var parameters = {
        choices: {"1_AGAIN": "Choose another property", "9_EXIT": "EXIT World Builder"},
        screenID: "world_builder",
        exitScreen: "GUI_SCREEN_SYSTEM_DATA",
        allowInterrupt: true
    };

    if (userInput && userInput !== "") {
        // Check if the input is a positive integer
        var numericInput = parseInt(userInput, 10);
        if (!isNaN(numericInput) && numericInput > 0) {
            // Map the numeric input to the corresponding property name
            const menuItemIndex = numericInput;
            const selectedMenu = this._menuItems[this._currentMenuKey]; // Use the active menu key

            if (menuItemIndex >= 1 && menuItemIndex < selectedMenu.length) {
                userInput = selectedMenu[menuItemIndex];
            } else {
                parameters.title = "World Builder";
                parameters.message = "Invalid numeric input. Please enter a valid property name or number.";
                parameters.background = "wb_bg_ERROR.png";
                mission.runScreen(parameters, this._handleExitChoice.bind(this));
                return;
            }
        }
    } else {
        log(this.name, "FOUND ME!")
        this._propertyToChange = "ERROR";
        this._changeWorld3(""); // No input, go straight to screen 3
        return;
    }

    if (this._menuItems.hasOwnProperty(userInput)) { // Check for KEYWORD to change the _currentMenuKey
        this._currentMenuKey = userInput;           // Update the current menu key
        this._changeWorld(userInput);              // Restart the process with the new menu
        return;                                   // Exit early to avoid proceeding with other logic
    }

    const sysID = player.ship.infoSystem;
    const sys = System.infoForSystem(galaxyNumber, sysID);
    const messageStart = "Current value of " + userInput + ": " + sys[userInput] + ".\n";
    parameters.title = "Rebuilding World " + sysID + ", " + sys.name;

    if (this._menuItems.READONLY.indexOf(userInput) !== -1) {
        parameters.message = messageStart + "This property is read-only. You cannot modify it.";
        parameters.background = {name: "wb_bg_READONLY.png", height: 496};
        mission.runScreen(parameters, this._handleExitChoice.bind(this));
        return;
    } else {
        this._propertyToChange = userInput;
        parameters.message = messageStart + this._messageTexts();
        parameters.background = this._currentBackground;
        parameters.allowInterrupt = false; // Conflicts with text-entry.
        parameters.textEntry = true;
        mission.runScreen(parameters, this._changeWorld3.bind(this));
        return;
    }
};

/* ========================================================
		MAKING A CHANGE AFTER SECOND USER-INPUT
=========================================================== */

this._changeWorld3 = function _changeWorld3 (newValue) {
    const layerDescription = ["Default (undefined by core Oolite)", "Static (planetinfo.plist)", "Dynamic (javascript)", "Priority (use judiciously)"];
    var parameters = {
        title: "World Builder",
        message: "LAYER: " +  layerDescription[this._currentLayer] + "\nOWNER: " + this._currentOwner + "\n\nNo change recorded.",
        choices: {"1_AGAIN": "Edit another property", "9_EXIT": "EXIT World Builder"},
        screenID: "world_builder",
        background: this._currentBackground,
        exitScreen: "GUI_SCREEN_SYSTEM_DATA",
        allowInterrupt: true
    };

    if (newValue && newValue !== "") {
        const sysID = player.ship.infoSystem;
        const sys = System.infoForSystem(galaxyNumber, sysID);
        const oldValue = sys[this._propertyToChange];

        if (newValue === "null" || newValue === "undefined") {
            log(this.name, '_changeWorld3 received newValue: "' + newValue + '"');
            newValue = null;
            log(this.name, "_changeWorld3 altered newValue to: null");
         // The following line looks wrong, but is correct:
            worldScripts.sysInfoChangeLog._pendingChange(galaxyNumber, sysID, this._propertyToChange, oldValue, undefined, this._currentLayer, this._currentOwner);
        } else {
         // To enable a log to be maintained, before changing system information, call:
            worldScripts.sysInfoChangeLog._pendingChange(galaxyNumber, sysID, this._propertyToChange, oldValue, newValue, this._currentLayer, this._currentOwner);
        }
        sys.setProperty(this._currentLayer, this._propertyToChange, newValue, this._currentOwner);

        parameters.title = "Rebuilding World " + sysID + ", " + sys.name;
     // parameters.message = "Changed " + this._propertyToChange + " from " + oldValue + " to " + newValue + ". Exit to view result.";
        parameters.message = "LAYER: " +  layerDescription[this._currentLayer] + "\nOWNER: " + this._currentOwner + "\n\nChanged " + this._propertyToChange + " from " + oldValue + " to " + newValue + ". Exit to view result.";
    }
    mission.runScreen(parameters, this._handleExitChoice.bind(this));
};

/* ========================================================
		HANDLER FROM RESULT SCREEN
=========================================================== */

this._handleExitChoice = function (choice) {
    if (choice === "1_AGAIN") {
        // Return to the first input screen
        this._changeWorld(this._currentMenuKey);
    }
};

/* ========================================================
		CHANGING OVER-RIDE OWNER
=========================================================== */

this._changeOwner = function (menuKey) {
    var menuLines = this._menuItems[menuKey];
    if (!menuLines) {
        log(this.name, "Error: Menu " + menuKey + " not found.");
        return;
    }
    this._currentMenuKey = menuKey;
    this._currentBackground = {name: "wb_bg_" + menuKey + ".png", height: 496};
    var message = menuLines[0] + "\n\n";



    // Store the change in a mission variable for later reference
    if (!missionVariables.World_Builder_owners) {
        missionVariables.World_Builder_owners = [this.oolite_manifest_identifier]; // Initialize array if not already set
    }
    var ownerLog = JSON.parse(missionVariables.World_Builder_owners || "[]");

    for (let i = 1; i < ownerLog.length; i++) {
        message += (i + ". " + ownerLog[i] + "\n");
    }



    var parameters = {
        title: "Resetting Owner " + this._currentOwner,
        message: message,
        screenID: "world_builder",
        background: this._currentBackground,
        allowInterrupt: false, // Conflicts with text-entry.
        textEntry: true
    };
    mission.runScreen(parameters, this._changeOwner_2.bind(this));
};
/* 

    // Store the change in a mission variable for later reference
    if (!missionVariables.World_Builder_owners) {
        missionVariables.World_Builder_owners = [this.oolite_manifest_identifier]; // Initialize array if not already set
    }
    var ownerLog = JSON.parse(missionVariables.World_Builder_owners || "[]");
    ownerLog.push({
        galaxyID: galaxy,
        systemID: system,
        property: property,
        oldValue: oldValue,
        newValue: newValue,
        layer: layer,
        owner: owner,
        timestamp: clock.seconds // Log the time of the change
    });
    if (ownerLog.length > 10) { // Keep only the last 10 changes
        ownerLog.shift(); // Remove the oldest entry
    }
    missionVariables.World_Builder_owners = JSON.stringify(ownerLog); // Save back to mission variables
 */
/* ========================================================
		CHANGING OVER-RIDE LAYER
=========================================================== */

this._changeLayer = function (input) {
    if (input >= 0 && input <= 3) {
        this._currentLayer = input;
    } else if (input === "LAYER") {
        this._currentMenuKey = input;
        this._currentBackground = {name: "wb_bg_LAYER.png", height: 496};
    } else if (this._menuItems.hasOwnProperty(input)) { // Check for KEYWORD to change the _currentMenuKey
        this._currentMenuKey = input;                  // Update the current menu key
        this._changeWorld(input);                     // Restart the process with the new menu
        return;                                      // Exit early to avoid proceeding with other logic
    } else {
        this._changeWorld2(input); // Restart the process with the new input
        return;
    }

    var menuLines = this._menuItems[this._currentMenuKey];
    if (!menuLines) {
        log(this.name, "Error: Menu " + this._currentMenuKey + " not found.");
        return;
    }
    let count = menuLines.length - 1;
    var message = menuLines[count] + "\n\n";
    for (let i = 0; i < count; i++) {
        message += (i + ". " + menuLines[i] + "\n");
    }

    var parameters = {
        title: "Resetting Layer " + this._currentLayer,
        message: message,
        screenID: "world_builder",
        background: this._currentBackground,
        allowInterrupt: false, // Conflicts with text-entry.
        textEntry: true
    };
    if (input === "LAYER") {
        parameters.music = "dt_manipulating_property_values.ogg";
    }
    mission.runScreen(parameters, this._changeLayer.bind(this));
};

/* ========================================================
		THE END
=========================================================== */