#this use only by _main_ 
import os 
import sys


#############################################################
#   tnz                                                     #
#############################################################
#   tnz(str)        
#   tnz_cstr(str)
#   tnz_str(str)           r=[tokenType,tokenValue]
#   tnz_frame(tokrns)
#   tnz_print(tnz_str)     //print
#   tnz_fprint(filePath)
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#   
#############################################################




color_list = [
    '#dcdcaa',  
    '#559cd6', 
    '#b5cea8',    
    '#16a085',    
    '#c586c0',  
    '#d7ba7d',    
    '#ce9178',    
    '#ffffff',    
    '#cccccc',

    '#6a9955',    
    '#899b7f',    
    '#9cdcfe',  
    '#5190c5',  
    '#4ec9b0',  
]

token_color = {
    # key: #fff -flag
    # flag ( b bold | i italic | u underline | s spellcheck)
    # flag ( U upper| L lower | T title )
    'default' : '#cccccc',  #default 

    #col color 
    'C0':'#dcdcaa',  
    'C1':'#559cd6', 
    'C2':'#b5cea8',    
    'C3':'#16a085',    
    'C4':'#c586c0',  
    'C5':'#d7ba7d',    
    'C6':'#ce9178',    
    'C7':'#ffffff',    
    'C8':'#cccccc',
    'C9':'#6a9955',    

    'd' : '#b5cea8',    #digit
    'n' : '#b5cea8',    #number
    'w' : '#9cdcfe',    #-s    #word 
    's' : '#ce9178',    #string
    '/'   : '#dcdcaa',
    'path': '#dcdcaa',  # path / .~/ ../ ../
    '_' : '       ',    #space
    'n' : '#899b7f',    #newline

    'C' : '#6a9955',    #comment 
    'e' : '#d7ba7d',    #escape_code
    'U' : '#16a085',    #upper case
    '>' : '#16a085',    #cmd 

    #   !
    '~' : '#ffffff',    #other char
    '&' : '#c586c0',    #attr 
    '@' : '#d7ba7d',    #-b   @tpp
    '#' : '#899b7f',    #-b   #id     #cccccc
    '$' : '#4fc1ff',  #'#4ed3d5',    #   $var 
    #   %
    '.' : '#d7ba7d',  #\\\'#4ec9b0',    #   .classname .fileExt .domain obj.method.method2
    '-'   : '#559cd6',

    'tag' : '#559cd6',  #tag
    'attr' : "#FFA621",  #attr



    #pogroming 
    'v'  : '#9cdcfe',  #variable
    'K'  : '#5190c5',  #key
    'F'  : '#dcdcaa',  #function  

    #keyword
    'w'  : '#cccccc',
    'w0' : '#c586c0',  #if|elif|import     color-
    'w1' : '#559cd6',  #def                color-blue
    'w2' : '#4ec9b0',  #type|str|list etc  color-green
    'w9' : '#4ec9b0',  #type|str|list etc  color-green


        
    #combination of token 
    'l'   : '#559cd6', # link://            
    'url' : '#559cd6', # url://

    'str-type': '#559cd6',  # r'regex' | f'format' | b16|b32|b64'baseEncode' 
    
    #hex 
    #octal 
    #binary 
    'cmd' : '#00bf00',
}

