"""DuckieDai Springs for TI-84 Plus CE Python."""

from math import sqrt


def duckiedai_intro(program_name, wait=True):
    """Show the reusable DuckieDai program opening."""
    title = program_name[:16]
    empty = 16 - len(title)
    left = empty // 2
    right = empty - left

    print("+----------------------+")
    print("|   " + " " * left + title + " " * right + "   |")
    print("|                      |")
    print("|       __             |")
    print("|   ___(o )>  quack!   |")
    print("|   \\ <_. )           |")
    print("|    `---'             |")
    print("|     by DuckieDai     |")
    print("+----------------------+")
    print("Loading...")

    if wait:
        input("Press enter to start ")
        print("\n" * 6)


def number(prompt):
    """Allow positive, negative, or zero values."""
    while True:
        try:
            value = float(input(prompt))

            if value > -1e100 and value < 1e100:
                return value

        except ValueError:
            pass

        print("Enter a valid number.")


def nonzero_number(prompt):
    """Require a number other than zero."""
    while True:
        value = number(prompt)

        if value != 0:
            return value

        print("Value cannot be zero.")


def positive_number(prompt):
    """Require a value greater than zero."""
    while True:
        try:
            value = float(input(prompt))

            if value > 0 and value < 1e100:
                return value

        except ValueError:
            pass

        print("Enter a number above 0.")


def nonnegative_number(prompt):
    """Allow zero or positive values."""
    while True:
        try:
            value = float(input(prompt))

            if value >= 0 and value < 1e100:
                return value

        except ValueError:
            pass

        print("Enter 0 or greater.")


def show_answer(name, value, unit):
    input("Press enter for answer ")
    print("\n" * 6)
    print("ANSWER")
    print(name + " = " + str(value))
    print(unit)


def main():
    duckiedai_intro("SPRING ENERGY")

    print("HOOKE'S LAW")
    print("& ELASTIC ENERGY")
    print()
    print("Fs = -k*x")
    print("PE = 0.5*k*x^2")
    input("Press enter for menu ")
    print("\n" * 6)
    print()
    print("What do you need?")
    print()
    print("1. Spring force")
    print("2. Spring constant")
    print("   from force")
    print("3. Displacement")
    print("   from force")
    input("Press enter for more ")
    print("\n" * 6)
    print("4. Elastic PE")
    print("5. Spring constant")
    print("   from PE")
    print("6. Displacement")
    print("   from PE")
    print()

    choice = input("Choose 1-6: ")

    print()

    # ==========================================
    # 1. SPRING FORCE
    #
    # Fs = -k*x
    # ==========================================

    if choice == "1":

        k = positive_number("k (N/m): ")
        x = number("Displacement (m): ")

        force = -k * x

        print()
        print("Using:")
        print("Fs = -k*x")
        print()
        print("Fs = -" + str(k))
        print("x " + str(x))

        show_answer(
            "Fs",
            force,
            "newtons"
        )

        print()
        print("Minus sign means")
        print("restoring force is")
        print("opposite displacement.")


    # ==========================================
    # 2. SPRING CONSTANT FROM FORCE
    #
    # k = -Fs/x
    # ==========================================

    elif choice == "2":

        force = number("Spring force (N): ")
        x = nonzero_number("Displacement (m): ")

        k = -force / x

        print()
        print("Using:")
        print("Fs = -k*x")
        print()
        print("Rearranged:")
        print("k = -Fs/x")

        if k <= 0:

            print()
            print("Result gives k <= 0.")
            print("Check force and")
            print("direction signs.")

        else:

            show_answer(
                "k",
                k,
                "N/m"
            )


    # ==========================================
    # 3. DISPLACEMENT FROM FORCE
    #
    # x = -Fs/k
    # ==========================================

    elif choice == "3":

        force = number("Spring force (N): ")
        k = positive_number("k (N/m): ")

        x = -force / k

        print()
        print("Using:")
        print("Fs = -k*x")
        print()
        print("Rearranged:")
        print("x = -Fs/k")

        show_answer(
            "x",
            x,
            "meters"
        )


    # ==========================================
    # 4. ELASTIC POTENTIAL ENERGY
    #
    # PE = 0.5*k*x^2
    # ==========================================

    elif choice == "4":

        k = positive_number("k (N/m): ")
        x = number("Displacement (m): ")

        pe = (
            0.5 *
            k *
            x ** 2
        )

        print()
        print("Using:")
        print("PE = 0.5*k*x^2")
        print()
        print("PE = 0.5 x")
        print(str(k) + " x")
        print(str(x) + "^2")

        show_answer(
            "PE",
            pe,
            "joules"
        )


    # ==========================================
    # 5. SPRING CONSTANT FROM ENERGY
    #
    # k = 2*PE/x^2
    # ==========================================

    elif choice == "5":

        pe = nonnegative_number("Elastic PE (J): ")
        x = nonzero_number("Displacement (m): ")

        k = (
            2 * pe /
            (x ** 2)
        )

        print()
        print("Using:")
        print("PE = 0.5*k*x^2")
        print()
        print("Rearranged:")
        print("k = 2*PE/x^2")

        show_answer(
            "k",
            k,
            "N/m"
        )


    # ==========================================
    # 6. DISPLACEMENT FROM ENERGY
    #
    # x = +/- sqrt(2*PE/k)
    # ==========================================

    elif choice == "6":

        pe = nonnegative_number("Elastic PE (J): ")
        k = positive_number("k (N/m): ")

        x = sqrt(
            (2 * pe) / k
        )

        print()
        print("Using:")
        print("PE = 0.5*k*x^2")
        print()
        print("Rearranged:")
        print("x = +/-sqrt(2*PE/k)")
        print()
        input("Press enter for answer ")
        print("\n" * 6)
        print("ANSWER")
        print("|x| = " + str(x))
        print("meters")
        print()
        print("Possible positions:")
        print("x = " + str(x))
        print("or")
        print("x = -" + str(x))

    else:
        print("Invalid choice.")

    print()
    print("DuckieDai says: done!")


# TI-Python imports the selected AppVar rather than
# setting __name__ to main.
main()
