# coding=utf-8
import os, sys
import xbmc, xbmcaddon, xbmcplugin, xbmcgui, xbmcvfs
import xml.etree.ElementTree as xmltree
import urllib
import json
from traceback import print_exc
import pluginBrowser

ADDON        = xbmcaddon.Addon()
ADDONID      = ADDON.getAddonInfo('id').decode( 'utf-8' )
ADDONVERSION = ADDON.getAddonInfo('version')
LANGUAGE     = ADDON.getLocalizedString
CWD          = ADDON.getAddonInfo('path').decode("utf-8")
ADDONNAME    = ADDON.getAddonInfo('name').decode("utf-8")
DEFAULTPATH  = xbmc.translatePath( os.path.join( CWD, 'resources' ).encode("utf-8") ).decode("utf-8")
ltype        = sys.modules[ '__main__' ].ltype

def log(txt):
    if isinstance (txt,str):
        txt = txt.decode('utf-8')
    message = u'%s: %s' % (ADDONID, txt)
    xbmc.log(msg=message.encode('utf-8'), level=xbmc.LOGDEBUG)

class ViewAttribFunctions():
    def __init__(self):
        pass

    def _load_rules( self ):
        if ltype.startswith('video'):
            overridepath = os.path.join( DEFAULTPATH , "videorules.xml" )
        else:
            overridepath = os.path.join( DEFAULTPATH , "musicrules.xml" )
        try:
            tree = xmltree.parse( overridepath )
            return tree
        except:
            return None

    def translateContent( self, content ):
        # Load the rules
        tree = self._load_rules()
        hasValue = True
        elems = tree.getroot().find( "content" ).findall( "type" )
        for elem in elems:
            if elem.text == content:
                return xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
        return None

    def editContent( self, actionPath, default ):
        # Load all the rules
        tree = self._load_rules().getroot()
        elems = tree.find( "content" ).findall( "type" )
        selectName = []
        selectValue = []
        # Find all the content types
        for elem in elems:
            selectName.append( xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) ) )
            selectValue.append( elem.text )
        # Let the user select a content type
        selectedContent = xbmcgui.Dialog().select( LANGUAGE( 30309 ), selectName )
        # If the user selected no operator...
        if selectedContent == -1:
            return
        self.writeUpdatedRule( actionPath, "content", selectValue[ selectedContent ], addFilter = True )

    def translateGroup( self, grouping ):
        # Load the rules
        tree = self._load_rules()
        hasValue = True
        elems = tree.getroot().find( "groupings" ).findall( "grouping" )
        for elem in elems:
            if elem.attrib.get( "name" ) == grouping:
                return xbmc.getLocalizedString( int( elem.find( "label" ).text ) )
        return None

    def editGroup( self, actionPath, content, default ):
        # Load all the rules
        tree = self._load_rules().getroot()
        elems = tree.find( "groupings" ).findall( "grouping" )
        selectName = []
        selectValue = []
        # Find all the content types
        for elem in elems:
            checkContent = elem.find( content )
            if checkContent is not None:
                selectName.append( xbmc.getLocalizedString( int( elem.find( "label" ).text ) ) )
                selectValue.append( elem.attrib.get( "name" ) )
        # Let the user select a content type
        selectedGrouping = xbmcgui.Dialog().select( LANGUAGE( 30310 ), selectName )
        # If the user selected no operator...
        if selectedGrouping == -1:
            return
        self.writeUpdatedRule( actionPath, "group", selectValue[ selectedGrouping ] )

    def addLimit( self, actionPath ):
        # Load all the rules
        try:
            tree = xmltree.parse( actionPath )
            root = tree.getroot()
            # Add a new content tag
            newContent = xmltree.SubElement( root, "limit" )
            newContent.text = "25"
            # Save the file
            self.indent( root )
            tree.write( actionPath, encoding="UTF-8" )
        except:
            print_exc()

    def editLimit( self, actionPath, curValue ):
        returnVal = xbmcgui.Dialog().input( LANGUAGE( 30311 ), curValue, type=xbmcgui.INPUT_NUMERIC )
        if returnVal != "":
            self.writeUpdatedRule( actionPath, "limit", returnVal )

    def addPath( self, actionPath ):
        # Load all the rules
        tree = self._load_rules().getroot()
        elems = tree.find( "paths" ).findall( "type" )
        selectName = []
        selectValue = []
        # Find all the path types
        for elem in elems:
            selectName.append( xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) ) )
            selectValue.append( elem.attrib.get( "name" ) )
            # Find any sub-path types
            for subElem in elem.findall( "type" ):
                selectName.append( "  - %s" %( xbmc.getLocalizedString( int( subElem.attrib.get( "label" ) ) ) ) )
                selectValue.append( "%s/%s" %( elem.attrib.get( "name" ), subElem.attrib.get( "name" ) ) )

        # Add option to select a plugin
        selectName.append( LANGUAGE( 30514 ) )
        selectValue.append( "::PLUGIN::" )

        # Let the user select a path
        selectedContent = xbmcgui.Dialog().select( LANGUAGE( 30309 ), selectName )
        # If the user selected no operator...
        if selectedContent == -1:
            return
        if selectValue[ selectedContent ] == "::PLUGIN::":
            # The user has asked to browse for a plugin
            path = pluginBrowser.getPluginPath()
            if path is not None:
                # User has selected a plugin
                self.writeUpdatedPath( actionPath, (0, path), addFolder = True)
        else:
            # The user has chosen a specific path
            self.writeUpdatedPath( actionPath, (0, selectValue[ selectedContent ] ), addFolder = True )

    def editPath( self, actionPath, curValue ):
        returnVal = xbmcgui.Dialog().input( LANGUAGE( 30312 ), curValue, type=xbmcgui.INPUT_ALPHANUM )
        if returnVal != "":
            self.writeUpdatedRule( actionPath, "path", returnVal.decode( "utf-8" ) )

    def editIcon( self, actionPath, curValue ):
        returnVal = xbmcgui.Dialog().input( LANGUAGE( 30313 ), curValue, type=xbmcgui.INPUT_ALPHANUM )
        if returnVal != "":
            self.writeUpdatedRule( actionPath, "icon", returnVal.decode( "utf-8" ) )

    def browseIcon( self, actionPath ):
        returnVal = xbmcgui.Dialog().browse( 2, LANGUAGE( 30313 ), "files", useThumbs = True )
        if returnVal:
            self.writeUpdatedRule( actionPath, "icon", returnVal )

    def writeUpdatedRule( self, actionPath, attrib, value, addFilter = False ):
        # This function writes an updated match, operator or value to a rule
        try:
            # Load the xml file
            tree = xmltree.parse( actionPath )
            root = tree.getroot()
            # Add type="filter" if requested
            if addFilter:
                root.set( "type", "filter" )
            # Find the attribute and update it
            elem = root.find( attrib )
            if elem is None:
                # There's no existing attribute with this name, so create one
                elem = xmltree.SubElement( root, attrib )
            elem.text = value
            # Save the file
            self.indent( root )
            tree.write( actionPath, encoding="UTF-8" )
        except:
            print_exc()

    def writeUpdatedPath( self, actionPath, newComponent, addFolder = False ):
        # This functions writes an updated path
        try:
            # Load the xml file
            tree = xmltree.parse( actionPath )
            root = tree.getroot()
            # Add type="folder" if requested
            if addFolder:
                root.set( "type", "folder" )
            # Find the current path element
            elem = root.find( "path" )
            if elem is None:
                # There's no existing path element, so create one
                elem = xmltree.SubElement( root, "path" )
            # Get the split version of the path
            splitPath = self.splitPath( elem.text )
            elem.text = ""
            if len( splitPath ) == 0:
                # If the splitPath is empty, add our new component straight away
                elem.text = "%s/" %( newComponent[ 1 ] )
            elif newComponent[ 0 ] == 0 and newComponent[ 1 ].startswith( "plugin://"):
                # We've been passed a plugin, so only want to write that plugin
                elem.text = newComponent[ 1 ]
            else:
                # Enumarate through everything in the existing path
                for x, component in enumerate( splitPath ):
                    if x != newComponent[ 0 ]:
                        # Transfer this component to the new path
                        if x == 0:
                            elem.text = self.joinPath( component )
                        elif x == 1:
                            elem.text += "?%s=%s" %( component[ 0 ], urllib.quote( component[ 1 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                        else:
                            elem.text += "&%s=%s" %( component[ 0 ], urllib.quote( component[ 1 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                    else:
                        # Add our new component
                        if x == 0:
                            elem.text = "%s/" %( newComponent[ 1 ] )
                        elif x == 1:
                            elem.text += "?%s=%s" %( newComponent[ 1 ], urllib.quote( newComponent[ 2 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                        else:
                            elem.text += "&%s=%s" %( newComponent[ 1 ], urllib.quote( newComponent[ 2 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                # Check that we added it
                if x < newComponent[ 0 ]:
                    if newComponent[ 0 ] == 1:
                        elem.text += "?%s=%s" %( newComponent[ 1 ], urllib.quote( newComponent[ 2 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                    else:
                        elem.text += "&%s=%s" %( newComponent[ 1 ], urllib.quote( newComponent[ 2 ].encode( "utf-8" ) ).decode( "utf-8" ) )
            # Save the file
            self.indent( root )
            tree.write( actionPath, encoding="UTF-8" )
        except:
            print_exc()

    def deletePathRule( self, actionPath, rule ):
        # This function deletes a rule from a path component
        result = xbmcgui.Dialog().yesno(ADDONNAME, LANGUAGE( 30407 ) )
        if not result:
            return

        try:
            # Load the xml file
            tree = xmltree.parse( actionPath )
            root = tree.getroot()
            # Find the current path element
            elem = root.find( "path" )
            # Get the split version of the path
            splitPath = self.splitPath( elem.text )
            elem.text = ""

            # Enumarate through everything in the existing path
            addedQ = False
            for x, component in enumerate( splitPath ):
                if x != rule:
                    # Transfer this component to the new path
                    if x == 0:
                        elem.text = self.joinPath( component )
                    elif not addedQ:
                        elem.text += "?%s=%s" %( component[ 0 ], urllib.quote( component[ 1 ].encode( "utf-8" ) ).decode( "utf-8" ) )
                        addedQ = True
                    else:
                        elem.text += "&%s=%s" %( component[ 0 ], urllib.quote( component[ 1 ].encode( "utf-8" ) ).decode( "utf-8" ) )
            # Save the file
            self.indent( root )
            tree.write( actionPath, encoding="UTF-8" )
        except:
            print_exc()

    def splitPath( self, completePath ):
        # This function returns an array of the different components of a path
        # [library]://[primary path]/[secondary path]/?attribute1=value1&attribute2=value2...
        # [(                        ,              )] [(        ,    )] [(        ,    )]...
        splitPath = []

        # If completePath is empty, return an empty list
        if completePath is None:
            return []

        # If it's a plugin, then we don't want to split it as its unlikely the user will want to edit individual components
        if completePath.startswith( "plugin://" ):
            return [ ( completePath, None ) ]

        # Split, get the library://primarypath/[secondarypath]
        split = completePath.rsplit( "/", 1 )
        if split[ 0 ].count( "/" ) == 3:
            # There's a secondary path
            paths = split[ 0 ].rsplit( "/", 1 )
            splitPath.append( ( paths[0], paths[1] ) )
        else:
            splitPath.append( ( split[ 0 ], None ) )


        # Now split the components
        if len( split ) != 1 and split[ 1 ].startswith( "?" ):
            for component in split[ 1 ][ 1: ].split( "&" ):
                componentSplit = component.split( "=" )
                splitPath.append( ( componentSplit[ 0 ], urllib.unquote( componentSplit[ 1 ].encode( "utf-8" ) ).decode( "utf-8" ) ) )

        return splitPath

    def joinPath( self, components ):
        # This function rejoins the library://path/subpath components of a path
        returnPath = "%s/" %( components[ 0 ] )
        if components[ 1 ] is not None:
            returnPath += "%s/" %( components[ 1 ] )
        return returnPath


    def translatePath( self, path ):
        # Load the rules
        tree = self._load_rules()
        subSearch = None
        translated = [ path[ 0 ], path[ 1 ] ]
        elems = tree.getroot().find( "paths" ).findall( "type" )
        for elem in elems:
            if elem.attrib.get( "name" ) == path[ 0 ]:
                translated[ 0 ] = xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
                subSearch = elem
                break

        if path[ 1 ] and subSearch is not None:
            for elem in subSearch.findall( "type" ):
                if elem.attrib.get( "name" ) == path[ 1 ]:
                    translated[ 1 ] = xbmc.getLocalizedString( int( elem.attrib.get( "label" ) ) )
                    break

        returnString = translated[ 0 ]
        if translated[ 1 ]:
            returnString += " - %s" %( translated[ 1 ] )

        return returnString

    def translateMatch( self, value ):
        if value == "any":
            return xbmc.getLocalizedString(21426).capitalize()
        else:
            return xbmc.getLocalizedString(21425).capitalize()

    def editMatch( self, actionPath ):
        selectName = [ xbmc.getLocalizedString(21425).capitalize(), xbmc.getLocalizedString(21426).capitalize() ]
        selectValue = [ "all", "any" ]
        # Let the user select wether any or all rules need match
        selectedMatch = xbmcgui.Dialog().select( LANGUAGE( 30310 ), selectName )
        # If the user made no selection...
        if selectedMatch == -1:
            return
        self.writeUpdatedRule( actionPath, "match", selectValue[ selectedMatch ] )

    # in-place prettyprint formatter
    def indent( self, elem, level=0 ):
        i = "\n" + level*"\t"
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + "\t"
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
            for elem in elem:
                self.indent(elem, level+1)
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
        else:
            if level and (not elem.tail or not elem.tail.strip()):
                elem.tail = i