configType = {
    'bg':'#1f1f1f',

    'title':{ 
        # #hasgtag
        # @ 
        # num
        # url 
        # email
        # word 
        # ~  
        'allow':'wdf@#--',
        'w_flag': '0aA_-',
    },
    '.tnz':{ 
        # #hasgtag
        # @ 
        # num
        # url 
        # email
        # word 
        # ~  
        'allow':'wdnl@#$/-:;.k,',  #: use for key 
        'w_flag': '0aA_-',
        'types':{
            #token_value: end toke_type 
            '//*': ['\n', 'C'],
        },
    },
    '.des':{ 
        # #hasgtag
        # @ 
        # num
        # url 
        # email
        # word 
        # ~  
        'allow':'wdnl@#$/-;.k',
        'w_flag': '0aA_-',
        'types':{
            #token_value: end toke_type 
            '//': ['\n', 'C'],
        },
    },
    'url':{ 
        'allow':',wd@#!-',
        'w_flag': '0aA_-',
    },
    '.css':{ 
        'allow':'Fwd@#$%-k',
        'w_flag': '0aA_-',
    },
    '.csv':{ 'allow':',wd------'},
    '.html':{

        'w_flag': '0aA_-',
        'keywords':{},
    },
    '.py':{
        'allow' :'-wdfaAb+!^Fk',

        'w_flag': '0aA_',
        'w9':['from', 'import'],
        'keywords':{
            'if'     :'w0',
            'elif'   :'w0',
            'else'   :'w0',
            'break'  :'w0',
            'continue':'w0',
            'as'    :'w0',
            'return':'w0', 
            'try'   :'w0',
            'except':'w0', 
            'for'   :'w0',
            'while' :'w0',
            'import':'w0',
            'from'  :'w0',



            'def'   : 'w1',
            'async' : 'w1',
            'in'    : 'w1',
            'not'   : 'w1',
            'with'  : 'w1',
            'None'  : 'w1',
            'global': 'w1',
            'and'   :'w1',
            'or'    :'w1',
            
            'type'  : 'w2',
            'zip'   : 'w2',
            'list'  : 'w2',
            'dict'  : 'w2',
            'str'   : 'w2',
            'int'   : 'w2',
            'float' : 'w2',
            'Exception':'w2',
            'rise':'v2,'
        },
        'types':{
            #token_value: end, toke_type 
            '#': ['\n', 'C']
        }
    }, 
    '.js':{
        'allow' :'-wdaAb+!^fp.F',
        'w_flag': '0aA_',
        'keywords':{
            'as'     :'w0',
            'raise'  :'w0',
            'from'   :'w0',
            'import' :'w0',
            'export' :'w0',
            'return' :'w0',
            'break'  :'w0',
            'if'     :'w0',
            'else'   :'w0',
            'function'    :'w0',
            'throw':'w0',
            'for':'w0',

            'const' :'w1',
            'class' :'w1',
            'this'  :'w1',
            'new'   :'w1',
            'static':'w1',
            'let'   :'w1',
            'new'   :'w1',
            'null'  :'w1',
            'false' :'w1',
            'true'  :'w1',
            'construction':'w1',
            'instanceof':'w1',
            'typeof':'w1',
            'of':'w1',

            'FormData':'w2',
            'Array':'w2', 
            'Object':'w2',
            'Error':'w2',
            'JSON':'w2',




        },
        'types':{
            #token_value: end toke_type 
            '/*': ['\n', 'C'],
            '//': ['\n', 'C'],
        },
    },
    '.c':{
        'allow' :'-wdfp#',
        'w_flag': '0aA_',
        'keywords':{
            'export' :'w0',
            'return' :'w0',

            'struct' :'w1',
            'void'   :'w1',
            'int'    :'w1',
            'const'  :'w1',
            'class'  :'w1',
            'this'   :'w1',
            'new'    :'w1',
            'static' :'w1',
            'let'    :'w1',
            'new'    :'w1',
            'null'   :'w1',
            'false'  :'w1',
            'true'   :'w1',
            'construction':'w1',

        },
        'types':{
            #token_value: end toke_type 
            '//': ['\n', 'C']
        },
    },
}

    #background


def print_arr(ln='11:', arr=[], end='\n' ):
    print('323:', '-'*48, end=end )
    if type(arr) != list: return 
    for elm in arr:
        print(f'{ln} {elm}', end=end)
    print('323:', '-'*48, end=end )
    
def print_kv(ln='11:', obj=[], end='\n' ):
    print('323:', '-'*48, end=end )
    if type(obj) != dict: return 
    for k,v in obj.items():
        print(f'{ln} {k:12}: {v}', end=end)
    print('323:', '-'*48, end=end )

