import re

class ConfigRange:
    def __init__(self, size, type, properties):
        self.size = size
        self.type = type.lower()
        self.properties = properties
        self.start = -1
        
    def get_range_string(self):
        return "{:06x}".format(self.start) + '-' + "{:06x}".format(self.start + self.size)
    
    def __repr__(self):
        return "{:06x}".format(self.size) + ', ' + self.type + ', ' + str(self.properties)

class Config:
    def __init__(self, directory, filename):
        with open(directory + '/' + filename, 'r') as configFile:
            self.text = configFile.read()
            self.directory = directory
            self.ranges = []
            self.name = ''
            self.md5 = ''
            self.subfolder = ''
            self.notSupported = False
            if not self._parse(self.text):
                raise Exception('Error: ' + self.parseError)
            #print(self.name)
            #print(self.md5)
            #print(str(self.ranges))
        
    def _parse(self, text):
        regex_property = r'^\s*([0-9a-zA-Z\-]+)\s*:\s*["]([^"]*)["]\s*$'
        regex_range = r'^\s*\[\s*(0x[0-9a-fA-F]+)\s*\]\s*:\s*(.*)$'
        for line in text.split('\n'):
            line = line.strip() # remove leading and trailing whitespace
            line = line.partition('#')[0] # remove comments
            if len(line) > 0:
                matches = self._parse_test_re(regex_property, line)
                if matches is not None:
                    self._parse_property(matches)
                    continue
                matches = self._parse_test_re(regex_range, line)
                if matches is not None:
                    #print(matches)
                    self._parse_range(matches)
                    continue
                self.parseError = 'Invalid line "' + line + '"'
                return False
        return True
    
    def _parse_property(self, matches):
        propertyName = matches[0]
        propertyValue = matches[1]
        if propertyName == 'config-name':
            self.name = propertyValue
        elif propertyName == 'subfolder':
            self.subfolder = propertyValue
        elif propertyName == 'checksum-md5':
            self.md5 = propertyValue
        elif propertyName == 'not-supported':
            self.notSupported = (propertyValue.lower() == 'true')
        elif propertyName == 'include':
            with open(self.directory + '/' + propertyValue, 'r') as includeFile:
                self._parse(includeFile.read())
        else:
            print('Unknown property "' + propertyName + '" with value "' + propertyValue + '"')
            
    def _parse_range(self, matches):
        rangeSize = int(matches[0], 0)
        rangeProperties = matches[1].split(',')
        
        for i in range(0, len(rangeProperties)):
            rangeProperties[i] = rangeProperties[i].strip() # remove leading and trailing whitespace
            rangeProperties[i] = self._parse_range_property(rangeProperties[i])
            
        self.ranges.append(ConfigRange(rangeSize, rangeProperties[0], rangeProperties[1:]))
            
    def _parse_range_property(self, property):
        if property.startswith('"'): # string
            return property[1:-1]
        else:
            return int(property, 0)
              
    def _parse_test_re(self, regex, line):
        matches = re.match(regex, line)
        if matches is not None:
            return matches.groups()
        return None
