#!/usr/bin/python
##This Python file uses the following encoding: utf-8
##
## (C) 2008-2015 Muthiah Annamalai,
## Licensed under GPL Version 3
## 
## Module has elements of PARSE-TREE  AST 
## 
import codecs
import functools
import sys

from .tamil_scanner import tamilToken, Token
from .transform import TransformVisitor

PYTHON3 = (sys.version[0] == '3')
if PYTHON3:
    str = str

try:
    import graphviz as gv

    graph = functools.partial(gv.Graph, format='svg')
    digraph = functools.partial(gv.Digraph, format='svg')
except ImportError as ie:
    pass

import xml.sax.saxutils

class Tag(object):
    def __init__(self,fileobj,name,tab=0,attrs={}):
        object.__init__(self)
        self.tagname = name
        self.attrs = attrs
        self.fileobj = fileobj
        self.tabstr = u" "*tab
        if len(attrs) > 0:
            pfx = u" "
        else:
            pfx = u""
        serialized_attrs = pfx+u" ".join( [ u"%s=\"%s\" "%(str(k),str(v)) for k,v in attrs.items()])
        self.fileobj.write(u"%s<%s%s>\n"%(self.tabstr,self.tagname,serialized_attrs))
    
    def disp(self,content):
        self.fileobj.write(u"%s\n"%content)
    
    def __del__(self):
        self.fileobj.write(u"%s</%s>\n"%(self.tabstr,self.tagname))
    
