import RPi.GPIO as gpio
import time
import threading


class FeApPinConfiguration(object):
    def __init__(self, gpio_numbering, pin_nsa, pin_nsi, pin_gabelschalter,
                 pin_schauzeichen, pin_wecker_enable, pin_wecker_a,
                 pin_wecker_b, invert_gs):
        if gpio_numbering == 'BOARD':
            gpio_numbering = gpio.BOARD
        elif gpio_numbering == 'BCM':
            gpio_numbering = gpio.BCM
        else:
            raise ValueError('Illegal gpio numbering: %s' % (gpio_numbering))

        self.gpio_numbering = gpio_numbering
        self.pin_nsa = pin_nsa
        self.pin_nsi = pin_nsi
        self.pin_gabelschalter = pin_gabelschalter
        self.pin_schauzeichen = pin_schauzeichen
        self.pin_wecker_enable = pin_wecker_enable
        self.pin_wecker_a = pin_wecker_a
        self.pin_wecker_b = pin_wecker_b
        self.invert_gs = invert_gs


class FeApUserInterface(object):
    def __init__(self, pinconfig):
        self.__pinconfig = pinconfig

        gpio.setmode(self.__pinconfig.gpio_numbering)
        gpio.setup(self.__pinconfig.pin_nsa, gpio.IN, gpio.PUD_UP)
        gpio.setup(self.__pinconfig.pin_nsi, gpio.IN, gpio.PUD_UP)
        gpio.setup(self.__pinconfig.pin_gabelschalter, gpio.IN, gpio.PUD_UP)
        gpio.setup(self.__pinconfig.pin_schauzeichen, gpio.OUT)
        gpio.setup(self.__pinconfig.pin_wecker_enable, gpio.OUT)
        gpio.setup(self.__pinconfig.pin_wecker_a, gpio.OUT)
        gpio.setup(self.__pinconfig.pin_wecker_b, gpio.OUT)

        gpio.add_event_detect(self.__pinconfig.pin_nsa, gpio.BOTH,
                              self.__on_nsa_change, 20)
        gpio.add_event_detect(self.__pinconfig.pin_nsi, gpio.FALLING,
                              self.__on_nsi_falling, 20)
        gpio.add_event_detect(self.__pinconfig.pin_gabelschalter, gpio.BOTH,
                              self.__on_gabelschalter_change, 20)
        #self.__nsa_up_time = 0
        self.__nsi_cnt = 0
        self.__weckt = False

        self.__nummernschalter_active_callbacks = []
        self.__nummernschalter_done_callbacks = []
        self.__gabelschalter_callbacks = []

    def __on_nsa_change(self, pin):
        nsastate = gpio.input(self.__pinconfig.pin_nsa)
        if nsastate == 0:
            #self.__nsa_up_time = time.time()
            self.__nsi_cnt = 0

            for cb in self.__nummernschalter_active_callbacks:
                cb()
        else:
            for cb in self.__nummernschalter_done_callbacks:
                cb(self.__nsi_cnt % 10)

    def __on_nsi_falling(self, pin):
        #print('nsi')
        self.__nsi_cnt += 1

    def __on_gabelschalter_change(self, pin):
        gbstate = gpio.input(self.__pinconfig.pin_gabelschalter)
        if self.__pinconfig.invert_gs:
            gbstate = 1 - gbstate
        print('gabelschalter:', gbstate)
        for cb in self.__gabelschalter_callbacks:
            cb(gbstate)

    def __wecker_thread(self):
        while self.__weckt:
            c = 0
            gpio.output(self.__pinconfig.pin_wecker_enable, 1)
            while c < 1000:
                gpio.output(self.__pinconfig.pin_wecker_a, 1)
                gpio.output(self.__pinconfig.pin_wecker_b, 0)
                time.sleep(0.02)
                gpio.output(self.__pinconfig.pin_wecker_a, 0)
                gpio.output(self.__pinconfig.pin_wecker_b, 1)
                time.sleep(0.02)
                c += 40
                print('ring')
            gpio.output(self.__pinconfig.pin_wecker_enable, 0)

            print('')
            time.sleep(4)


    def add_gabelschalter_callback(self, cb):
        self.__gabelschalter_callbacks.append(cb)

    def add_nummernschalter_active_callback(self, cb):
        self.__nummernschalter_active_callbacks.append(cb)

    def add_nummernschalter_done_callback(self, cb):
        self.__nummernschalter_done_callbacks.append(cb)

    def set_wecker(self, enabled):
        if enabled and not self.__weckt:
            self.__weckt = True
            t = threading.Thread(target=self.__wecker_thread)
            t.start()
        elif not enabled:
            self.__weckt = False

    def set_schauzeichen(self, enabled):
        gpio.output(self.__pinconfig.pin_schauzeichen, 1 if enabled else 0)


if __name__ == '__main__':
    gpio.setmode(gpio.BOARD)
    pinconfig = FeApPinConfiguration()
    t = FeApUserInterface(pinconfig)

    def dailed(num):
        print(num)

    t.add_nummernschalter_callback(dailed)

    t.set_schauzeichen(True)
    time.sleep(0.5)
    t.set_schauzeichen(False)
    time.sleep(0.5)
    t.set_schauzeichen(True)
    time.sleep(0.5)
    t.set_schauzeichen(False)
    time.sleep(0.5)
    t.set_schauzeichen(True)
    time.sleep(0.5)
    t.set_schauzeichen(False)
    time.sleep(0.5)
    t.set_schauzeichen(True)
    time.sleep(0.5)
    t.set_schauzeichen(False)
    time.sleep(0.5)

    t.set_wecker(True)
    time.sleep(20)
    t.set_wecker(False)
    while True:
        time.sleep(1)