def hex_to_rgb(hex_color):
    def is_valid_hex_color(hex_color):
        # Remove the hash symbol if it exists
        hex_color = hex_color.lstrip('#')
        
        # Check the length of the hex color
        if len(hex_color) not in (3, 6):
            return False
        
        # Check if all characters are valid hexadecimal digits
        valid_chars = "0123456789abcdefABCDEF"
        for char in hex_color:
            if char not in valid_chars:
                return False
                
        return True
    
    if not is_valid_hex_color(hex_color):
        hex_color = token_color.get('defult', '#c6c6c6')
        
    
    # Remove the hash symbol if it exists
    hex_color = hex_color.lstrip('#')
    
    # If it's a 3-digit hex code, convert it to 6-digit
    if len(hex_color) == 3:
        hex_color = ''.join([c * 2 for c in hex_color])
    
    # Convert the hex values to RGB
    r = int(hex_color[0:2], 16)
    g = int(hex_color[2:4], 16)
    b = int(hex_color[4:6], 16)
    
    return r, g, b


############################################################
#   tnz                                                    #
############################################################
#priary function use to tnz string 
def tnz(s:str, w='',ln=0):
    """
    Docstring for tnz
    
    :param s: Description

    w_config  
        alpha   aA
        alpnum  0aA
        word    0aA_
        alpha   0aA_-
            
    tnz_type 
        primary_type
        d   0       digit  
        a   aA      alpha   
        s   ''      string 
                    space 
                    newline

        w   0aA_    word            
        e   0aA_-   extend word
        n   -+d.d   num 
        p   ./ ~/ ../   path

    token_config
        ./ ~/   p       path   
        mk_     w       word        aA_ 
        M01     w       word        0aA
        m0-R_   w       word        0aA_-
        mk-5    w-n     word-num 
        5i64    d-w-d 
        567     d       digit 
        +5      n       num 
        -5.5    d

    """

    tokens    = []
    preType = ''
    si       = 0
    s        = '\n'+s+'\n'
    endChar  = None
    
    #jump to lineNum 
    #if ln:        
    #    for i, c in enumerate(s):
    #        if c == '\n': si+=i 
    #        if si == ln  : break 

    lns = []        #line num 
    
    for i in range(si, len(s)):
        c = s[i]
        
        if endChar:
            if c == endChar: endChar=None
            continue
        
        elif c >= '0' and c <= '9': tokenType = 'd'
        elif c >= 'a' and c <= 'z': tokenType = 'w'
        elif c >= 'A' and c <= 'Z': tokenType = 'w'
        elif c == '_'             : tokenType = 'w'     #alpha
        elif c in ' \t'           : tokenType = ' '     #space
        elif c in '\n'            : tokenType = '\n'; lns.append(len(tokens))  #newline 
        elif c in '\'"`'          : tokenType = 's' ; endChar=c     #newline 
        else                      : tokenType = c       #misc 
        
        #sperator ,; store each char 
        if  tokenType in ',;' and preType == tokenType :
            tokens.append([c, c]); si=i 
        
        elif preType != tokenType and preType != '':

            # type-num  +-d.d
            if preType in '+-' and tokenType == 'd' : preType  ='n'; tokenType='n'; continue
            if preType == 'd'  and tokenType == '.' : preType  ='n'; tokenType='n';  continue
            if preType == 'n'  and tokenType in '.d': tokenType='n'; continue
            
            # type-path  ~/  ./  ../
            if preType in '.~' and tokenType == '/' : preType='/'; tokenType='/';  continue
            

            #   type-word   aA0_-
            #if preType == 'w' and tokenType == '_':  continue            
            if preType == 'w' and tokenType == '-' and not s[i+1].isdigit()     : continue
            if preType == 'w' and tokenType == 'd' and tokens[-1][0] not in 'nd': continue
            #if preType == 'w' and tokenType == 'd' :  continue
            
            token_value = s[si:i]
            tokens.append([preType, token_value ])
            si = i
            if preType == '#' and tokenType == 'd': tokenType = 'w';             
        
        preType = tokenType
        
    return tokens[1:]


