import collections
import os
import logging

import paths


class MultiPrinterGPIOConf:

    COMMENT = "#"
    PARAMS = [('pin', int), ('printer_id', str), ('command', str), ('pull', str)]
    OUT_PREFIX = "out_"

    @staticmethod
    def save_conf(text, filepath=None):
        if not filepath:
            filepath = paths.GPIO_CONF_PATH
        try:
            with open(filepath, "w") as f:
                f.write(text)
        except Exception as e:
            return str(e)

    @staticmethod
    def erase_conf(filepath=None):
        if not filepath:
            filepath = paths.GPIO_CONF_PATH
        try:
            os.remove(filepath)
        except:
            pass

    def __init__(self):
        self.logger = logging.getLogger((__class__.__name__))

    def load_conf(self, filepath=None):
        conf_dicts = []
        if not filepath:
            filepath = paths.GPIO_CONF_PATH
        try:
            if os.path.exists(filepath):
                with open(filepath) as f:
                    for line in f.readlines():
                        line = line.split(self.COMMENT)[0].strip()
                        if line:
                            pin_config = self.parse_a_line(line)
                            if pin_config:
                                conf_dicts.append(pin_config)
            else:
                with open(filepath, "w") as f:
                    f.write(self.COMMENT + "Multiprinter GPIO config\n")
                    f.write(self.COMMENT + "Text to the right of # is ignored\n")
                    f.write(self.COMMENT + "printer_id: in format VID_PID_SNR or * for any printer\n")
                    f.write(self.COMMENT + "commands: cancel, pause, send_bed_clear, out_bed_not_clear and more in the docs\n")
                    f.write(self.COMMENT + "commands consider outputs except for prefixed with out_\n")
                    f.write(self.COMMENT + "pull values are optional. Can be one of three: up, down and disable. Default is up\n")
                    f.write(self.COMMENT + "For output lines pull column sets inversion of output event. Default is no.\n")
                    f.write(self.COMMENT + "Values are space or tab separated\n\n")
                    f.write(self.COMMENT + " ".join([i[0] for i in self.PARAMS]) + "(optional)\n")
        except Exception as e:
            self.logger.error('Error in config: ' + str(e))
        return conf_dicts

    def parse_a_line(self, line):
        conf = {}
        try:
            params_templ = collections.deque(self.PARAMS)
            for param in [ param.strip() for param in line.split() ]:
                if not params_templ or param.startswith(self.COMMENT):
                    break
                param_name, param_type = params_templ.popleft()
                try:
                    value = param_type(param)
                    # if param_name == 'command':
                    #     is_output = value.startswith(self.OUT_PREFIX)
                    # if param_name == 'pull':
                    #     if is_output:
                    #         if value == 'no':
                    #             value = "" 
                    #     elif value not in ('up', 'down', 'disable'):
                    #         self.logger.warning(f'Disabling invalid pull value {value} in line: {line}')
                    #         value = "disable"
                    if param_name == 'pull' and value == 'no':
                        value = ""
                except ValueError:
                    self.logger.warning(f'Invalid value {param} in line: ' + line)
                    continue
                else:
                    conf[param_name] = value
        except Exception as e:
            self.logger.error('Error parsing a config line: ' + str(e))
        return conf


