#!/usr/bin/env python

from lib.database import get_database
from lib.defs import Console
from lib.menu import retry_prompt, select_item_index
from lib.inlretro import dump_game
from lib.inesheader import write_with_header
from lib.util import input_or_exit
from os import close, path, remove
from shutil import copyfile
from tempfile import mkstemp

CONSOLE_OPTIONS = {
    Console.FAMICOM: 'NES/Famicom',
    Console.GENESIS: 'Genesis/Mega Drive',
    Console.NES: 'NES/Famicom',
    Console.N64: 'Nintendo 64',
    Console.SNES: 'SNES/Super Famicom',
}

CONSOLE_EXTENSIONS = {
    Console.FAMICOM: 'nes',
    Console.GENESIS: 'md',
    Console.NES: 'nes',
    Console.N64: 'z64',
    Console.SNES: 'sfc',
}

def main():
    print("The INL Retro Cartridge Backup Helper")

    done = False

    while not done:
        game = None
        console = pick_console_or_exit()
    
        if console:
            database = get_database(console)
            while not game:
                game = pick_game(database)
            backup_game(game)
        else:
            done = True

    print("Exiting...")

def pick_console_or_exit():
    consoles = [Console.GENESIS, Console.NES, Console.N64, Console.SNES]
    options = map(lambda c: CONSOLE_OPTIONS[c], consoles)

    print('\nSelect a console')
    index = select_item_index(options, 'Exit')

    return consoles[index] if index != None else None

def pick_game(database):
    def version_to_listing(version):
        return "%s - %s" % (version.region, version.console.value)

    game = None
    
    while game == None:
        name_index = None
        versions = []
        version_index = None

        # Search for games by name
        search = input_or_exit("\nSearch for game: ")

        # Search for results and have the user pick from them
        if len(search):
            name_suggestions = database.search(search)
            name_index = select_item_index(name_suggestions, 'Redo search')

        # If the user picked something, gather all versions of games by that name
        if name_index != None:
            name = name_suggestions[name_index]
            versions = sorted(
                database.get_games_by_name(name),
                key=lambda game: game.region
            )

        # If there is more than one version for that name, have the user pick one
        if len(versions) == 1:
            game = versions[0]
        elif len(versions) > 1:
            print("\nWhich region/console for %s?" % name)
            version_suggestions = map(version_to_listing, versions)
            version_index = select_item_index(version_suggestions, 'Redo game search')
                
        if version_index != None:
            game = versions[version_index]

    return game

def backup_game(game):
    print("\nCreating backup for %s" % game.name)

    # This is a little bit awkward, because we need the INLretro subprocess to write to
    # the tempfile first if this is NES/Famicom. Also: not sure if this works in Windows,
    # but probably neither does anything else in here.
    bin_fd, bin_filename = mkstemp()
    close(bin_fd)

    try:
        retry = False
        if dump_game(game, bin_filename):
            to_filename = "roms/%s (%s).%s" % (
                game.name,
                game.region,
                CONSOLE_EXTENSIONS[game.console]
            )

            # NES/Famicom dumps need to write the final file with the NES2.0 header
            if game.console == Console.NES or game.console == Console.FAMICOM:
                write_with_header(game, bin_filename, to_filename)
            else:
                copyfile(bin_filename, to_filename)

            print("\nWrote backup to\n\t%s" % to_filename)
    
        else:
            print("\nFailed to read data from the cartridge.")
            retry = retry_prompt('Retry?', True)

    finally:
        # Temp file cleanup
        remove(bin_filename)

    if retry:
        backup_game(game)

if __name__ == "__main__":
    main()
