# The Handler is the core control class for a single execution of the busy
# program. It's called when busy is run, and there are some functions to get
# things configured and started. Then one Handler is instantiated. This is the
# only place that imports the UI, Command, and Root classes. So the handler
# instance is passed around, and other classes can access what they need from
# there. Keeping the imports in one place allows the class families to be more
# modular.
#
# A Handler instance provides the following properties. For the most part, these
# properties are how commands access other class families. Remember that the
# Namespace from the Handler is the original Namespace, so use the one passed in
# to the execute() method of the Command for actual usage in an interactive UI.
# Also, the Handler doesn't hold a queue property, because it is only used by
# certain commands. Instead, get your queue from your root yourself!
#
# namespace - The argparse Namespace from the original parsing of the command
# line
#
# root - The Root object for retrieval and storage of items. This is the main
# way that a command gets its root.
#
# ui - The UI instance being implemented. This is the main way a command gets
# its UI.
#
# command - The original Command instance being implemented. Interactive UIs
# might instantiate other Commands.


from argparse import ArgumentParser
import sys
from pathlib import Path
from sys import argv

from busy.command.command import Command
from busy.ui.ui import UI
from busy.root.file_system_root import FileSystemRoot
from busy.util.python_version import confirm_python_version

PYTHON_VERSION = (3, 6, 5)

def main(*args):
    if not args:
        args = argv[1:]
    confirm_python_version(PYTHON_VERSION) 
    parser = get_parser()      
    namespace = parser.parse_args(args)
    try:
        handler = Handler(namespace)
        handler.execute()
    except (RuntimeError, ValueError) as error:
        print(f"Error: {str(error)}")

def get_parser():
    parser = ArgumentParser(prog='busy')
    parser.add_argument('--root', action='store', \
        help='file system path to busy data', \
        default=None)
    subparsers = parser.add_subparsers(dest='command')
    for command in Command.family_members('name'):
        key = command.get_member_attr('key')
        aliases = [key] if key else []
        subparser = subparsers.add_parser(command.name, aliases=aliases)
        command.set_parser(subparser)
    return parser


class Handler():

    def __init__(self, namespace):
        self.namespace = namespace
        self.root = FileSystemRoot(namespace.root)
        command_class = Command.family_member('name', namespace.command)
        if not command_class:
            raise RuntimeError(f"Unknown command {namespace.command}")
        self.ui = UI.family_member('name', command_class.ui)(self)
        self.command = command_class(self.root, self.ui)

    # Handle the command and output its final status

    def execute(self):
        result = self.command.execute(self.namespace)
        if result:
            print(result)
        if self.command.status:
            print(self.command.status)


    # Some useful methods so other components don't need to import from
    # different class families
    
    def get_command_values(self, *attributes):
        return Command.family_attrs(*attributes)


    # A method for commands within interactive UIs. Use our own root but the UI
    # is passed in. Returns None if attribute value doesn't resolve.
    
    def get_command(self, attribute, value, ui):
        member = Command.family_member(attribute, value)
        if member:
            return member(self.root, ui)

