"""
    :)
"""
from vyapp.plugins.syntax.tools import get_tokens_unprocessed_matrix
from vyapp.plugins.syntax.keys import PRECEDENCE_TABLE, DEFAULT
from pygments.lexers import get_lexer_for_filename, guess_lexer


class Spider:
    def  __init__(self, area, theme, max=10):
        self.area          = area
        self.max           = max
        self.theme         = theme
        self.styles        = theme.styles
        self.default_style = getattr(theme, 'default_style', '#957C8B')
        self.default_style = self.default_style if self.default_style else '#957C8B'

        self.default_background = theme.background_color \
        if theme.background_color else 'black'
        self.lexer = None
        area.configure(background = self.default_background)
        area.configure(foreground = self.default_style)

        for ind in self.styles.keys():
            self.set_token_style(ind)

        area.install('syntax', (-1, '<<LoadData>>', 
        lambda event: self.update_all()),
        (-1, '<<SaveData>>', lambda event: self.update_all()),
        (-1, '<Escape>', lambda event: self.update()))

    def set_lexer(self):
        """
        Try to detect the lexer by filename if it fails
        then try to guess the lex by shebang statement.
        
        The shebang statement should be placed in the first
        20 lines of the file.
        """

        try:
            self.lexer = get_lexer_for_filename(self.area.filename, '')
        except Exception as e:
            self.lexer = guess_lexer(self.area.get('1.0', '20.0'))

    def update_all(self):
        """
        Colorize all text in the widget.
        """

        # When it need to update all the text
        # just save the lexer for later usage.
        self.set_lexer()
        self.tag_tokens('1.0', 'end')

    def update(self):
        """
        Update a small range of the text. It is mostly called 
        when Escape is pressed.
        """

        TAG_KEYS_PRECEDENCE = PRECEDENCE_TABLE.get(
        tuple(self.lexer.aliases), DEFAULT)

        index0 = self.area.index('@0,0')
        index0 = self.area.index('%s -%sl' % (index0, self.max))
        index0 = self.area.tag_next_occur(TAG_KEYS_PRECEDENCE, 
        index0, 'insert', '1.0')

        index1 = '@%s,%s' % (self.area.winfo_height(), 
        self.area.winfo_width())

        index2 = self.area.index(index1)
        index2 = self.area.index('%s +%sl' % (index1, self.max))

        index2 = self.area.tag_prev_occur(TAG_KEYS_PRECEDENCE, 
        index2, 'insert', 'end')

        for ind in self.styles.keys():
            self.area.tag_remove(str(ind), index0, index2)
        self.tag_tokens(index0, index2)

    def tag_tokens(self, index, stopindex):
        """
        Add the token'tag to each range of text.
        """

        count, offset = self.area.indexref(index)
        tokens        = get_tokens_unprocessed_matrix(count, offset, 
        self.area.get(index, stopindex), self.lexer)

        for ((srow, scol), (erow, ecol)), token, value in tokens:
            self.area.tag_add(str(token), '%s.%s' % (srow, 
                 scol), '%s.%s' % (erow, ecol))

    def set_token_style(self, token):
        """
        Configure the tag which maps to the token in the
        AreaVi. 
        
        If there is no such a definition of token
        in styles dict then it defaults to self.background 
        and self.default_style.
        """

        tag  = str(token)
        conf = self.theme.style_for_token(token)

        self.area.tag_configure(tag, 
        foreground='#%s' % conf['color'] if conf['color'] \
        else self.default_style, 
        background='#%s' % conf['bgcolor'] if conf['bgcolor'] else \
        self.default_background, 
        underline=conf['underline'])

        # Note: It may be interesting to redefine
        # tag_configure in AreaVi and implement it there.
        self.area.tag_lower(tag, 'sel')

install = Spider