import logging
import config

class GPIOInterface:

    def __init__(self):
        self.GPIO = None
        self.logger = logging.getLogger(self.__class__.__name__)
        if config.get_settings().get('gpio').get('enabled'):
            try:
                import RPi.GPIO as GPIO
                trigger_str = config.get_settings().get('gpio').get('trigger')
                if trigger_str == "rising":
                    self.trigger = GPIO.RISING
                elif trigger_str == "falling":
                    self.trigger = GPIO.FALLING
                elif trigger_str == "both":
                    self.trigger = GPIO.BOTH
                else:
                    self.logger.warning("Error starting RPi.GPIO: unknown trigger type in config. Should be one of rising, falling, both")
                    raise AssertionError
                pull_str = config.get_settings().get('gpio').get('pull')
                if pull_str == "up":
                    self.pull = GPIO.PUD_UP
                elif pull_str == "down":
                    self.pull = GPIO.PUD_DOWN
                else:
                    self.pull = None
                self.bouncetime = config.get_settings().get('gpio').get('bouncetime', 200)
            except ImportError:
                self.logger.warning("No RPi.GPIO module - disabling GPIO interface")
            except AssertionError:
                pass
            else:
                GPIO.setmode(GPIO.BOARD)
                GPIO.setwarnings(False)
                self.active_buttons = []
                self.cancel_callbacks = []
                self.buttons = []
                self.GPIO = GPIO
                buttons = config.get_settings()['gpio'].get('buttons', {})
                for button in buttons:
                    action_name = button
                    pin_number = buttons[button]
                    self.buttons.append((pin_number, action_name))
                    if self.pull:
                        GPIO.setup(pin_number, GPIO.IN, pull_up_down=self.pull)
                    else:
                        GPIO.setup(pin_number, GPIO.IN)
                    GPIO.add_event_detect(pin_number, self.trigger, bouncetime=self.bouncetime)
                    self.logger.info("GPIO event registered: pin%d=%s" % (pin_number, action_name))

    def check_events(self, printer_interfaces):
        if self.GPIO:
            for pin_num, action_name in self.buttons:
                if self.GPIO.event_detected(pin_num):
                    for pi in printer_interfaces:
                        self.run_method(pi, action_name)

    def run_method(self, pi, method_name):
        method = getattr(pi, method_name, None)
        if method:
            try:
                method()
            except Exception:
                self.logger.exception("Exception in GPIO handler")
        else:
            self.logger.error("GPIO event error: no method %s" % method_name)

    def close(self):
        if self.GPIO:
            self.GPIO.cleanup()

