from tnz import * 
z       = {}
extDict = {
    'jpg':'img',
}


FDIR     = { 
    'x' : 0, 'y' : 1, 'w' : 2, 'h' : 3,
    'ML': 4, 'MT': 5, 'MR': 6, 'MB': 7,
    'BL': 8, 'BT': 9, 'BR':10, 'BB':11,
    'PL':12, 'PT':13, 'PR':14, 'PB':15,
}


def print_kv(ln='7:', obj={} ):
    print('316:', '-'*32 )
    if type(obj) != dict: return 
    for k,v in obj.items():
        print(f'{ln} {k:12}: {v}')


def parse_box(s=None, tokens=None):
    if s         : tokens = tnz(s[1:]) +[['w','a']]
    if not tokens: return {}

    f = [0,0,0,0]
    #print('137:', tokens, '\n' )
    for i,token in enumerate( tokens):
        _type, _value = token
        
        if _type  in 'nd': 
            _sufffix = tokens[i+1][1]
            num      = float(_value)
            if 'a' in _sufffix: f = [num,num,num,num]
            if 'l' in _sufffix: f[0] = num
            if 't' in _sufffix: f[1] = num
            if 'r' in _sufffix: f[2] = num
            if 'b' in _sufffix: f[3] = num
            if 'h' in _sufffix: f[0], f[2] = [num, num] 
            if 'v' in _sufffix: f[1], f[3] = [num, num] 
        
    
    k= {'M':'Mr','B':'Br','P':'Pd'}.get(s[0], 'P')
    #print('121:', tokens)
    #print('122:', k, f)
    return k,f 


def parse_ly(s=None, tokens=None):
    """
        ly_flag | arr | align | offset o_flag | offset1 | aId ly_box 
        u0F     | []  | &00   | +2.5   z4     | , +5 z5 | !A  .Pd
        w       |     | &d    | n      w      | , n  w  | !w  .w     
        
        <ly_flag>
            u00     u_flag    u_area
            z00     z_flag    z_point 
            m*x*S*  c_flag    matrix 
            R*C*S*  c_flag    table_cell
        
        <arr>
            [si,ei,sj,ej...] 
            s  start
            e  end 
        
        <ly_box> 
            Mr      margin 
            Br      border
            Pd      padding 

        <s_flag>    //suffix flag 
            //s_flag  for u_type 
            S   square  
            N   numb    bw = aw/N
            R   make this block resize 

            //cell flag 
            b   span both   
            r   span row 
            c   span volum 

        <obj>
            {m,n}       //matrix row colum 
            {R,C,S}     //tabel cell obj 
    """
    
    if s          : tokens = tnz(s[1:])
    if  not tokens: return {}

    tokens   = [['w',s[0]]] +tokens+ [[' ', ' ']]*16
    

    #print('127:', s)
    #for i, token in enumerate(tokens):
    #    print('111:', i, token)
    
    _type     = '' 
    pre_value = ''
    ly_type   = None 
    ly_flag   = None
    ly_props  = {}
    si        = 0

    while si< len(tokens) : 
        _type, _value = tokens[si]
        #print('196:', tokens[si])
        if   not ly_type      : ly_type = _value
        elif not ly_flag      : ly_flag = _value
        if   _type == 'd'     : ly_props[pre_value] = int(_value)
        elif _type not in 'wd': break

        pre_value = _value 
        si       +=1
    #print('183:', s, tokens[si-1] )   
    if tokens[si-1][0] == 'w': ly_props['s_flag'] = tokens[si-1][1]
    if tokens[si][0]   == '[':
        """
            [start:end:step]
            [depth0, depth1, depth2]
        """
        #iarr   index arra y
        
        i,iarr, tmp =0, [], [None]*3
        while si< len(tokens) : 
            _type,_value  = tokens[si]
            si  +=1 
            #print('215:', _type, _value)
            if _type  in 'dn'   : tmp[i] = int(_value); 
            if _type  == ':'    : i+=1
            if _value in ',ijk]': i =0; iarr+=tmp; tmp=[None]*3; 
            if _type  in '] '   : break
            
        ly_props['ly_iarr'] = iarr         

    if tokens[si][0] == '&': _type = '&'; si+=1
    if tokens[si][0] == 'd' and _type == '&': ly_props['&']      = '&'+tokens[si][1]    ; si+=1
    if tokens[si][0] == 'n'                 : ly_props['offset'] = float(tokens[si][1]) ; si+=1; _type = 'o'                 
    if tokens[si][0] == 'w' and _type == 'o': ly_props['o_flag'] = tokens[si][1]        ; si+=1
    
    
    #if tokens[si][0] == ',': _type = '&'; si+=1
    #if tokens[si][0] == 'n': _type = '&'; si+=1
    #if tokens[si][0] == 'w': _type = '&'; si+=1
    
    if tokens[si][0] == '!'                 : _type           = '!'              ; si+=1
    if tokens[si][0] == 'w' and _type == '!': ly_props['aId'] = '!'+tokens[si][1]; si+=1
    if tokens[si][0] == '.' and _type == '!': _type           = '.'              ; si+=1 
    if tokens[si][0] == 'w' and _type == '.': ly_props['ly_box'] = tokens[si][1]
                
    if ly_type in 'xy': ly_type ='xy'
    ly_props['ly_type'] = ly_type 
    ly_props['ly_flag'] = ly_type + ly_flag
    ly_props.setdefault('offset', 0)
    #print('252:', ly_type, ly_flag )
    #print_kv('243:', ly_props)
    #for k,v in ly_props.items():
    #    print(f'255: {k:12}: {v}')
    
    return ly_props


