#!/usr/bin/env python
"""
Defines the utility that walks the user through plotting a cross section.

Copyright 2017 Southern California Earthquake Center

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# Python Imports
import sys

# Package Imports
import xmltodict

# UCVM Imports
from ucvm.src.framework.ucvm import UCVM
from ucvm.src.shared.functions import ask_and_validate, is_number, is_acceptable_value, \
    is_valid_proj4_string
from ucvm.src.shared.properties import UCVM_DEPTH, UCVM_ELEVATION, UCVM_DEFAULT_PROJECTION
from ucvm.src.visualization.cross_section import CrossSection


def usage() -> None:
    """
    Displays the help text associated with this utility.

    Returns:
        Nothing
    """
    UCVM.print_with_replacements(
        "\n"
        "ucvm_plot_cross_section - UCVM Version [version]\n"
        "\n"
        "Plots a cross-section given a series of questions.\n"
        "\n"
        "-f, --file f:          The configuration file from which to read."
    )


def ask_questions(test: bool) -> dict:
    """
    Asks the necessary questions to generate the cross-section plot.

    Returns:
        The filled-in question dictionary if successful and None if not.
    """
    answers = {
        "start_point": {
            "x": 0,
            "y": 0,
            "z": 0,
            "depth_elev": 0,
            "projection": ""
        },
        "end_point": {
            "x": 0,
            "y": 0,
            "z": 0,
            "depth_elev": 0,
            "projection": ""
        },
        "cross_section_properties": {
            "width_spacing": 0,
            "height_spacing": 0,
            "property": "",
            "end": 0
        },
        "plot": {
            "features": {
                "scale": "",
                "colormap": ""
            }
        },
        "cvm_list": "",
        "data": {
            "save": "n",
            "location": "",
            "name": ""
        }
    }

    # Get list of installed models.
    installed_models = {}
    counter = 1
    for model in UCVM.get_list_of_installed_models()["velocity"]:
        if model["id"] == "1d" or model["id"] == "dataproductreader":
            continue
        installed_models[counter] = {"name": model["name"], "id": model["id"]}
        counter += 1

    print("Generating a cross-section requires various parameters to be defined (such \n"
          "as the start point, ending point, and so on). The following questions will guide\n"
          "you through the definition of those parameters.")

    answers["start_point"]["x"] = \
        float(ask_and_validate("\nWhat is the X or longitudinal coordinate of the start point?",
                               is_number, "Answer must be a number."))
    answers["start_point"]["y"] = \
        float(ask_and_validate("What is the Y or latitudinal coordinate of the start point?",
                               is_number, "Answer must be a number."))

    answers["end_point"]["x"] = \
        float(ask_and_validate("\nWhat is the X or longitudinal coordinate of the end point?",
                               is_number, "Answer must be a number."))
    answers["end_point"]["y"] = \
        float(ask_and_validate("What is the Y or latitudinal coordinate of the end point?",
                               is_number, "Answer must be a number."))

    top_depth_or_elev = \
        float(ask_and_validate("\nWhat is the top depth or elevation for your cross-section?",
                               is_number, "Answer must be a number"))

    bottom_depth_or_elev = \
        float(ask_and_validate("What is the bottom depth or elevation for your cross-section?",
                               is_number, "Answer must be a number"))

    depth_elev = \
        ask_and_validate("\nAre your top and bottom numbers depth (by default) or elevation?\n"
                         "Type 'd' or enter for depth, 'e' for elevation:", is_acceptable_value,
                         "Type the character 'd' for depth or 'e' for elevation.",
                         allowed=["d", "e", ""])

    if str(depth_elev).lower().strip() == "e":
        depth_elev = UCVM_ELEVATION
    else:
        depth_elev = UCVM_DEPTH

    projection = \
        ask_and_validate("\nIn which projection are your points specified?\n"
                         "The default for UCVM is WGS84 latitude and longitude. To accept\n"
                         "the default projection, simply hit enter:", is_valid_proj4_string,
                         "The answer must be a valid Proj.4 projection.")

    if str(projection).strip() == "":
        projection = UCVM_DEFAULT_PROJECTION

    answers["start_point"]["z"] = top_depth_or_elev
    answers["end_point"]["z"] = bottom_depth_or_elev
    answers["start_point"]["depth_elev"] = depth_elev
    answers["end_point"]["depth_elev"] = depth_elev
    answers["start_point"]["projection"] = projection
    answers["end_point"]["projection"] = projection

    answers["cross_section_properties"]["width_spacing"] = \
        ask_and_validate("\nWhat horizontal spacing be, in meters, for each extracted point?",
                         is_number, "Answer must be a number")
    answers["cross_section_properties"]["height_spacing"] = \
        ask_and_validate("What vertical spacing be, in meters, for each extracted point?",
                         is_number, "Answer must be a number")

    answers["cross_section_properties"]["property"] = \
        ask_and_validate("\nWhich property or properties (comma-separated) should be plotted?\n"
                         "Acceptable answers include Vp, Vs, density, Qp, or Qs:")

    print("\nYou must select the velocity model(s) from which you would like to retrieve this\n"
          "data. You can either enter in your model(s) as text (e.g. cvms4.usgs-noaa) or you\n"
          "can select from one of the predefined ones in the list below.")

    if not test:
        for index, name in installed_models.items():
            print(str(index) + ") " + name["name"])

    answers["cvm_list"] = ask_and_validate("\nWhich velocity model would you like?")
    try:
        int(answers["cvm_list"])
        answers["cvm_list"] = installed_models[int(answers["cvm_list"])]["id"]
    except ValueError:
        pass

    answers["plot"]["features"]["scale"] = "discrete"
    answers["plot"]["features"]["colormap"] = "RdBu"

    answers["data"]["save"] = ask_and_validate(
        "\nWould you like the plot saved to disk? Type 'y' for yes, 'n' for no:",
        is_acceptable_value, "Enter y for yes, n for no.", allowed=["y", "n"]
    )

    if answers["data"]["save"].lower() == "y":
        answers["data"]["location"] = ask_and_validate(
            "Enter the folder location where this plot should be stored: "
        )
        answers["data"]["name"] = ask_and_validate(
            "Enter the file name (leave off the .png extension): "
        )

    save_config = ask_and_validate(
        "\nWould you like to save this configuration file for future use? Type 'y' for yes, 'n' for no:",
        is_acceptable_value, "Enter y for yes, n for no.", allowed=["y", "n"]
    )

    if save_config == "y":
        name = ask_and_validate(
            "Enter the file name to which this configuration should be saved (leave off the '.xml' ending): ",
        )

        if name.strip() == "":
            name = "plot_cross_section.xml"

        with open(name.replace(".xml", "") + ".xml", "w") as fd:
            fd.write(xmltodict.unparse({"root": answers}, pretty=True))

    return answers


def main() -> int:
    """
    The main UCVM cross-section generation function.

    Returns:
        0 if successful. Raises an error code otherwise, if not.
    """
    try:
        options = UCVM.parse_options([
            {"short": "f", "long": "file", "value": True, "required": False},
            {"short": "t", "long": "test", "value": False, "required": False}
        ], usage)
    except ValueError as v_err:
        print("[ERROR]: " + str(v_err) + "\n")
        sys.exit(-1)

    if options["file"] is not None:
        with open(options["file"], "r") as fd:
            section_info = xmltodict.parse(fd.read())["root"]
    else:
        section_info = ask_questions(options["test"] is not None)

    if options["test"] is None:
        CrossSection.from_dictionary(section_info).plot()
    else:
        cs = CrossSection.from_dictionary(section_info)
        cs.extract()
        for y_row in cs.extracted_data:
            for x in y_row:
                print(str(x))

    return 0

if __name__ == "__main__":
    sys.exit(main())
