import subprocess
import typing as tp
import threading
import logging

from .exceptions import ProcessFailed

logger = logging.getLogger(__name__)


def read_nowait(process: subprocess.Popen, output_list: tp.List[str]):
    try:
        while process.stdout.readable():
            line = process.stdout.readline()
            output_list.append(line)
    except (IOError, OSError):
        pass


def call_and_return_stdout(args: tp.Union[str, tp.List[str]],
                           timeout: tp.Optional[int] = None,
                           encoding: tp.Optional[str] = None,
                           expected_return_code: int = 0, **kwargs) -> tp.Union[bytes, str]:
    """
    Call a process and return it's stdout.

    Everything in kwargs will be passed to subprocess.Popen

    A bytes object will be returned if encoding is not defined, else stdout will be decoded
    according to specified encoding.

    #todo every usage of this call will spawn a daemonic thread, pending a fix

    :param args: arguments to run the program with. If passed a string, it will be split on space.
    :param timeout: amount of seconds to wait for the process result. If process does not complete
        within this time, it will be sent a SIGKILL
    :param encoding: encoding with which to decode stdout. If none is passed, it will be returned as a bytes object
    :param expected_return_code: an expected return code of this process. 0 is the default. If process
        returns anything else, ProcessFailed will be raise
    :raises ProcessFailed: process' result code was different from the requested
    """
    if isinstance(args, str):
        args = args.split(' ')
    kwargs['stdout'] = subprocess.PIPE

    stdout_list = []

    proc = subprocess.Popen(args, **kwargs)
    reader_thread = threading.Thread(target=read_nowait, args=(proc, stdout_list), daemon=True)
    reader_thread.start()

    try:
        proc.wait(timeout=timeout)
    except subprocess.TimeoutExpired:
        proc.kill()
        proc.wait()

    if proc.returncode != expected_return_code:
        raise ProcessFailed(proc.returncode)
    else:
        if encoding is None:
            return b''.join(stdout_list)
        else:

            return ''.join((row.decode(encoding) for row in stdout_list))



@@ -248,25 +248,22 @@
 ess.
-stdout.readable()
+poll() is None
 :%0A  
@@ -302,14 +302,63 @@
 read
-line()
+(2048)%0A            if line == '':%0A                break
 %0A   
@@ -962,88 +962,8 @@
 g.%0A%0A
-    #todo every usage of this call will spawn a daemonic thread, pending a fix%0A%0A
     
@@ -1986,16 +1986,41 @@
 c.wait()
+%0A    reader_thread.join()
 %0A%0A    if

resolve a #todo