#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributers.

from fenrirscreenreader.core import debug
from collections import Counter

class attributeManager():
    def __init__(self):
        self.currAttributes = None
        self.prevAttributes = None
        self.currAttributeDelta = ''
        self.currAttributeCursor = None
        self.prefAttributeCursor = None
        self.initDefaultAttributes()
        self.prevLastCursorAttribute = None
        self.currLastCursorAttribute = None

    def initialize(self, environment):
        self.env = environment
    def shutdown(self):
        pass
    def setLastCursorAttribute(self, lastCursorAttribute):
        self.prevLastCursorAttribute = self.currLastCursorAttribute
        self.currLastCursorAttribute = lastCursorAttribute
    def resetLastCursorAttribute(self):
        self.prevLastCursorAttribute = None
        self.currLastCursorAttribute = None
    def isLastCursorAttributeChange(self):
        if self.prevLastCursorAttribute == None:
            return False
        return self.prevLastCursorAttribute != self.currLastCursorAttribute
    def getCurrAttributeCursor(self):
        return self.currAttributeCursor
    def isAttributeCursorActive(self):
        return self.currAttributeCursor != None
    def isAttributeChange(self):
        if not self.prevAttributes: 
            return False
        return self.currAttributes != self.prevAttributes
    def resetAttributeAll(self):
        self.resetAttributeDelta()
        self.resetAttributeCursor()
    def getAttributeDelta(self):
        return self.currAttributeDelta
    def resetAttributeDelta(self):
        self.currAttributeDelta = ''
    def setAttributeDelta(self, currAttributeDelta):
        self.currAttributeDelta = currAttributeDelta
    def resetAttributeCursor(self):
        self.currAttributeCursor = None
        self.prefAttributeCursor = None
    def setAttributeCursor(self, currAttributeCursor):
        self.prefAttributeCursor = self.currAttributeCursor
        self.currAttributeCursor = currAttributeCursor.copy()
    def resetAttributes(self, currAttributes):
        self.prevAttributes = None
        self.currAttributes = currAttributes
    def setAttributes(self, currAttributes):
        self.prevAttributes = self.currAttributes
        self.currAttributes = currAttributes.copy()

    def getAttributeByXY(self, x, y):
        if not self.currAttributes:
            return None
        if len(self.currAttributes) < y:
            return None
        if len(self.currAttributes[y]) < x - 1:
            return None
        try:
            return self.currAttributes[y][x]
        except KeyError:
            try:
                return self.defaultAttributes[0]
            except:
                pass
        return None
    def appendDefaultAttributes(self, attribute):
        if not attribute:
            return
        if len(attribute) != 10:
            return
        self.defaultAttributes.append(attribute)
    def initDefaultAttributes(self):
        self.defaultAttributes = [None]
        self.defaultAttributes.append([
            'default', # fg
            'default', # bg
            False, # bold
            False, # italics
            False, # underscore
            False, # strikethrough
            False, # reverse
            False, # blink
            'default', # fontsize
            'default' # fontfamily
        ]) #end attribute
    def isDefaultAttribute(self,attribute):
        return attribute in self.defaultAttributes
    def hasAttributes(self, cursor, update=True):
        if not cursor:
            return False
        cursorPos = cursor.copy()
        try:
            attribute = self.getAttributeByXY( cursorPos['x'], cursorPos['y'])
            
            if update:
                self.setLastCursorAttribute(attribute)
            if not self.isLastCursorAttributeChange():
                return False

            if self.isDefaultAttribute(attribute):
                return False

        except Exception as e:
            return False
        return True

    def formatAttributes(self, attribute, attributeFormatString = ''):
        # "black",
        # "red",
        # "green",
        # "brown",
        # "blue",
        # "magenta",
        # "cyan",
        # "white",
        # "default" # white.
        # _order_
        # "fg",
        # "bg",
        # "bold",
        # "italics",
        # "underscore",
        # "strikethrough",
        # "reverse",
        # "blink"
        # "fontsieze"
        # "fontfamily"
        if attributeFormatString == '':
            attributeFormatString = self.env['runtime']['settingsManager'].getSetting('general', 'attributeFormatString')
        if not attributeFormatString:
            return ''
        if attributeFormatString == '':
            return ''
        if not attribute:
            return ''
        if len(attribute) != 10:
            return ''

        # 0 FG color (name)
        try:
            attributeFormatString = attributeFormatString.replace('fenrirFGColor', _(attribute[0]))
        except Exception as e:
            attributeFormatString = attributeFormatString.replace('fenrirFGColor', '')
        
        # 1 BG color (name)
        try:
            attributeFormatString = attributeFormatString.replace('fenrirBGColor', _(attribute[1]))
        except Exception as e:
            attributeFormatString = attributeFormatString.replace('fenrirBGColor', '')
        
        # 2 bold (True/ False)
        try:
            if attribute[2]:
                attributeFormatString = attributeFormatString.replace('fenrirBold', _('bold'))    
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirBold', '')
        
        # 3 italics (True/ False)
        try:
            if attribute[3]:
                attributeFormatString = attributeFormatString.replace('fenrirItalics', _('italic'))
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirItalics', '')
        
        # 4 underline (True/ False)
        try:
            if attribute[4]:
                attributeFormatString = attributeFormatString.replace('fenrirUnderline', _('underline'))
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirUnderline', '')
        
        # 5 strikethrough (True/ False)
        try:
            if attribute[5]:
                attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', _('strikethrough'))
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirStrikethrough', '')
        
        # 6 reverse (True/ False)
        try:
            if attribute[6]:
                attributeFormatString = attributeFormatString.replace('fenrirReverse', _('reverse'))
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirReverse', '')
        
        # 7 blink (True/ False)
        try:
            if attribute[7]:
                attributeFormatString = attributeFormatString.replace('fenrirBlink', _('blink'))
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirBlink', '')
        
        # 8 font size (int/ string)
        try:
            try:
                attributeFormatString = attributeFormatString.replace('fenrirFontSize', int(attribute[8]))
            except:
                pass
            try:
                attributeFormatString = attributeFormatString.replace('fenrirFontSize', str(attribute[8]))
            except:
                pass 
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirFontSize', _('default'))
        
        # 9 font family (string)
        try:
            attributeFormatString = attributeFormatString.replace('fenrirFont', attribute[9])   
        except Exception as e:
            pass
        attributeFormatString = attributeFormatString.replace('fenrirFont', _('default'))
                 
        return attributeFormatString
    def trackHighlights(self):
        result = ''
        currCursor = None
        # screen change
        if self.prevAttributes == None:
            return result,  currCursor
        # no change
        if self.prevAttributes == self.currAttributes:
            return result,  currCursor
        # error case
        if self.currAttributes == None:
            return result,  currCursor
        # special case for pty if not text exists.
        if len(self.currAttributes) == 0:
            return result,  currCursor
        text = self.env['runtime']['screenManager'].getScreenText()
        textLines = text.split('\n')

        if len(textLines) != len(self.currAttributes):
            return result,  currCursor
        for line in range(len(self.prevAttributes)):
            if self.prevAttributes[line] != self.currAttributes[line]:
                for column in range(len(self.prevAttributes[line])):
                    if self.prevAttributes[line][column] == self.currAttributes[line][column]:
                        continue
                    if self.isUsefulForTracking(line, column, self.currAttributes, self.prevAttributes):
                        if not currCursor:
                            currCursor = {'x': column, 'y': line}
                        result += textLines[line][column]
                result += ' '
        return result, currCursor
    def isUsefulForTracking(self, line, column, currAttributes, prevAttributes, attribute=1 , mode = 'zaxe'):
        if len(currAttributes) <= 3:
            return False
        if line < 0:
            return False   
        if line > len(currAttributes):
            return False
        useful = False
        if mode == 'default':
            # non default tracking
            useful = not self.isDefaultAttribute(currAttributes[line][column])
        elif (mode == 'zaxe') or (mode == ''):
            # arround me tracking for bg
            if line == 0:
                useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line + 2][column][attribute])
            elif line >= len(prevAttributes):
                useful = (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line - 2][column][attribute])
            else:
                useful = (currAttributes[line][column][attribute] != currAttributes[line + 1][column][attribute]) and (currAttributes[line][column][attribute] != currAttributes[line - 1][column][attribute])
        elif mode == 'barrier':
            # to be implement
            useful = True

        return useful
        