def parse_ystr(s, yli={}):
    #s = yli.get('_')
    if len(s)==0: return

    props = {
        'class':[],
        'F'    :[0]*12*4,
        #'f':[
        #    0,0,0,0,    #bx by bw bh    box  
        #    0,0,0,0,    #ML MT MR MB    margin 
        #    0,0,0,0,    #BL BT BR BB    border
        #    0,0,0,0,    #PL PT PR PB    padding
        #],
        #'Mr':[0,0,0,0],     #margin 
        #'Br':[0,0,0,0],     #border
        #'Pd':[0,0,0,0],     #padding
        #'Rd':[0,0,0,0],     #round
        #'bg':'', 
        #'bg':'', 
    }
    tokens      = tnz(s)
    si          = 0
    bId         = None 
    fileExt     = None
    for i,token in enumerate(tokens+[[' ','']]):
        
        if token[0] == ' ' and si < len(tokens): 

            token_type, _value = tokens[si] 
            FToken = None
            value  = ''.join([_[1] for _ in tokens[si:i]])
            #print_arr('289:', tokens[si:i])
            if len(value) == 0: continue
            
            if  token_type in 'dn' : 
                FToken = tokens[si:i]
                _    , _value = tokens[si]
                _type, suffix = tokens[i-1]

                #print('149:', _type, _value, token_type ) 
                if _type in 'dn':                         
                    if 'w'in props: props['h'] = float(_value)
                    else          : props['w'] = float(_value)
                if suffix == 'x': props['x'] = float(_value)
                if suffix == 'y': props['y'] = float(_value)
                if suffix == 'w': props['w'] = float(_value)
                if suffix == 'h': props['h'] = float(_value)
                
                #relative to aId 
            
            elif token_type == '!' : props['bId']   = value; bId = value; bId_tokens = tokens[si:i];  
            elif token_type == '/' : props['path']  = value; fileExt = tokens[i-1][1]
            elif token_type == '#' : props['id']    = value
            elif token_type == '-' : props['txt_flag']= value 
            elif token_type == '&' : props['align'] = value 
            elif token_type == '.' : props['class'].append(value)
            elif value[0] in 'MBP' : k,v = parse_box(value); props[k] = v; 
            elif value[0] in 'uzmxy' : 
                props['ly'] = value; 
                if   value[0] in 'uzm': props['ly_type'] = value[0]
                elif value[0] in 'xy' : props['ly_type'] = 'xy'

            si =i+1

            if FToken:
                tmp     = [0,0,0,0]  # [abs, rel aId, prop]
                preType = ''
                Fi      = -1
                for token in  tokens: 
                    _type, value = token
                    if   _type in 'nd': tmp[0], tmp[1] = float(value), float(value)
                    elif preType in 'nd' and _type == 'w': Fi     = FDIR.get(value,-1)
                    elif preType == '!'  and _type == 'w': tmp[2] = '!'+value
                    elif preType == '.'  and _type == 'w': tmp[3] = FDIR.get(value, Fi)
                    preType = _type
                if Fi>-1: props['F'][Fi*4:Fi*4+4] = tmp

    # get elm_type by fileExt 
    if fileExt:
        extType = extDict.get(fileExt, '')
        if(extType == 'img'): props.update({ 'type': 'img', 'data': props['path']})


    #get ly not in y-str base upon bId 
    if 'ly' not in props :  
        #   !m0i5j      //matric 
        #   !R0C0       //cell row,col 
        #   !z50        //z-point
        #   !u80        //u-area 
        #   !p          //p parent 
        props['ly'] = bId[1:]

    #   y_prop add to yli 
    for k,v in props.items():  yli[k] = v 

    #print('250:', bId_tokens)
    #print_kv('325:', props)
    #print('351:',props['F'][2*4:2*4+4])

    return bId


