"""
This module defines a thread which takes a provided StampedMessageIterator,
continuously reads StampedMessage's from it, optionally transforms those
messages, and pushes the result to a queue.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import collections
import os
import time

from . import common
from . import expression_parser
from data.tools import zed


class Player(common.ThreadInterface):
    def __init__(self, iterator, queue, blocking):
        assert isinstance(iterator, zed.iterator.StampedMessageIteratorBase)
        assert isinstance(queue, collections.deque)
        assert isinstance(blocking, bool)

        super(Player, self).__init__()
        self._it = iterator
        self._queue = queue
        self._blocking = blocking and queue.maxlen is not None
        self._functor = None

    def _run_impl(self):
        try:
            if self._blocking and len(self._queue) == self._queue.maxlen:
                # If we are pushing data to the queue faster than it can be read
                # out, wait for a bit to give the processor time to be
                # scheduled. This helps reduce thread contention.
                time.sleep(0.05)
            else:
                msg = self._it.next()
                if self._functor is not None:
                    try:
                        msg = self._functor(msg)
                    except:
                        # Raising an error only kills this thread and not the
                        # main process.
                        # os._exit exits the process, which is what we want.
                        # In tihs case we exit with status os.EX_DATAERR,
                        # meaning the input data was incorrect.
                        print("ERROR: One or more of the signals provided "\
                              "doesn't exist. Please review their names and "\
                              "run again")
                        os._exit(os.EX_DATAERR)
                self._queue.append(msg)
        except StopIteration:
            self.shutdown = True

    def set_expression_filter(self, expression_string):
        self._functor = expression_parser.parse(expression_string)
