import threading
import signal

from first_event_observer import First_event_observer
from nullth_event_HTTP_starter import HTTP_starter
from second_event_observer import Second_event_observer
from constant import *
from waiter import Waiter


class Blackboard(Waiter):
    print_observers_tuple = list()
    mock_observers = threading.Semaphore(value=1)
    filters_first = list()
    mock_filters_first = threading.Semaphore(value=1)
    filters_second = list()
    mock_filters_second = threading.Semaphore(value=1)
    data = dict()
    type_event = None
    condition = threading.Event()
    raw_preparer = First_event_observer()
    http = HTTP_starter()
    main_job = Second_event_observer()

    def __init__(self):
        super().__init__()
        self.run = None
        self.data[event_second_data] = dict()
        for t in types:
            tt, _ = t
            self.data[event_second_data][tt] = list()

    def start(self):
        self.http.blackboard = self
        self.raw_preparer.blackboard = self
        self.main_job.blackboard = self
        self.start_all()
        self._notify()

    def start_all(self):
        for th, tupl in self.print_observers_tuple:
            save, _ = tupl
            th.type_observed = save
            th.blackboard = self
            th.daemon = True
            th.start()
        self.raw_preparer.daemon = True
        self.main_job.daemon = True
        self.http.daemon = True
        self.raw_preparer.start()
        self.main_job.start()
        self.http.start()

    def attach_observer_tuple(self, observer_tuple):
        self.mock_observers.acquire()
        self.print_observers_tuple.append(observer_tuple)
        self.mock_observers.release()

    def deattach_observer_tuple(self, observer_tuple):
        self.mock_observers.acquire()
        self.print_observers_tuple.remove(observer_tuple)
        self.mock_observers.release()

    def register_filter_first(self, filter0):
        self.mock_filters_first.acquire()
        self.filters_first.append(filter0)
        self.mock_filters_first.release()

    def register_filter_second(self, filter1):
        self.mock_filters_second.acquire()
        self.filters_second.append(filter1)
        self.mock_filters_second.release()

    def _notify(self):
        self.pripare_to_signal()
        while self.run:
            self.wait_until(1)
            if not self.run:
                break
            self.main_job.update(self.type_event)
            self.raw_preparer.update(self.type_event)
            for th, _ in self.print_observers_tuple:
                th.update(self.type_event)

    def pripare_to_signal(self):
        self.run = True

        def signal_handler(sig, frame):
            self.run = False
            self._notify()

        signal.signal(signal.SIGINT, signal_handler)

    def notify(self):
        self.update(1)