def tnz_cstr(s:str):
    #cmd str to tokens 
    tokens  = tnz(s)+[[' ', ' ']]
    si      = 0
    r = [] 
    #print_arr('433:', tokens)

    types = []
    value = []
    
    for i in range(0, len(tokens)):
        

        #this use in query 
        if i != 0 and tokens[i][0] in '=' : 
            value  = ''.join([_[1] for _ in tokens[si:i]]) 
            r.append([_type, value])    
            #_type, _value = tokens[i] 
            #r.append([_type, value])
            si=i

            #if _type  == '/' and tokens[i-2] == '.' : r.append(['.', tokens[i-1]])

        elif tokens[i][0] == ' ' : 
            _type, _value = tokens[si] 
            
            value  = ''.join([_[1] for _ in tokens[si:i]]) 
            #print('446:', si,i, _type,_value,  value)
            if si == 0 and _type == 'w': _type = '>' 
            #elif _type  == '-' : _type = '-'
            #elif _value == '--': _type = '--'
            #elif _type  == '/' : _type = '/'
            #elif _type  == '&' : _type = '&'
            #elif _type  == '=' : _type = '='
            #elif _type  == 's' : _type = 's'
            

            if _type != ' ':
                 r.append([_type, value])
            #if _type  == '/' and tokens[i-2] == '.' : r.append(['.', tokens[i-1]])


            r.append([' ', tokens[i][1]])
            si=i+1
    

    #print_arr('453:', r,'\r\n')
    return r[:-1]


#secondry function to tnz further classfication 
def tnz_str(s:str, kv={}):

    """
    misc
        logic   airth   
        ==      +       >>  left-shift   
        !=      -       <<  right-shift
        <=      /       &&  and
        >=      *       ||  or
        >       ++      &   bitwise-and
        <       --      |   bitwise-or
        !       %       ^   bitwise-xor
    num_suffix 
        size    
        KB    K killo     12y years 
        MB    M million    1m month  
        GB    B billion    3w week  
        TB    T triloon   24d day  

    """

    
    tokens  = tnz(s)
    ext     = kv.get('ext', '')
    config  = configType.get(ext,{})
    kw_dict = config.get('keywords',{})  #keyword_dict 
    mw      = config.get('w9',[])
    w9 = []
    wd  = {}    #{word: wtype}  
    preType, preValue = '', ''
    #print_arr('433:', tokens)
    """
    wtype 
        //prefix 
        @w   import 
        $w   var 
        $0  args
        w   word|var 
        dw    num_suffic 
        .w   class|prop|method
        !w   bId 
        <w   attr 
        -w   flag 
        //suffix 
        w=   assign 
        w()  fun|tupless
        w{}  obj|block
        w[]  arr
    """
    

    CF  = 0
    for i in range(0, len(tokens)):
        _type, _value  = tokens[i]
        
        if _type == 'w' : 
            #print('496:', preType, _type)
            if   preType  == 'd': tokens[i][0] = '_n'   #  9w  num_suffix
            if   preType  == 'n': tokens[i][0] = '_n'   #  +0n num_suffix
            elif preType  == '/': tokens[i][0] = '/'    #  /path
            elif preValue == '!': tokens[i][0] = '!'    #  !bId
            elif preValue == '@': tokens[i][0] = '@'    #  @tpp 
            elif preValue == '#': tokens[i][0] = '#'    #  #hash 
            elif preValue == '$': tokens[i][0] = '$'    #  $var 
            elif preValue == '%': tokens[i][0] = '%'    #  %dtype 
            elif preValue == '&': tokens[i][0] = '&'    #  &args
            elif preValue == '.': tokens[i][0] = '.'    #  .class
            elif preValue == '-': tokens[i][0] = '-'    #  -flag 
            elif preValue == '<': tokens[i][0] = 'attr' #  <attr
            
            # set _type 'w*'
            if _value in kw_dict : tokens[i][0] = kw_dict[_value] #keyword 
            if preValue in mw:  w9.append(_value)       #
            if _value in w9  : tokens[i][0] = 'w9'      #import 

            wd[_value] = tokens[i][0] 


        #elif preType + _type ==  '\n/' : 
        #elif preType + _type ==  '\n$' : 
        #elif preType + _type ==  '\n:' : 
        elif _value == '//'        : tokens[i-1][0] = 'C'   #inline comment 
        #list-arr
        elif preType +_type == '\n-': tokens[i-1][0] = 'C'+str(CF); CF+=1
        elif 0<CF and _type == ';'  : tokens[i-1][0] = 'C'+str(CF); CF+=1
        
        #list-obj
        elif preType+_type == '\n:'       : tokens[i-1][0] = 'K'; CF =1  
        elif preType+_type == 'w:' and CF : tokens[i-1][0] = 'K'
        elif         _type == '\n' : CF=0 

        elif preType+_type == 'w(' : tokens[i-1][0] = 'F'    #fun 

        if _type != ' ':
            preType, preValue = _type, _value

    #print_arr('514:', tokens)
    
    return tokens


