"""Implements Mach5 menues."""

import os.path
import errno
import yaml

from collections import OrderedDict
from getkey import getkey, keys
import subprocess


def get_data_from(menu_file):
    """Get menu data from a yaml menu file."""
    menu_file = os.path.expanduser(menu_file)
    if not os.path.exists(menu_file):
        raise FileNotFoundError(errno.ENOENT,
                                os.strerror(errno.ENOENT), menu_file)
    with open(menu_file, 'r') as yaml_file:
        menu_data = yaml.safe_load(yaml_file)

    if 'entries' not in menu_data:
        raise ValueError(f"Malformed file {menu_file}.\
        First entry is not a menu")
    return(menu_data)


class Command:
    """A Mach5 command."""

    def __init__(self, cmd_data):
        """Construct a Mach5 command object."""
        if len(cmd_data['sc']) != 1:
            raise ValueError(f"Shortcut must be only one character.\
            {cmd_data['heu']} is invalid.")
        self._name = cmd_data['name']
        self._cmd = cmd_data['cmd']
        self._sc = cmd_data['sc']

    def show(self):
        """Return string for Command."""
        return f"{self._sc} - {self._name}"

    def execute(self):
        """Execute command."""
        subprocess.Popen(os.path.expanduser(self._cmd))


class Menu:
    """A Mach5 menu."""

    def __init__(self, menu_data):
        """Construct a menu object from a menu data dict."""
        self._name = menu_data['name']
        self._entries = OrderedDict()
        self._sc = menu_data['sc']
        for e in menu_data['entries']:
            if e['sc'] in self._entries:
                raise ValueError(f"Repeated shortcut {e['sc']}")
            if 'entries' in e:
                self._entries[e['sc']] = Menu(e)
            else:
                self._entries[e['sc']] = Command(e)

    def show(self, recursive=False):
        """Show Menu."""
        my_str = ""
        if self._sc:
            my_str = f"{self._sc} - "
        my_str += f"{self._name} (m)"
        if recursive:
            my_str += "\n"
            for i, v in self._entries.items():
                my_str += f"{v.show()}\n"
        return my_str

    def get_command(self):
        """Get command from menu."""
        print(self.show(True))
        while True:
            opt = getkey()
            if opt in self._entries:
                if isinstance(self._entries[opt], Menu):
                    return self._entries[opt].get_command()
                else:
                    return self._entries[opt]
            elif opt == keys.ESC:
                exit(0)