# This file is auto-generated by setup.py

class TypesBase(object):
    """
    Base class for arbitrary vocabulary type. 
    This class provides bisic initializer, comparators, 
    and (de-)serialization methods. 
    """
    _prefixes = {}
    base_url: str
    shortname: str
    
    def __init__(self, type_uri: str):
        self.parse_names(type_uri)
        if self.__repr__() not in self.__class__._prefixes:
            self.__class__._prefixes[self.__repr__()] \
                = self.__class__._create_prefix(self.shortname,
                                               self.__class__._prefixes.values()
                                               )
    
    def parse_names(self, type_uri:str):
        if '/' in type_uri:
            self.base_uri, self.shortname = type_uri.rsplit('/', 1)
        else:
            self.base_uri = ""
            self.shortname = type_uri

    @classmethod
    def _create_prefix(cls, shortname, existing_prefixes):
        
        def extract_chars(string, indices):
            return "".join(string[i].lower() for i in sorted(set(indices)) if i < len(string))
        
        if shortname.isalnum():
            
            cap_letters = [i for i, c in enumerate(shortname) if c.isupper()] + [len(shortname)]
            if len(cap_letters) > 1:
                max_diff = max(cap_letters[i] - cap_letters[i-1] for i in range(1, len(cap_letters)))
            else:
                max_diff = len(shortname)
            more_letters = []
            prefix = extract_chars(shortname, cap_letters)
            if prefix in existing_prefixes:
                for i in range(1, max_diff):
                    for j in cap_letters:
                        more_letters.append(j + i)
                        prefix = extract_chars(shortname, cap_letters + more_letters)
                        if prefix not in existing_prefixes:
                            break
                    else:
                        continue
                    break
        else:
            prefix = None
        return prefix

    @classmethod
    def from_str(cls, string: str):
        if 'mmif.clams.ai' in string:
            if string.endswith('Document'):
                return DocumentTypesBase(string)
            else:
                return AnnotationTypesBase(string)
        else:
            return cls(string)
    
    def __hash__(self):
        return hash(str(self))
        
    def __eq__(self, other):
        if isinstance(other, str):
            other = self.from_str(other)
        return isinstance(other, TypesBase) and self.base_uri == other.base_uri and self.shortname == other.shortname
            
    def __repr__(self):
        if len(self.base_uri) > 0: 
            return f'{self.base_uri}/{self.shortname}'
        else:
            return self.shortname
    
    # aliases
    def __str__(self):
        return self.__repr__()
    
    def _serialize(self):
        return self.__repr__()

    def get_prefix(self):
        return self.__class__._prefixes[self.__repr__()]

    def set_prefix(self, prefix):
        self.__class__._prefixes[self.__repr__()] = prefix

ThingTypesBase = TypesBase


class ClamsTypesBase(TypesBase):
    """
    Base class for CLAMS vocabulary types. Main 
    This class adds handling of MMIF specification versions 
    in initializer and comparators. 
    """
    version: str
    
    def parse_names(self, type_uri:str):
        if 'mmif.clams.ai' not in type_uri:
            raise ValueError(f'{type_uri} is not a CLAMS vocabulary URI')
        self.base_uri, self.version, _, self.shortname = type_uri.rsplit('/', 3)

    def __hash__(self):
        return hash(str(self))

    def __eq__(self, other):
        if isinstance(other, str):
            other = ThingTypesBase.from_str(other)
        if isinstance(other, ClamsTypesBase):
            if '.' in self.version and '.' in other.version:
            # regular version 
                s_major, s_minor, s_patch = self.version.split('.')
                o_major, o_minor, o_patch = other.version.split('.')
                if s_major != o_major or s_minor != o_minor:
                    return False
            else:
                # dummy version given at development time
                if self.version != other.version:
                    return False
            return self.base_uri == other.base_uri and self.shortname == other.shortname
        else:
            return False
    
    def __repr__(self):
        return f'{self.base_uri}/{self.version}/vocabulary/{self.shortname}'


class AnnotationTypesBase(ClamsTypesBase):
    """
    Inherit from this class to build your own custom annotation
    vocabularies. 
    """
    ...


class DocumentTypesBase(ClamsTypesBase):
    """
    Inherit from this class to build your own custom document
    vocabularies. 
    """
    ...


class ThingType(ThingTypesBase):
    """
    This class contains the topmost CLAMS thing type 
    defined in the spec version 0.4.0 as a class variable. 
    """
    Thing = ClamsTypesBase('http://mmif.clams.ai/0.4.0/vocabulary/Thing')
