# -*- coding: utf-8 -*-
"""Subprocess execution utilities

.. codeauthor:: Joe Decapo <joe@polka.cat>

"""

import atexit
import os
import subprocess
from multiprocessing.pool import ThreadPool

from termcolor import cprint


# Disable errors shown by pylint for catching too general exception
# pylint: disable=W0703


def subprocess_exit_handler(process):
    """terminate subprocess"""

    try:
        process.terminate()
    except Exception as err:
        del err


def execute_subprocess_command(command, path, shell=True, env=None, stdout=None, stderr=None):
    """Execute subprocess command"""

    if isinstance(command, list):
        cmd = ' '.join(command)
    else:
        cmd = command
    try:
        process = subprocess.Popen(cmd, shell=shell, env=env, cwd=path,
                                   stdout=stdout, stderr=stderr)
        atexit.register(subprocess_exit_handler, process)
        process.communicate()
    except (KeyboardInterrupt, SystemExit):
        raise
    else:
        return process.returncode


def execute_command(command, path, shell=True, env=None, print_output=True):
    """Execute command via thread"""

    cmd_env = os.environ.copy()
    if env:
        cmd_env.update(env)

    if print_output:
        pipe = None
    else:
        pipe = subprocess.PIPE

    pool = ThreadPool()

    try:
        result = pool.apply(execute_subprocess_command,
                            args=(command, path),
                            kwds={'shell': shell, 'env': cmd_env, 'stdout': pipe, 'stderr': pipe})
        pool.close()
        pool.join()
        return result
    except (KeyboardInterrupt, SystemExit):
        if pool:
            pool.close()
            pool.terminate()
        cprint('\n - Command failed\n', 'red')
        return 1
    except Exception as err:
        if pool:
            pool.close()
            pool.terminate()
        cprint('\n - Command failed', 'red')
        print(err + '\n')
        return 1


def execute_forall_command(command, path, forall_env, print_output):
    """Execute forall command with additional environment variables and display continuous output"""

    return execute_command(command, path, env=forall_env, print_output=print_output)

@@ -378,20 +378,91 @@
 bprocess
+%0A%0A    :param Popen process: Popen subprocess instance%0A    :return:%0A    
 %22%22%22%0A
-
 %0A    try
@@ -666,16 +666,436 @@
  command
+%0A%0A    :param command: Command to run. Can be str or list of str%0A    :param str path: Path to set as %60%60cwd%60%60%0A    :param Optional%5Bbool%5D shell: Whether to execute subprocess as %60%60shell%60%60%0A    :param Optional%5Bdict%5D env: Enviroment to set as %60%60env%60%60%0A    :param Optional%5Bint%5D stdout: Value to set as %60%60stdout%60%60%0A    :param Optional%5Bint%5D stderr: Value to set as %60%60stderr%60%60%0A    :return: Subprocess return code%0A    :rtype: int%0A    
 %22%22%22%0A%0A   
@@ -1637,16 +1637,377 @@
 a thread
+%0A%0A    :param command: Command to run. Can be str or list of str%0A    :param str path: Path to set as %60%60cwd%60%60%0A    :param Optional%5Bbool%5D shell: Whether to execute subprocess as %60%60shell%60%60%0A    :param Optional%5Bdict%5D env: Enviroment to set as %60%60env%60%60%0A    :param Optional%5Bbool%5D print_output: Whether to print output%0A    :return: Command return code%0A    :rtype: int%0A    
 %22%22%22%0A%0A   
@@ -2895,24 +2895,24 @@
 nt_output):%0A
-
     %22%22%22Execu
@@ -2996,16 +2996,288 @@
 s output
+%0A%0A    :param command: Command to run. Can be str or list of str%0A    :param str path: Path to set as %60%60cwd%60%60%0A    :param dict forall_env: Enviroment to set as %60%60env%60%60%0A    :param bool print_output: Whether to print output%0A    :return: Command return code%0A    :rtype: int%0A    
 %22%22%22%0A%0A   

Update Sphinx documentation for util.execute