import axipy
from axipy import Style, IndividualThematicLayer, RangeThematicLayer, LineStyle, PointStyle, PolygonStyle

from LoadMiWor.ui.processTool.parserWor.ParserMiCommand.addInParsers import prepareStringIndvidualValue, getSyleObjects, \
    prepareStringRangeValue
from LoadMiWor.ui.processTool.parserWor.ParserMiCommand.modParsers.parsersLib import initLoadLibParser
from LoadMiWor.ui.processTool.parserWor.parse import parse, search

def getBrush(index_start,words):
    mi_brush="Brush ("
    mi_brush=mi_brush+words[index_start+1]+","
    mi_brush=mi_brush+words[index_start+2]+","
    mi_brush=mi_brush+words[index_start+2]+") "
    return mi_brush
def GetSymbol(index_start,words):
    mi_symbol="Symbol ("
    ln_words_symbol=len(words)-index_start-1
    if ln_words_symbol==3:
        ''' тиль без шрифта '''
        mi_symbol=mi_symbol+words[index_start+1]+","
        mi_symbol=mi_symbol+words[index_start+2]+","
        mi_symbol=mi_symbol+words[index_start+3]+") "
        return mi_symbol
    mi_symbol=mi_symbol+words[index_start+1]+","
    mi_symbol=mi_symbol+words[index_start+2]+","
    mi_symbol=mi_symbol+words[index_start+3]+","
    isFirstKey=True
    isEndString=False
    for i in range(index_start+4,len(words)):
        cur_word=words[i]
        if not cur_word.isnumeric():
            if isFirstKey:
                mi_symbol=mi_symbol+'"'
            else:
                mi_symbol=mi_symbol+' '
            mi_symbol=mi_symbol+cur_word
            isFirstKey=False
        else:
            if not isEndString:
                mi_symbol=mi_symbol+'"'
                isEndString=True

            mi_symbol=mi_symbol+','
            mi_symbol=mi_symbol+cur_word
    mi_symbol=mi_symbol+") "
    return mi_symbol
def getStyle(words_key):
    str_brush=None
    str_pen=None
    str_symbol=None
    for i,key in enumerate(words_key):
        if key.lower()=='brush':
            str_brush=getBrush(i,words_key)
        if key.lower()=='pen':
            str_pen="Pen ("+words_key[i+1]+","+words_key[i+2]+","+words_key[i+3]+") "
        if key.lower()=='symbol':
            str_symbol=GetSymbol(i,words_key)
    return str_brush,str_pen,str_symbol
def MiBrushPenSymbolCombine(mi_brush,mi_pen,mi_symbol):
    mi_style=None
    if mi_brush is not None:
        mi_style=mi_brush
    if mi_pen is not None:
        if mi_style is None:
            mi_style=mi_pen
        else:
            mi_style=mi_style+mi_pen
    if mi_symbol is not None:
        if mi_style is None:
            mi_style=mi_symbol
        else:
            mi_style=mi_style+mi_symbol
    return mi_style
def getNumericFromString(str_value:str):
    #if not str_value.isnumeric():
    #    return None
    try:
        if str_value.find(".")>=0:
            return float(str_value)
        return int(str_value)
    except:
        return None
class AxiIndividualThematic:
    def __init__(self,expr:str):
        self.__expr=expr
        self.__list_value_style=[]
        self.__axi_IndividualThematic=IndividualThematicLayer(expr)
        self.__default_style=None
    def addValue(self,value,mi_style):
        self.__list_value_style.append({'value':value,"style":Style.from_mapinfo(mi_style)})
    def setDefault(self,wor_string):
        over_style=getSyleObjects(wor_string)
        overStyle=axipy.da.CollectionStyle()
        if over_style['brush'] is not None and over_style['pen'] is not None:
            polygon_style=Style.from_mapinfo(over_style['brush']+' '+over_style['pen'])
            overStyle.for_polygon(polygon_style)
        if over_style['line'] is not None:
            line_style=Style.from_mapinfo(over_style['line'])
            overStyle.for_line(line_style)
        if over_style['symbol'] is not None:
            point_style=Style.from_mapinfo(over_style['symbol'])
        if over_style['font'] is not None:
            text_style=Style.from_mapinfo(over_style['font'])
        if over_style['font'] is not None or over_style['symbol'] is not None or over_style['line'] is not None or (over_style['brush'] is not None and over_style['pen'] is not None):
            self.__default_style=overStyle


    def update(self):
        count=self.__axi_IndividualThematic.count
        for i in range(count):
            value=self.__axi_IndividualThematic.get_value(i)
            item_thems=list(filter(lambda item: item['value'] ==value, self.__list_value_style))
            if len(item_thems)==0:
                if self.__default_style is not None:
                    self.__axi_IndividualThematic.set_style(i,self.__default_style)
                continue
            item_theme=item_thems[0]
            mi_style=item_theme['style']
            if isinstance(mi_style,LineStyle):
                self.__axi_IndividualThematic.style_geometry_type=axipy.StyleGeometryType.Linear
            if isinstance(mi_style, PointStyle):
                self.__axi_IndividualThematic.style_geometry_type = axipy.StyleGeometryType.Point
            if isinstance(mi_style, PolygonStyle):
                self.__axi_IndividualThematic.style_geometry_type = axipy.StyleGeometryType.Polygonal

            self.__axi_IndividualThematic.set_style(i,mi_style)
        self.__axi_IndividualThematic.title="Отдельные значения -"+self.__expr
    @property
    def themeLayer(self):
        return self.__axi_IndividualThematic
