import os

from base_gpio_interface import BaseGPIOInterface
from gpio_map import GPIOMap

from periphery import GPIO # pylint: disable=import-error


class PeripheryGPIOInterface(BaseGPIOInterface):

    CHAR_GPIO_DEV_NAME = 'gpiochip'

    def __init__(self):
        self.sysfs_mode = not self.char_gpio_available()
        self.pin_map = GPIOMap()
        super().__init__()

    def setup_gpio(self, pull_str=None, trigger_str=None, _=None):
        return True
    
    def char_gpio_available(self):
        for filename in os.listdir('/dev'):
            if self.CHAR_GPIO_DEV_NAME in filename:
                return True
        return False
    
    def setup_input(self, pin_number, pull):
        return self.setup_pin('in', pin_number, pull)

    def setup_output(self, pin_number):
        return self.setup_pin('out', pin_number)

    def setup_pin(self, role, pin_number, pull=None):
        try:
            kwargs = {}
            if pull:
                if "pull" not in pull and pull != 'disable':
                    pull = "pull_" + pull
                kwargs['bias'] = pull
            if self.sysfs_mode:
                self.logger.info(f'Using GPIO pin{pin_number} as {role}put in sysfs mode')
                line_number = self.pin_map.get_chip_line(pin_number)
                #self.logger.debug(f'GPIO Sysfs setup {line_number} {role} {kwargs}')
                return GPIO(line_number, role, **kwargs)
            else:
                self.logger.info(f'Using GPIO pin{pin_number} as {role}put in chardev mode')
                chip_and_pin = self.pin_map.get_cgpio_dev_and_line(pin_number)
                if chip_and_pin:
                    #self.logger.debug(f'CGPIO chip_dev={chip_and_pin[0]} in_dev_pin_num={chip_and_pin[1]} {role} {kwargs}')
                    return GPIO(*chip_and_pin, role, **kwargs)
                else:
                    raise ValueError('Unable to setup a pin')
        except:
            self.logger.exception(f'Error on setup of GPIO pin number {pin_number}')

    def read_level(self, pin_number):
        try:
            return self.in_pins[pin_number]['handle'].read()
        except Exception as e:
            self.logger.error(f'Error on read from GPIO pin number {pin_number} {e}')
            self.enabled = False
            return False

    def write_level(self, pin_number, level):
        try:
            self.out_pins[pin_number]['handle'].write(level)
        except Exception as e:
            self.logger.error(f'Error on write to GPIO pin number {pin_number} {e}')
            self.enabled = False

    def close(self):
        self.enabled = False
        for pin_number in self.in_pins:
            try:
                self.in_pins[pin_number]['handle'].close()
            except:
                self.logger.exception(f'Error on close GPIO pin number {pin_number}:')
        for pin_number in self.out_pins:
            try:
                self.out_pins[pin_number]['handle'].close()
            except:
                self.logger.exception(f'Error on close GPIO pin number {pin_number}:')


if __name__ == "__main__":
    per_inter = PeripheryGPIOInterface()