#############################################################
#   tnz print                                               #
#############################################################
#create fram so easy to use render 
def tnz_frame(tokens:list, kv={},PF=0):
    #   colorCode[i] = '#ffffffff'  max range 256 
    #   frame[<elm>]
    #   <elm>   //4 byte each use one byte 
    #       - bg
    #       - fg      #rgba 
    #       - flag
    #       - c
    #   <flag> 
    #        b   bold 
    #        u   underline 
    #        i   italic
    #        I   inverse  
    #        U   upper 
    #        L   lower 
    #   <elm size 1byte 
    #   <config>
    #       L   show lineNum 
    #       _   show spaceChar 
    #       I   inverse
    #       
    #   PF ==  0:    return frame
    #   PF ==  1:    print()
    #   PF == -1:    retuen print_str 

        
    

    ln     = kv.get('ln', 0)            #   start line_num
    la     = kv.get('la', 0)            #   active line_num 
    config = kv.get('config', 'lI')     #   lineNum lI_
    f      = kv.get('f', [])            #   f[x y w h] 
    ext    = kv.get('ext','defult')     #   lang ext
    LF     = kv.get('LF', '\n')         #   lineFeed 

    #####################################################
    
    bracket= []
    frame  = [] 
    colNum = None
    flag   = ''
    bg,fg  = kv.get('bg', '#000000'),''

    for i,token in enumerate([['\n', '\n']] + tokens):
        _type, _value  = token
        

        #print('890:', _type, _value)
        #show space char 
        if  _type == '0':  continue

        #print space_char 
        if _type == ' ' and '_' in config: 
            if _value[0] == ' ' : _value = '•'* len(_value)
            if _value[0] == '\t': _value = '>'* len(_value)
            fg = '#7f7f7f'

        #   line_num 
        elif _type == '\n':  
            fg, s = '#7f7f7f', ''
            flag = ''
            if _type == '\n': colNum = None  

            #show lineNum
            for c in  _value:
                ln+=1
                s+='\n'
                #active line heighlight 
                #if ln==la        : print_tokens.append(f'\033[7m') 
                if 'l' in config: s+= f'{ln:3} ' 
            for c in s: 
                
                if c == '\n': c     = LF 
                else        : _type = 'ln'
                if ln == la : flag  = 'I'
                frame.append([bg,fg,flag,c, _type])
            continue
        
        # color bracket   
        elif _type in '[{()}]':   
            for c in _value:
                if c in '({[': 
                    bracket.append(c)
                    fg = color_list[len(bracket)]
                if c in ']})' and bracket:
                    fg = color_list[len(bracket)]
                    bracket.pop()
                
                frame.append([bg,fg,flag,c,_type])
            continue 

        #elif _type == 'w': # and 'v' in  colorDict:
            #fg =   token_color.get('','#ffffff' )
        #elif colNum              : fg = token_color[colNum]
        elif colNum              : fg = token_color[colNum]
        elif _type == 'w'        : fg = token_color['v']
        elif _type in token_color: fg = token_color[_type]
        else                     : fg = token_color['~']

        
        if _type[0] == 'C'  : colNum = _type
        
            

        for c in _value:
            frame.append([bg,fg,flag,c, _type])

    #print flag true than prit 
    if PF: 
        print_tokens = []
        #frame[0] newLine char 
        for elm in frame[1:]:
            bg,fg,flag,c,_type = elm 
            r,g,b        = hex_to_rgb(fg)
            FEC = '' #flag escape code 
            if 'I' in flag: FEC= '7;'
            print_tokens.append(f'\033[{FEC}38;2;{r};{g};{b}m{c}\033[0m')
        r = ''.join(print_tokens)
        if PF ==  1: print(r)       #print frame 
        if PF == -1: return r       #print frame str 

        #print_arr('750:', frame)
    else:
        return frame