class SerializerXML(TransformVisitor):
    def __init__(self,interpreter,debug=False,filename=None):
        """ base class to write transform methods """
        self.tab = 0
        self.filename = filename
        self.file = sys.stdout
        if filename:
           self.file = codecs.open(filename,"w","UTF-8")
        self.file.write(u"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
        tobj = Tag(self.file,u"tamil",self.tab)
        self.incr()
        TransformVisitor.__init__(self,interpreter,debug)
        self.decr()
    
    def __del__(self):
        if self.filename:
            self.file.close()
        
    def disp_basic(self,tagname,contents):
        escaped_contents =  xml.sax.saxutils.escape(u"%s"%contents)
        self.file.write(u"%s<%s>%s</%s>\n"%(self.tabstr(),tagname,escaped_contents,tagname))
    
    def tabstr(self):
        return u" "*self.tab
        
    def incr(self):
        self.tab += 1
    
    def decr(self):
        self.tab -= 1

    def update_line(self,obj):
        pass
        return
        
    def visit_identifier(self, IDobj):  
        self.disp_basic( u"ID",str(IDobj.id))
        return
    
    def visit_string(self, string):
        self.disp_basic( u"STR",string)
        return
    
    def visit_number(self, num):
        self.disp_basic( u"NUM",num)
        return
    
    def visit_expr_call(self,expr_call):
        tobj = Tag(self.file,name=u"EXPRCALL",tab=self.tab)
        self.incr()

        tobj_id = Tag(self.file,name=u"FUNCID",tab=self.tab)
        self.incr()
        expr_call.func_id.visit(self)
        del tobj_id
        self.decr()
        
        self.incr()
        tobj_args = Tag(self.file,name=u"FUNCARGS",tab=self.tab)
        expr_call.arglist.visit(self)
        del tobj_args
        self.decr()
        
        self.decr()
        return
    
    def visit_expr_list(self, expr_list):
        tobj = Tag(self.file,name=u"EXPRLIST",tab=self.tab)
        self.incr()
        for pos,exp_itr in enumerate(expr_list.exprs):
            exp_itr.visit( self )
        self.decr()
        return
    
    def visit_stmt_list(self,stmt_list):
        tobj = Tag(self.file,name=u"STMTLIST",tab=self.tab)
        self.incr()
        for stmt in stmt_list.List:
            stmt.visit(self)
        self.decr()
        return
    
    def visit_stmt( self, stmt):
        tobj = Tag(self.file,name=u"STMT",tab=self.tab)
        ## is this a recipe for getting stuck in a loop?
        stmt.visit(self)
        return
    
    def visit_expr(self, expr):
        escaped_tok_kind = xml.sax.saxutils.escape( Token.get_name(expr.binop.kind) )
        tobj = Tag(self.file,name=u"EXPR",tab=self.tab,attrs={u"binop":escaped_tok_kind})
        self.incr()
        
        tobj_term = Tag(self.file,name=u"TERM",tab=self.tab)
        self.incr()
        expr.term.visit(self)
        del tobj_term
        self.decr()
        
        toktype = tamilToken.token_types[expr.binop.kind]
        expr.next_expr.visit(self)
        self.decr()
        return
    
    def visit_return_stmt(self, ret_stmt):
        tobj = Tag(self.file,name=u"RETURN",tab=self.tab)
        keyword = u"பின்கொடு"
        # return may have optional argument
        if hasattr(ret_stmt.rvalue,'visit'):
            ret_stmt.rvalue.visit(self)
        return
    
    def visit_break_stmt(self, break_stmt ):
        tobj = Tag(self.file,name=u"BREAK",tab=self.tab)
        keyword = u"நிறுத்து" #tamilToken.Keywords["break"]
        return
    
    def visit_continue_stmt(self, cont_stmt):
        tobj = Tag(self.file,name=u"CONTINUE",tab=self.tab)
        keyword = u"தொடர்" #tamilToken.Keywords["continue"]
        return
    
    def visit_else_stmt(self,else_stmt):
        tobj = Tag(self.file,name=u"ELSE",tab=self.tab)
        self.incr()
        keyword = u"இல்லை"
        else_stmt.stmt.visit( self )
        self.decr()
        return
    
    def visit_if_elseif_stmt(self,if_elseif_stmt):
        tobj = Tag(self.file,name=u"IF",tab=self.tab)
        self.incr()
        
        # condition expression
        if_elseif_stmt.expr.visit(self)
        
        # IF kw
        keyword_if = u"ஆனால்"
        
        # True-Body
        if_elseif_stmt.body.visit( self )
        
        # False-Body - optionally present
        if hasattr(if_elseif_stmt.next_stmt,'visit'):
            tobj_else = Tag(self.file,name=u"ELSE",tab=self.tab)
            self.incr()
            if_elseif_stmt.next_stmt.visit(self)
            del tobj_else
            self.decr()
        
        self.visit_end_kw()
        self.decr()
        
    def visit_end_kw(self):
        # END kw
        #tobj = Tag(name="END",tab=self.tab)
        keyword_end = u"முடி"
        
    def visit_while_stmt(self,while_stmt):
        """
        @( itr < L ) வரை
                        சமம்= சமம் + input[itr]*wts[itr]
            itr = itr + 1
                முடி"""
        tobj_while = Tag(self.file, name="WHILE", tab=self.tab)
        self.incr()

        # condition expression
        tobj_while_cond = Tag(self.file,name=u"WHILE_COND",tab=self.tab)
        self.incr()
        while_stmt.expr.visit(self)
        self.decr()
        del tobj_while_cond
        
        # While kw
        keyword_while = u"வரை"
        
        # Body
        while_stmt.body.visit( self )
        
        self.visit_end_kw()
        self.decr()
        return
    
    # foreach is transformed at the AST-level
    # so its really a MACRO here
    def visit_for_stmt(self,for_stmt):
        """
        @( x = -1 , x < 0, x = x + 1 ) ஆக
                        பதிப்பி x, "கருவேபில"
                முடி
        """
        tobj_for = Tag(self.file,name=u"FOR",tab=self.tab)
        self.incr()
        
        # condition expression
        tobj_for_init = Tag(self.file,name=u"FOR_INIT",tab=self.tab)
        for_stmt.expr_init.visit(self)
        del tobj_for_init
        
        tobj_for_cond = Tag(self.file,name=u"FOR_COND",tab=self.tab)
        for_stmt.expr_cond.visit(self)
        del tobj_for_cond
        
        tobj_for_update = Tag(self.file,name=u"FOR_UPDATE",tab=self.tab)
        for_stmt.expr_update.visit(self)
        del tobj_for_update
        
        # For kw
        keyword_for = u"ஆக"
        
        # Body
        for_stmt.body.visit( self )
        self.visit_end_kw()
        self.decr()
        return
    
    def visit_assign_stmt(self, assign_stmt):
        tobj_assign = Tag(self.file,name=u"ASSIGN",tab=self.tab)
        self.incr()
        
        tobj_assign_lval = Tag(self.file,name=u"ASSIGN_LVAL",tab=self.tab)
        self.incr()
        assign_stmt.lvalue.visit( self )
        self.decr()
        del tobj_assign_lval
        
        tobj_assign_rval = Tag(self.file,name=u"ASSIGN_RVAL",tab=self.tab)
        self.incr()
        assign_stmt.rvalue.visit( self )
        self.decr()
        del tobj_assign_rval
        
        self.decr()
        return
    
    def visit_print_stmt(self, print_stmt):
        tobj = Tag(self.file,name=u"PRINT",tab=self.tab)
        keyword = u"பதிப்பி"
        self.incr()
        print_stmt.exprlst.visit(self)
        self.decr()
        return

    def visit_eval_stmt(self, eval_stmt ):
        tobj = Tag(self.file,name=u"EVALSTMT",tab=self.tab)
        self.incr()
        eval_stmt.expr.visit(self)
        self.decr()
        return
    
    def visit_arg_list(self, arg_list):
        tobj = Tag(self.file,name=u"ARGLIST",tab=self.tab)
        self.incr()
        L = len(arg_list.get_list())
        for pos,arg in enumerate(arg_list.get_list()):
            if hasattr(arg,'visit'):
                arg.visit(self)
        self.decr()
        return
    
    def visit_value_list(self,value_list):
        for value in value_list.args:
            value.visit(self)
        return

    def visit_function(self,fndecl_stmt):
        """
        நிரல்பாகம் fibonacci_தமிழ்( x )
        @( x <= 1 ) ஆனால்
                        ஈ = 1
                இல்லை
                        ஈ = fibonacci_தமிழ்( x - 1 ) + fibonacci_தமிழ்( x - 2 )
                முடி 
                பின்கொடு ஈ
        முடி
        """
        tobj = Tag(self.file,name=u"FUNCTION",tab=self.tab,attrs={u"name":fndecl_stmt.name})
        
        # Function kw
        keyword_fn = u"நிரல்பாகம்"
        
        # name of function
        
        # arglist expression
        fndecl_stmt.arglist.visit(self)
        
        # Body expression
        fndecl_stmt.body.visit(self)
        
        return
    
    def visit_binary_expr(self,binexpr):
        self.visit_expr(binexpr)
        return
    