# TODO: Docstrings
import subprocess


class BaseProcess(object):
    # TODO: Docstrings
    def __init__(self, *args, **kwargs):
        # TODO: Docstrings
        self.process = None
        self.command = None
        self.named_parameter_separator = '='
        self.named_parameter_prefix = '--'

    def start_process(self, *args, **kwargs):
        # TODO: Docstrings
        command = self.prepare_command(self.get_command(), **kwargs)
        self.command = command
        self.process = subprocess.Popen(command,
                                        stdin=subprocess.PIPE,
                                        stdout=subprocess.PIPE,
                                        stderr=subprocess.PIPE)

    def run_process(self, *args, **kwargs):
        # TODO: Docstrings
        self.start_process(*args, **kwargs)
        output, error = self.process.communicate()
        return output, error

    @property
    def argument_mapping(self):
        # TODO: Docstrings
        raise NotImplementedError('Derived classes must implement the argument_mapping property.')

    def argument_mapping_to_list(self):
        # TODO: Docstrings
        argument_list = list()
        for option, value in self.argument_mapping.items():
            if value:
                if value is True:
                    argument_list.append('-' + option)
                else:
                    argument_list += ['-' + option, str(value)]
        return argument_list

    def get_command(self):
        raise NotImplementedError('Derived classes must implement the get_command method.')

    def prepare_command(self, unprepared_command, **kwargs):
        if self.named_parameter_separator != ' ':
            unprepared_command += [self.named_parameter_prefix + key + self.named_parameter_separator + str(value)
                                   for key, value in kwargs.items()]
        else:
            for key, value in kwargs.items():
                unprepared_command.append(self.named_parameter_prefix + key)
                unprepared_command.append(value)
        return unprepared_command