#tokenz string print 
def tnz_print(txt,kv={'config':'l_', 'LF': '\r\n'}):
    tokens  = tnz_str(txt)
    tnz_frame(tokens, kv, 1)


#file print 
def tnz_fprint(filePath,kv={'config':'l_', 'LF': '\r\n'}):
    if not os.path.isfile(filePath):
        print(f'\r805: [Error] path not exit "{filePath}"')
        return ''
    with open(filePath, 'r') as file:
        txt     = file.read()    
        kv      = {'config':'l_', 'LF': '\r\n'}
        tokens  = tnz_str(txt)
        tnz_frame(tokens, kv, 1)
    return '' 


#############################################################
#   zparse                                                  #
#############################################################
def zparse(s, PF=0):

    def getStr(tokens):
        return ('' .join([_[1] for _ in tokens])).strip()
    
    obj,arr = {},[] 
    zli,yli = [],{}

    zls,yls = [],[]
    #r_zls,r_yls = zls, yls 
    zobj    = {'/zls':zls, '/yls':yls}
    z       = zobj
    si      = 1

    CF,key  = 'zpath', ''    
    preType = ''
    #print('840:',s, CF)
    tokens  = tnz(s)+[['\n', '\n'], [' ', ' ']]

    for i in range(1, len(tokens)):
        _type, _value = tokens[i] 
        #print('837:', i, hex(ord(_type)),  _value)
        #line = line.replace('\t', ' ')
        #line = (line.split(' //'))[0].strip()
        if      _type == ' '      : continue
        elif CF+_type == 'zpath\n':  z['zpath']= getStr(tokens[si:i])
        
        
        #
        elif CF+_type== '$:'        : key     = getStr(tokens[si:i]);         #obj
        elif CF+_type== '$\n'and key: zobj[key]  = getStr(tokens[si:i])
        
        elif CF+_type== '.{'       : key      = getStr(tokens[si:i]);  obj={}; zobj[key]=obj 
        elif CF+_type=='{:'        : key      = getStr(tokens[si:i]);          #obj
        elif CF+_type=='{;' and key: obj[key] = getStr(tokens[si:i]);   #yli

        elif CF+_type=='!:'         : key      = getStr(tokens[si:i]);         #yli
        elif CF+_type=='!;'  and key: yli[key] = getStr(tokens[si:i]);  #yli
        elif CF+_type=='!\n' and key: yli[key] = getStr(tokens[si:i]);  #yli

        elif CF+_type=='::'         : key      = getStr(tokens[si:i]);         #zli-obj
        elif CF+_type==':;'  and key: zli[key] = getStr(tokens[si:i]);   #yli
        elif CF+_type==':\n' and key: zli[key] = getStr(tokens[si:i]);   #yli

        
        elif CF+_type=='-;' and preType+_type != '\n;': zli.append(getStr(tokens[si:i])); si=i+1  
        elif CF+_type=='-\n': zli.append(getStr(tokens[si:i])); si=i+1  #yli

        # create zobj 
        elif CF+_type=='/\n': 
            key     = getStr(tokens[si:i]); 
            if key in ['/zls' , 'yls']: 
                zobj     = z 
                zls, yls = z.get('/zls', []), z.get('/yls', [])

            else:
                zls,yls = [],[]
                zobj    = {'/zls':zls, '/yls':yls}; 
                z[key]    = zobj
            
        #set C_flag
        if           _type  ==   '{': CF='{'; si=i+1; key='' ;  #   {obj}
        elif preType+_value == '\n/': CF='/'; si=i  ; key='' ;  #   zobj 
        elif preType+_type  == '\n.': CF='.'; si=i  ; key='' ;  #   .class 
        elif preType+_type  == '\n$': CF='$'; si=i  ; key='' ;  #   $var
        elif preType+_type  == '\n!': CF='!'; si=i  ; key='_'; yli= {}; yls.append(yli)
        elif preType+_type  == '\n:': CF=':'; si=i+1; key='_'; zli= {}; zls.append(zli)
        elif preType+_type  == '\n-': CF='-'; si=i+1;          zli= []; zls.append(zli)
        elif preType == '\n':
            if CF    != '{' and _type != ';' : CF=''; 
            if _type == ';': si =i+1
            
        #insert bId 
        if CF+_type == '!;' and key == '_': 
            bId = '!'+tokens[si+1][1]
            zobj[bId] = zli 
            

        if _type in '{\n:;': si=i+1; 
        if _type == '\n;'  : key=''
        preType = _type 
        
    if PF:
        print('869:','-'*32)
        for k,v in z.items():
            print(f'869: {k:12}: {v}')

    return z 