class AxiRangeThematic:
    def __init__(self,expr:str,ignore=None):
        self.__expr=expr
        self.__list_value_style=[]
        self.__axi_RangeThematicLayer=RangeThematicLayer(expr)
    def addValue(self,values,mi_style):
        self.__list_value_style.append({'value':values,"style":Style.from_mapinfo(mi_style)})
    def setSplitType(self,type_split):
        self.__type_split=type_split
        if type_split==1:
            self.__axi_RangeThematicLayer.splitType=RangeThematicLayer.EQUAL_COUNT
            return
        if type_split==2:
            self.__axi_RangeThematicLayer.splitType=RangeThematicLayer.EQUAL_INTERVAL
            return
        self.__axi_RangeThematicLayer.splitType=RangeThematicLayer.MANUAL
    def update(self):
        self.__axi_RangeThematicLayer.ranges=len(self.__list_value_style)
        for i,range in enumerate(self.__list_value_style):
            self.__axi_RangeThematicLayer.set_interval_value(i,range['value'])
            self.__axi_RangeThematicLayer.set_style(i,range['style'])
        #self.setSplitType(self.__type_split)
        self.__axi_RangeThematicLayer.title="Диапозоны "+self.__expr
    @property
    def themeLayer(self):
        return self.__axi_RangeThematicLayer

def factoryRangeTheme(expr,items,source_wor):
    #id=int(id_shade)
    ignore=None
    expression=expr
    if expr.find('ignore')>0:
        token_ignore=parse('{expr} ignore {value}',expr)
        expression=token_ignore.named['expr']
        ignore=float(token_ignore.named['value'])
    axiRange=AxiRangeThematic(expression,ignore)
    children_item=items['children']
    for i,item in enumerate(children_item):
        words=item['words']
        if not words[0].isnumeric():
            break
        mi_str = source_wor[item['index']].strip()
        str_low,str_max=prepareStringRangeValue(mi_str)
        low_value=getNumericFromString(str_low)
        hi_value=getNumericFromString(str_max)
        mi_brush,mi_pen,mi_symbol=getStyle(words)
        mi_style=MiBrushPenSymbolCombine(mi_brush,mi_pen,mi_symbol)
        axiRange.addValue((low_value,hi_value),mi_style)
    return axiRange
def factoryIndividualTheme(expr,items,source_wor):
    axiIndividual=AxiIndividualThematic(expr)
    children_item=items['children']
    for i,item in enumerate(children_item):
        mi_str=source_wor[item['index']].strip()
        if mi_str.lower().find('default')==0:
            axiIndividual.setDefault(mi_str)
            continue

        value,style=prepareStringIndvidualValue(mi_str)
        if value is None:
            continue
        if value.isnumeric():
            if value.isdigit():
                value = int(value)
            else:
                value = float(value)
        axiIndividual.addValue(value,style)
    return axiIndividual







def factoryThemeLayer(items,source_wor):
    lib_token=initLoadLibParser()
    string_wor=source_wor[items['index']]
    token_theme=None
    token_theme=lib_token['shade_range'].parserToken(string_wor)
    if token_theme is not None:
        ''' Создаем тематический слой диапозонов'''
        id_shade=int(token_theme.named['id_layer'])
        expression=token_theme.named['expr']

        axiRange=factoryRangeTheme(expression,items,source_wor)
        return {"id":id_shade,"shade":axiRange}
    token_theme=lib_token['shade_individual'].parserToken(string_wor.strip())
    if token_theme is not None:
        ''' Создаем тематический слой индивидуальных занчений'''
        id_shade = int(token_theme.named['id_layer'])
        axiIndividual = factoryIndividualTheme(token_theme.named['expr'], items, source_wor)
        return {"id": id_shade, "shade": axiIndividual}
    token_theme=lib_token['shade_individual_1'].parserToken(string_wor.strip())
    if token_theme is not None:
        ''' Создаем тематический слой индивидуальных занчений'''
        id_shade=int(token_theme.named['id_layer'])
        axiIndividual=factoryIndividualTheme(token_theme.named['expr'],items,source_wor)
        return {"id":id_shade,"shade":axiIndividual}
    token_theme = lib_token['shade_individual_2'].parserToken(string_wor.strip())
    if token_theme is not None:
        ''' Создаем тематический слой индивидуальных занчений'''
        id_shade = int(token_theme.named['id_layer'])
        axiIndividual = factoryIndividualTheme(token_theme.named['expr'], items, source_wor)
        return {"id": id_shade, "shade": axiIndividual}
    return None
class AxiThemeLayer:
    def __init__(self,id_layer,zoom_visible=False,min_zoom=None,max_zoom=None):
        self.__idLayer=id_layer
        self.__zoom_visible=zoom_visible
        self.__min_zoom=min_zoom
        self.__max_zoom=max_zoom
    @property
    def Id(self):
        return self.__idLayer
    @property
    def zoom_visible(self):
        return self.__zoom_visible
    @property
    def min_zoom(self):
        return self.__min_zoom
    @property
    def max_zoom(self):
        return self.__max_zoom



    




