# problem2solution.py
#
# ICS H32 Fall 2025
# Exercise Set 5
# INSTRUCTOR SOLUTION

import urllib.request



def _download_file(url: str) -> str:
    request = urllib.request.Request(url)
    response = urllib.request.urlopen(request)

    try:
        return response.read().decode(encoding = 'utf-8')
    finally:
        response.close()



class InvalidCommandError(Exception):
    pass



class InvalidDataError(Exception):
    pass



def _must_have_line(data_lines: list[str], line_number: int) -> None:
    if line_number >= len(data_lines):
        raise InvalidDataError



class Location:
    def __init__(self, name: str, data: str):
        self._name = name
        
        data_lines = data.split('\n')

        _must_have_line(data_lines, 0)

        if data_lines[0].startswith('TITLE '):
            self._title = data_lines[0][len('TITLE '):]
        else:
            raise InvalidDataError

        _must_have_line(data_lines, 1)

        if data_lines[1] != 'DESCRIPTION':
            raise InvalidDataError

        line_number = 2
        self._description = ''

        while True:
            _must_have_line(data_lines, line_number)

            if data_lines[line_number] == 'END DESCRIPTION':
                line_number += 1
                break
            else:
                self._description += data_lines[line_number] + '\n'
                line_number += 1

        _must_have_line(data_lines, line_number)

        if data_lines[line_number] != 'COMMANDS':
            raise InvalidDataError

        line_number += 1

        self._commands = {}

        while True:
            _must_have_line(data_lines, line_number)

            if data_lines[line_number] == 'END COMMANDS':
                line_number += 1
                break
            else:
                command_parts = data_lines[line_number].split(':')

                if len(command_parts) != 2:
                    raise InvalidDataError

                destination = command_parts[1]

                for command in command_parts[0].split(','):
                    self._commands[command] = destination

                line_number += 1

        self._is_game_over = line_number < len(data_lines) and data_lines[line_number] == 'GAME OVER'



    def name(self) -> str:
        return self._name


    def title(self) -> str:
        return self._title


    def description(self) -> str:
        return self._description


    def is_game_over(self) -> bool:
        return self._is_game_over


    def get_command_destination(self, command: str) -> str:
        if command.upper() in self._commands:
            return self._commands[command.upper()]
        else:
            raise InvalidCommandError



def _read_game_url() -> str:
    print("Specify the base URL for the game you'd like to play.")
    print()
    return input('Game URL: ')



def _load_location(name: str, base_url: str) -> Location:
    return Location(name, _download_file(f'{base_url}{name}.dat'))



def run() -> None:
    base_url = _read_game_url()
    location_name = 'start'

    while True:
        try:
            location = _load_location(location_name, base_url)
        except InvalidDataError:
            print()
            print('Internal Game Error')
            print(f'The location {location_name} is represented by invalid data.')
            break

        print()
        print(location.title())
        print(location.description())

        if location.is_game_over():
            print()
            print('GAME OVER')
            break

        command = input('What would you like to do? ')

        try:
            location_name = location.get_command_destination(command)
        except InvalidCommandError:
            print('That is an invalid command.')
    


if __name__ == '__main__':
    run()
