#!/usr/bin/python3
import time

from map import rooms
from player import *
from items import *
from gameparser import *
from people import *

       

def print_inventory_items(items):
    """This function takes a list of inventory items and displays it nicely, in a
    manner similar to print_room_items(). The only difference is in formatting:
    print "You have ..." instead of "There is ... here.".
    """

    inv_str = ''
    
    for i in items :
        inv_str += i["name"] + ', '

    if inv_str != '' :
        if inv_str[-2] == "," :
            inv_str = inv_str[:-2]

    if inv_str != "" :
        inv_str = "You have " + inv_str + "."
        
        print(inv_str + "\n")
            

def print_room(room):
    """This function takes a room as an input and nicely displays its name
    and description. The room argument is a dictionary with entries "name",
    "description" etc. (see map.py for the definition). The name of the room
    is printed in all capitals and framed by blank lines. Then follows the
    description of the room and a blank line again. If there are any items
    in the room, the list of items is printed next followed by a blank line
    (use print_room_items() for this).
    """
    # Display room name
    print("_" * (len(room["name"]) + 4) + "\n")
    print("~ " + room["name"].upper() + " ~")
    print("_" * (len(room["name"]) + 4))
    
    # Display room description
    print("\n" + room["description"])
    print()
    

def exit_leads_to(exits, direction):
    """This function takes a dictionary of exits and a direction (a particular
    exit taken from this dictionary). It returns the name of the room into which
    this exit leads.
    """
    return rooms[exits[direction]]["name"]



def is_valid_exit(exits, chosen_exit):
    """This function checks, given a dictionary "exits" (see map.py) and
    a players's choice "chosen_exit" whether the player has chosen a valid exit.
    It returns True if the exit is valid, and False otherwise. Assume that
    the name of the exit has been normalised by the function normalise_input().
    """
    return chosen_exit in exits

def is_valid_person(people, chosen_person):
    """This function checks the chosen person is in the room"""

    return chosen_person in people


def execute_go(direction):
    """This function, given the direction (e.g. "south") updates the current room
    to reflect the movement of the player if the direction is a valid exit
    (and prints the name of the room into which the player is
    moving). Otherwise, it prints "You cannot go there."
    """

    global current_room
    
    if is_valid_exit(current_room["exits"], direction) :
        current_room = move(current_room["exits"], direction)

    else :
        print("You cannot go there.")      


def execute_take(item_id):
    """This function takes an item_id as an argument and moves this item from the
    list of items in the current room to the player's inventory. However, if
    there is no such item in the room, this function prints
    "You cannot take that."
    """

    found_item = False
    
    for i in current_room["items"] :
        if i["id"] == item_id :

            # Check mass
            mass = 0
            
            for x in inventory :
                mass += x["mass"]

            mass += i["mass"]

            if mass >= 2100 :
                print("You are carrying too many heavy things.")

            else :
                inventory.append(i)
                current_room["items"].remove(i)

                found_item = True
                break
        
    if found_item == False :
        print("You cannot take that.")  
    

def execute_drop(item_id):
    """This function takes an item_id as an argument and moves this item from the
    player's inventory to list of items in the current room. However, if there is
    no such item in the inventory, this function prints "You cannot drop that."
    """

    found_item = False
    
    for i in inventory :
        if i["id"] == item_id :
            current_room["items"].append(i)
            inventory.remove(i)

            found_item = True
            break
        
    if found_item == False :
        print("You cannot drop that.")    


def execute_talk(people_id):
    """This function takes a people_id as an argument and begins a conversation
    with the person."""

    if is_valid_person(current_room["people"], people_id) :
        person_conv = current_room["people"][people_id]["conversation"]

        print(person_conv["opening"])
        input("Press ENTER to continue...")
        
        print("\nYou can ask...")
        qcount = 0

        if not person_conv["questions"] == [] :
            
            for q in range(0, len(person_conv["questions"])) :
                print("Input %d to ask '%s'" % (q+1, person_conv["questions"][q]))
                qcount += 1

            while True :
                try :
                    qask = int(input("\n> "))

                    if qask <= qcount and qask > 0 :
                        print(person_conv["responses"][qask-1])
                        input("Press ENTER to continue...")
                        break

                    else :
                        print("You cannot ask that.")

                except :
                    print("Type a number from the list of questions.")
        
    else :
        print("This person isn't here.")

def execute_command(command):
    """This function takes a command (a list of words as returned by
    normalise_input) and, depending on the type of action (the first word of
    the command: "go", "take", or "drop"), executes either execute_go,
    execute_take, or execute_drop, supplying the second word as the argument.

    """

    if 0 == len(command):
        return

    if command[0] == "go":
        if len(command) > 1:
            execute_go(command[1])
        else:
            print("Go where?")

    elif command[0] == "take":
        if len(command) > 1:
            execute_take(command[1])
        else:
            print("Take what?")

    elif command[0] == "drop":
        if len(command) > 1:
            execute_drop(command[1])
        else:
            print("Drop what?")

    elif command[0] == "talk":
        if len(command) > 1:
            execute_talk(command[1])
        else:
            print("Talk to whom?")
            
    else:
        print("This makes no sense.")


def menu(exits, room_items, inv_items):
    """This function, given a dictionary of possible exits from a room, and a list
    of items found in the room and carried by the player, prints the menu of
    actions using print_menu() function. It then prompts the player to type an
    action. The players's input is normalised using the normalise_input()
    function before being returned.
    """

    print("What do you want to do?")

    # Read player's input
    user_input = input("> ")

    # Normalise the input
    normalised_user_input = normalise_input(user_input)

    return normalised_user_input


def move(exits, direction):
    """This function returns the room into which the player will move if, from a
    dictionary "exits" of avaiable exits, they choose to move towards the exit
    with the name given by "direction".
    """

    # Next room to go to
    return rooms[exits[direction]]


# This is the entry point of our program
def main():

    print("Welcome!")
    time.sleep(0.5)
    
    # Main game loop
    while True:
        # Display game status (room description, inventory etc.)
        print_room(current_room)
        print_inventory_items(inventory)

        # Show the menu with possible actions and ask the player
        command = menu(current_room["exits"], current_room["items"], inventory)

        # Execute the player's command
        execute_command(command)
        

# Are we being run as a script? If so, run main().
# '__main__' is the name of the scope in which top-level code executes.
# See https://docs.python.org/3.4/library/__main__.html for explanation
if __name__ == "__main__":
    main()

