from __future__ import print_function
import os
import sys
import subprocess
from os import environ as env
from shellpython import config

_colorama_intialized = False
_colorama_available = True
    import colorama
    from colorama import Fore, Style
except ImportError:
    _colorama_available = False

def _is_colorama_enabled():
    return _colorama_available and config.COLORAMA_ENABLED

def _print_stdout(text):

def _print_stderr(text):
    print(text, file=sys.stderr)

# print all stdout of executed command

# print all stderr of executed command

# runs command in interactive mode when user can read output line by line and send to stdin

# no throw mode. With this parameter user explicitly says that NonZeroReturnCodeError must not be thrown for this
# specific command. It may be useful if for some reason this command does not return 0 even for successful run

def exe(cmd, params):
    """This function runs after preprocessing of code. It actually executes commands with subprocess

    :param cmd: command to be executed with subprocess
    :param params: parameters passed before ` character, i.e. p`echo 1 which means print result of execution
    :return: result of execution. It may be either Result or InteractiveResult

    global _colorama_intialized
    if _is_colorama_enabled() and not _colorama_intialized:
        _colorama_intialized = True

    if config.PRINT_ALL_COMMANDS:
        if _is_colorama_enabled():
            _print_stdout(Fore.GREEN + '>>> ' + cmd + Style.RESET_ALL)
            _print_stdout('>>> ' + cmd)

    if _is_param_set(params, _PARAM_INTERACTIVE):
        return _create_interactive_result(cmd, params)
        return _create_result(cmd, params)

def _is_param_set(params, param):
    return True if params.find(param) != -1 else False

class ShellpyError(Exception):
    """Base error for shell python

class NonZeroReturnCodeError(ShellpyError):
    """This is thrown when the executed command does not return 0
    def __init__(self, cmd, result):
        self.cmd = cmd
        self.result = result

    def __str__(self):
        if _is_colorama_enabled():
            return 'Command {red}\'{cmd}\'{end} failed with error code {code}, stderr output is {red}{stderr}{end}'\
                .format(red=Fore.RED, end=Style.RESET_ALL, cmd=self.cmd, code=self.result.returncode,
            return 'Command \'{cmd}\' failed with error code {code}, stderr output is {stderr}'.format(
                    cmd=self.cmd, code=self.result.returncode, stderr=self.result.stderr)

class Stream:
    def __init__(self, file, encoding, print_out_stream=False, color=None):
        self._file = file
        self._encoding = encoding
        self._print_out_stream = print_out_stream
        self._color = color

    def __iter__(self):
        return self

    def next(self):
        return self.sreadline()

    __next__ = next

    def sreadline(self):
        line = self._file.readline()
        if sys.version_info[0] == 3:
            line = line.decode(self._encoding)

        if line == '':
            raise StopIteration
            line = line.rstrip(os.linesep)
            if self._print_out_stream:
                if self._color is None:
                    _print_stdout(self._color + line + Style.RESET_ALL)

            return line

    def swriteline(self, text):
        text_with_linesep = text + os.linesep
        if sys.version_info[0] == 3:
            text_with_linesep = text_with_linesep.encode(self._encoding)


class InteractiveResult:
    """Result of a shell command execution.

    To get the result as string use str(Result)
    To get lines use the Result.lines field
    You can also iterate over lines of result like this: for line in Result:
    You can compaire two results that will mean compaire of result strings
    def __init__(self, process, params):
        self._process = process
        self._params = params
        self.stdin = Stream(process.stdin, sys.stdin.encoding)

        print_stdout = _is_param_set(params, _PARAM_PRINT_STDOUT) or config.PRINT_STDOUT_ALWAYS
        self.stdout = Stream(process.stdout, sys.stdout.encoding, print_stdout)

        print_stderr = _is_param_set(params, _PARAM_PRINT_STDERR) or config.PRINT_STDERR_ALWAYS
        color = None if not _is_colorama_enabled() else Fore.RED
        self.stderr = Stream(process.stderr, sys.stderr.encoding, print_stderr, color)

    def sreadline(self):
        return self.stdout.sreadline()

    def swriteline(self, text):

    def returncode(self):
        return self._process.returncode

    def __iter__(self):
        return iter(self.stdout)

    def __bool__(self):
        return self.returncode == 0

    __nonzero__ = __bool__

class Result:
    """Result of a shell command execution.

    To get the result stdout as string use str(Result) or Result.stdout or print Result
    To get output of stderr use Result.stderr()

    You can also iterate over lines of stdout like this: for line in Result:

    You can access underlying lines of result streams as Result.stdout_lines Result.stderr_lines.
    E.g. line_two = Result.stdout_lines[2]

    You can also compaire two results that will mean compaire of result stdouts
    def __init__(self):
        self._stdout_lines = []
        self._stderr_lines = []
        self.returncode = None

    def stdout(self):
        """Stdout of Result as text
        return os.linesep.join(self._stdout_lines)

    def stderr(self):
        """Stderr of Result as text
        return os.linesep.join(self._stderr_lines)

    def stdout_lines(self):
        """List of all lines from stdout
        return self._stdout_lines

    def stderr_lines(self):
        """List of all lines from stderr
        return self._stderr_lines

    def _add_stdout_line(self, line):
        line = line.rstrip(os.linesep)

    def _add_stderr_line(self, line):
        line = line.rstrip(os.linesep)

    def __str__(self):
        return self.stdout

    def __iter__(self):
        return iter(self._stdout_lines)

    def __eq__(self, other):
        return self.__str__() == other.__str__()

    def __bool__(self):
        return self.returncode == 0

    __nonzero__ = __bool__

def _create_result(cmd, params):
    p = subprocess.Popen(cmd,

    result = Result()

    for line in p.stdout.readlines():
        if sys.version_info[0] == 3:
            line = line.decode(sys.stdout.encoding)


    for line in p.stderr.readlines():
        if sys.version_info[0] == 3:
            line = line.decode(sys.stderr.encoding)



    if (_is_param_set(params, _PARAM_PRINT_STDOUT) or config.PRINT_STDOUT_ALWAYS) and len(result.stdout) > 0:

    if (_is_param_set(params, _PARAM_PRINT_STDERR) or config.PRINT_STDERR_ALWAYS) and len(result.stderr) > 0:
        if _is_colorama_enabled():
            _print_stderr(Fore.RED + result.stderr + Style.RESET_ALL)

    result.returncode = p.returncode

    if p.returncode != 0 and not _is_param_set(params, _PARAM_NO_THROW):
        raise NonZeroReturnCodeError(cmd, result)

    return result

def _create_interactive_result(cmd, params):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

    result = InteractiveResult(p, params)

    return result