from threading import Thread

from multiprocessing import Queue


class Stream(object):

    def __init__(self, process, type):
        self.process = process
        self.type = type
        self.content = ''
        self.last_read = None
        self.remain = ''
        self.nb_lines = 0
        self.tee = None
        self.tee_file = None


    def start(self, source, tee=None, check=None, check_timeout=None):
        """
        Start the thread that listens to the stream and process it
        """
        self.source = source

        if tee:
            self.tee = tee
            self.tee_file = open(tee, 'w+')
        else:
            self.tee_file = None

        q = Queue() if check else None

        # initiate the parsing thread
        self.thread = Thread(target=self.do_streaming, args=(check, q))
        self.thread.daemon = True # thread dies with the program
        self.thread.start()

        # wait for the check to be complete
        if check:
            result = q.get(timeout=check_timeout)
            q.close()
            return result


    def do_streaming(self, check=None, q=None):
        """
        Parse the stream and trigger the corresponding events
        """
        try:
            if self.type == 'stdout':
                # call the event for the stream close
                self.process.on_start()

            line = self.source.readline()
            while line:
                str_line = line.decode()
                self.nb_lines += 1

                # check if the stream correspond to the check handler
                if check is not None:
                    result = check(str_line)
                    if result:
                        q.put(result)
                        check = None

                # update the content
                self.content += str_line

                # call the events on new line
                self.process.on_new_line(str_line, self.type)

                # write the log file
                if self.tee_file:
                    self.tee_file.write(str_line)
                    self.tee_file.flush()

                line = self.source.readline()

            if self.type == 'stdout':
                # call the event for the stream close
                self.process.on_stop()

        except Exception as e:
            if q:
                q.put(None)
                q.close()
            self.process.logger.error('Error in the streaming of {} : {}'.format(self.process.name, e))
            self.process.kill()