def parse_yli(line, z={}): 
    yli = {'line': line}
    _   = None 
    for token in line.split(';'):
        #print('127:', token)          
        if   ':' in token: k,v   = token.split(':', 1)
        elif _ == None:
            #print('126:', token)  
            k,v,_  = '_',  token, token
            bId    = parse_ystr(_, yli)
            z[bId] = yli 
        else               : continue
        #print('40:', line, '\n', k,v )
        yli[k.strip()] = v.strip()

    (z.setdefault('/zls', [])).append(yli)
    return yli 

    
def zparse(s):
    yls = []
    obj = {}
    zls = [] 
    line = [] 
    for line in s.split('\n'):
        line = line.replace('\t', ' ')
        line = (line.split(' //'))[0].strip()
        if len(line)==0: continue


        if line.startswith('$'):
            if ':' not in line: continue 
            k,v = line.split(':', 1)
            z[k.strip()] = v.strip()

        #   zls 
        elif line ==  '/zls':zls = []; z[line]= zls
        elif line ==  '/yls' :yls = []; z[line]= yls
        #elif line.strartswith('/'):line=[]; z[line]= line 
        #   zli 
        elif line.startswith('-'):
            zli = [token.strip() for token in line.split(';')]
            zls.append(zli)



        #yls
        elif line ==  '/yls':
            yls = [] 
            z[line]= yls

        #yli
        elif line.startswith('!'): 
            yli = parse_yli(line)
            yls.append(yli)
            

        #elif line.startswith('/'):

        #elif 
    return z




def test():

    parse_ystr('!A z7+45!B -4w!A.w')
    #parse_ly('x5y12!B')
    #parse_ly('x5y12!B')
    #parse_ystr('!WC -25x!A 26y 50w 70h')

    txt = '!m!1j0i ; txt:0i0j;'
    #parse_ystr(txt)
    txt = '!A  u80   40; txt:!A;'
    txt ='u80'
    #print(parse_ly(txt))
    

    txt = '!Z 	z00!p &80 M+0.5h R0.5 B2	./wallpaper.jpg; txt:!Z;'
    #tokens = parse_ly(txt)

    #print_kv('398:', tokens)

    #parse_ly('u40[24:12]!p')
    

    #parse_ly('u40[24:12]!p')
    #parse_ly('u40[24i12j]')

    #parse_ly('u40N2!A')

    #parse_ly('u40N2[24:-12,123]&45+7x!A')
    #parse_uz('m3x3[5i6j]&45+7x!A')


    #parse_ystr('!A-5i6j')
    #parse_box('P0.5ht7b')
    
    txt = 'u40&00+7!A.Pd'       
    txt = 'u40+7!A.Pd'       # in this offset dont work
    #parse_ly(txt)

    #test-tnz()
    txt = '!A-A m3x3[2:-5.5,-5]'
    #tokens = tnz(txt)

    #test-parse_ystr()
    txt = '!A-A u00-25.6,16.5z5!P.Pd 12w 123h #4564 -utf .class 192-.+168.12F 20-12-2025 24:12:12 ./path &44 M1h'    
    #txt = '!A u40+25 25.7h 13  #154 &12 -flag ./path .class'
    #parse_ystr1(txt)

    #   test-parse()
    #with open('./swm.zy', 'r') as file:
    #    txt = file.read()
    #    zparse(txt)
    #    print(z)
    #    for k,v in z.items():
    #        print(f'271: {k:12}:')  # {v}')
    #    for _ in z.get('/yls',{}):
    #        print(_)        
    #    #print('275:', z.get('/yls',{}))
    #    print('\n'*4, '-'*32 )
    #    for k,v in (z.get('!Z',{})).items():
    #        print(f'271: {k:12}: {v}')
    #        #print(k,v)        


#test()
#test_zy()