from __future__ import unicode_literals
import sys
from collections  import OrderedDict, namedtuple
try:
    from configparser import ConfigParser  # Python 3
except ImportError:
    from ConfigParser import ConfigParser  # Python 2

try:
    from builtins import input as raw_input  # Python 3
except ImportError:
    from __builtin__ import raw_input        # Python 2

Action = namedtuple("Action", "name do")


class Menu:
    def __init__(self, title, actions, parent=None):
        self.title = title
        self.actions = actions
        self.parent = parent

    @classmethod
    def from_config(cls, game, config, title, parent=None):
        if title not in game.menus:  # create menu
            actions = OrderedDict()
            self = game.menus[title] = cls(title, actions, parent)
            for opt, value in config.items(title):  # Python 3.2+:
                                                    # config[title].items()
                if value in config.sections():  # submenu
                    do = cls.from_config(game, config, value, self)
                else:  # concrete choice
                    def make_do(action, menu):
                        return lambda: getattr(game, 'do_' + action)(menu)
                    do = make_do(value, self)
                actions[opt] = Action(value, do)
        return game.menus[title]

    def __call__(self):
        # show menu
        print(self.title + ":")
        for opt, action in self.actions.items():
            print("\t{}: {}".format(opt, action.name))

        # take user input
        prompt = 'Choose [{}]: '.format(', '.join(self.actions))
        action_name = read_choice(choices=self.actions, prompt=prompt)
        if not sys.stdin.isatty():
            print(action_name)  # echo the choice in non-interactive mode

        # act on it
        return self.actions[action_name].do


class Game:
    def __init__(self):
        self.menus = {}
        self.options = {}

    def do_start(self, menu):
        print("start game with options: {}".format(self.options))
        # ... play game
        return menu  # return to menu

    def do_exit(self, menu):
        print("bye")
        return None  # do nothing (the end)

    def __getattr__(self, name):  # called for non-existing game attributes
        if not name.startswith('do_'):
            raise AttributeError(name)

        # game.do_something(menu) sets corresponding option to 'something'
        def set_option(menu):
            self.options[menu.title] = name[len('do_'):]
            return menu.parent  # return to parent menu
        return set_option


def read_choice(choices, prompt):
    c = None
    while c not in choices:
        c = raw_input(prompt)
    return c


def main():
    # read menu provided in ini-format
    config = ConfigParser()
    config_lines = []
    for line in iter(sys.stdin.readline, ''):  # consume config in
                                               # ini-format
                                               # line-by-line to allow
                                               # accepting user input
                                               # later from stdin
                                               # (avoid read-ahead)
        if line.rstrip() == '---':
            break  # end of config (the rest is user input)
        config_lines.append(line)

    # Python 3.3:
    # config.read_string(''.join(config_lines))
    # Python < 3.3:
    from io import StringIO
    config.readfp(StringIO(''.join(config_lines)))

    # create game
    game = Game()
    menu = Menu.from_config(game, config, 'Main menu')

    # run it
    while menu is not None:  # use trampoline to avoid recursion limit
        menu = menu()

main()