def tnzm(s, txt=''):

    kv      = {} #{'path, flag, fn, ext}
    path    = '' 
    fn      = ''  #function name 
    r,emsg  = None, ''
    tokens  = tnz_cstr(s)

    for token in tokens:
        _type, _value = token 
        if   _type == '/' : kv['path'] = _value; path = _value
        elif _type == '-' : kv['flag'] = _value
        elif _type == '.' : kv['ext']  = _value
        elif _type == 's' : kv['str']  = _value
        elif _value.startswith('fn:'): kv['fn'] = _value; fn= _value

    #get which str you want tnz 
    if path:
        if os.path.isfile(path):
            with open(path, 'r') as file:
                txt = file.read()    
        else:
            emsg = f'805: [Error] path not exit "{path}"'
            
    else:
        txt = kv.get('str', '')[1:-1]

    #print debug data 
    if 0: 
        print_arr('862:', tokens)
        for k,v in kv.items():
            print(f'864:{k:12}: {v}')
        print('867:', '-'*32)
        print('866: cmd_str', s)
        print('867: path', path, )
        #print('868: txt\n', txt)
        print('869:', '-'*32)

    ####################################################
    if emsg:
        return r, emsg

    elif fn == 'fn:tnz_cstr':
        tokens = tnz_cstr(txt)
        print('838:', txt)
        print_arr('838:', tokens)


    elif fn == 'fn:tnz_fprint':
        kv['config'] = 'l_'
        tokens = tnz_str(txt)
        tnz_frame(tokens, kv, 1)
        #print_arr('838:', tokens)

    elif fn == 'fn:zparse':
        print('922:')
        r = zparse(txt)
        if not r: 
            emsg = f'800: [Error] zparse() has issue'
        
    
    elif fn == 'fn:tnz_frame':
        tokens  = tnz_str(txt)
        ftokens = tnz_frame(tokens)
        print('838:', txt)
        print_arr('838:', tokens)
        print_arr('838:', ftokens)
        r = ftokens
    
    else:
        emsg = f'805: [Error] fn not exit "{fn}"' 

    
    return r, emsg 


def test():
    txt = 'input ./path ../path1 "OPPO A52"  ~/path2 -flag'
    #parse_cstr(txt)

    txt="""def print_arr(ln='11:', arr=[] ):
    print('604:', '-'*32 )
    if type(arr) != list: return 
    for elm in arr:
        print(f'{ln} {elm}')
    """            
    #r = tnz_print(txt, {'ext':'.py', 'config':'\n_'})
    #txt = 'input [()]./path ../path1 "OPPO A52"  ~/path2 -flag'

    #config = {'ext':'.py', 'config':'\n_'}
    #tokens = tnz_str(txt,config)
    #tnz_frame(tokens, config)

    tokens = tnz('http://zshlo.com:7856/:rx/r/resp/lib-js/tnz.js')
    print_arr('959:', tokens)
test()



if __name__ == "__main__":

    s      = ' '.join(sys.argv)
    tnzm(s)
    