import xbmcaddon
import xbmcplugin
import xbmc
import xbmcgui
import xbmcvfs
import os, sys
import threading
import json
import urllib
import time

WINDOW = xbmcgui.Window(10000)

import Utils as utils
from ClientInformation import ClientInformation
from PlaybackUtils import PlaybackUtils
from DownloadUtils import DownloadUtils
from ReadEmbyDB import ReadEmbyDB
from API import API


##### Play items via plugin://plugin.video.emby/ #####
def doPlayback(id):
    checkService()
    url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id
    result = DownloadUtils().downloadUrl(url)
    item = PlaybackUtils().PLAY(result, setup="default")


#### DO RESET AUTH #####    
def resetAuth():
    # User tried login and failed too many times
    resp = xbmcgui.Dialog().yesno("Warning", "Emby might lock your account if you fail to log in too many times. Proceed anyway?")
    if resp == 1:
        xbmc.log("Reset login attempts.")
        WINDOW.setProperty("Server_status", "Auth")
    else:
        xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')

### ADD ADDITIONAL USERS ###
def addUser():

    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    currUser = WINDOW.getProperty("currUser")
    deviceId = clientInfo.getMachineId()
    deviceName = clientInfo.getDeviceName()

    # Get session
    url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
    result = doUtils.downloadUrl(url)
    
    try:
        sessionId = result[0][u'Id']
        additionalUsers = result[0][u'AdditionalUsers']
        # Add user to session
        userlist = {}
        users = []
        url = "{server}/mediabrowser/Users?IsDisabled=false&IsHidden=false"
        result = doUtils.downloadUrl(url)

        # pull the list of users
        for user in result:
            name = user[u'Name']
            userId = user[u'Id']
            if currUser not in name:
                userlist[name] = userId
                users.append(name)

        # Display dialog if there's additional users
        if additionalUsers:

            option = xbmcgui.Dialog().select("Add/Remove user from the session", ["Add user", "Remove user"])
            # Users currently in the session
            additionalUserlist = {}
            additionalUsername = []
            # Users currently in the session
            for user in additionalUsers:
                name = user[u'UserName']
                userId = user[u'UserId']
                additionalUserlist[name] = userId
                additionalUsername.append(name)

            if option == 1:
                # User selected Remove user
                resp = xbmcgui.Dialog().select("Remove user from the session", additionalUsername)
                if resp > -1:
                    selected = additionalUsername[resp]
                    selected_userId = additionalUserlist[selected]
                    url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
                    postdata = {}
                    doUtils.downloadUrl(url, postBody=postdata, type="DELETE")
                    xbmcgui.Dialog().notification("Success!", "%s removed from viewing session" % selected, time=1000)
                    return
                else:
                    return

            elif option == 0:
                # User selected Add user
                for adduser in additionalUsername:
                    xbmc.log(str(adduser))
                    users.remove(adduser)

            elif option < 0:
                # User cancelled
                return

        # Subtract any additional users
        xbmc.log("Displaying list of users: %s" % users)
        resp = xbmcgui.Dialog().select("Add user to the session", users)
        # post additional user
        if resp > -1:
            selected = users[resp]
            selected_userId = userlist[selected]
            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
            postdata = {}
            doUtils.downloadUrl(url, postBody=postdata, type="POST")
            xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % selected, time=1000)

    except:
        xbmc.log("Failed to add user to session.")
        xbmcgui.Dialog().notification("Error", "Unable to add/remove user from the session.", xbmcgui.NOTIFICATION_ERROR)

##### BROWSE EMBY CHANNELS #####    
def BrowseChannels(id, folderid=None):
    
    _addon_id   =   int(sys.argv[1])
    _addon_url  =   sys.argv[0]
    
    xbmcplugin.setContent(int(sys.argv[1]), 'files')
    if folderid:
        url = "{server}/mediabrowser/Channels/" + id + "/Items?userid={UserId}&folderid=" + folderid + "&format=json"
    else:
        if id == "0": # id 0 is the root channels folder
            url = "{server}/mediabrowser/Channels?{UserId}&format=json"
        else:
            url = "{server}/mediabrowser/Channels/" + id + "/Items?userid={UserId}&format=json"

    results = DownloadUtils().downloadUrl(url)
    if results:
        result = results.get("Items")
        if(result == None):
            result = []

        item_count = len(result)
        current_item = 1;
            
        for item in result:
            id=str(item.get("Id")).encode('utf-8')
            type=item.get("Type").encode('utf-8')
            
            
            if(item.get("Name") != None):
                tempTitle = item.get("Name")
                tempTitle=tempTitle.encode('utf-8')
            else:
                tempTitle = "Missing Title"
                
            if type=="ChannelFolderItem":
                isFolder = True
            else:
                isFolder = False
            item_type = str(type).encode('utf-8')
            
            if(item.get("ChannelId") != None):
               channelId = str(item.get("ChannelId")).encode('utf-8')
            
            channelName = ''   
            if(item.get("ChannelName") != None):
               channelName = item.get("ChannelName").encode('utf-8')   
               
            if(item.get("PremiereDate") != None):
                premieredatelist = (item.get("PremiereDate")).split("T")
                premieredate = premieredatelist[0]
            else:
                premieredate = ""
            
            #mediaStreams=API().getMediaStreams(item, True)
                    
            #people = API().getPeople(item)
            
            # Process Genres
            genre = API().getGenre(item)
                    
            # Process UserData
            userData = item.get("UserData")
            PlaybackPositionTicks = '100'
            overlay = "0"
            favorite = "False"
            seekTime = 0
            if(userData != None):
                if userData.get("Played") != True:
                    overlay = "7"
                    watched = "true"
                else:
                    overlay = "6"
                    watched = "false"
                if userData.get("IsFavorite") == True:
                    overlay = "5"
                    favorite = "True"
                else:
                    favorite = "False"
                if userData.get("PlaybackPositionTicks") != None:
                    PlaybackPositionTicks = str(userData.get("PlaybackPositionTicks"))
                    reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
                    seekTime = reasonableTicks / 10000
            
            playCount = 0
            if(userData != None and userData.get("Played") == True):
                playCount = 1
            # Populate the details list
            details={'title'        : tempTitle,
                     'channelname'  : channelName,
                     'plot'         : item.get("Overview"),
                     'Overlay'      : overlay,
                     'playcount'    : str(playCount)}
            
            if item.get("Type") == "ChannelVideoItem":
                xbmcplugin.setContent(_addon_id, 'movies')
            elif item.get("Type") == "ChannelAudioItem":
                xbmcplugin.setContent(_addon_id, 'songs')

            # Populate the extraData list
            extraData={'thumb'        : API().getArtwork(item, "Primary")  ,
                       'fanart_image' : API().getArtwork(item, "Backdrop") ,
                       'poster'       : API().getArtwork(item, "poster") , 
                       'tvshow.poster': API().getArtwork(item, "tvshow.poster") ,
                       'banner'       : API().getArtwork(item, "Banner") ,
                       'clearlogo'    : API().getArtwork(item, "Logo") ,
                       'discart'      : API().getArtwork(item, "Disc") ,
                       'clearart'     : API().getArtwork(item, "Art") ,
                       'landscape'    : API().getArtwork(item, "Thumb") ,
                       'id'           : id ,
                       'rating'       : item.get("CommunityRating"),
                       'year'         : item.get("ProductionYear"),
                       'premieredate' : premieredate,
                       'genre'        : genre,
                       'playcount'    : str(playCount),
                       'itemtype'     : item_type}
                       
            if extraData['thumb'] == '':
                extraData['thumb'] = extraData['fanart_image']
                
            liz = xbmcgui.ListItem(tempTitle)

            artTypes=['poster', 'tvshow.poster', 'fanart_image', 'clearlogo', 'discart', 'banner', 'clearart', 'landscape', 'small_poster', 'tiny_poster', 'medium_poster','small_fanartimage', 'medium_fanartimage', 'medium_landscape', 'fanart_noindicators']
            
            for artType in artTypes:
                imagePath=str(extraData.get(artType,''))
                liz=PlaybackUtils().setArt(liz,artType, imagePath)
            
            liz.setThumbnailImage(API().getArtwork(item, "Primary"))
            liz.setIconImage('DefaultTVShows.png')
            #liz.setInfo( type="Video", infoLabels={ "Rating": item.get("CommunityRating") })
            #liz.setInfo( type="Video", infoLabels={ "Plot": item.get("Overview") })
            
            if type=="Channel":
                file = _addon_url + "?id=%s&mode=channels"%id
                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz, isFolder=True)
            
            elif isFolder == True:
                file = _addon_url + "?id=%s&mode=channelsfolder&folderid=%s" %(channelId, id)
                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz, isFolder=True)
            else:
                file = _addon_url + "?id=%s&mode=play"%id
                liz.setProperty('IsPlayable', 'true')
                xbmcplugin.addDirectoryItem(handle=_addon_id, url=file, listitem=liz)

    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

##### GET NEXTUP EPISODES FOR TAGNAME #####    
def getNextUpEpisodes(tagname,limit):
    #if the addon is called with nextup parameter, we return the nextepisodes list of the given tagname
    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
    # First we get a list of all the in-progress TV shows - filtered by tag
    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "lastplayed" }, "filter": {"and": [{"operator":"true", "field":"inprogress", "value":""}, {"operator": "contains", "field": "tag", "value": "%s"}]}, "properties": [ "title", "studio", "mpaa", "file", "art" ]  }, "id": "libTvShows"}' %tagname)
    
    json_result = json.loads(json_query_string)
    # If we found any, find the oldest unwatched show for each one.
    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
        for item in json_result['result']['tvshows']:
            json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "writer", "cast", "dateadded", "lastplayed" ], "limits":{"end":1}}, "id": "1"}' %item['tvshowid'])

            if json_query2:
                json_query2 = json.loads(json_query2)
                if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
                    count = 0
                    for item in json_query2['result']['episodes']:
                        liz = createListItem(item)
                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
                        count +=1
                        if count == limit:
                            break
    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

def getInProgressEpisodes(tagname,limit):
    #if the addon is called with inprogressepisodes parameter, we return the inprogressepisodes list of the given tagname
    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
    # First we get a list of all the in-progress TV shows - filtered by tag
    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "lastplayed" }, "filter": {"and": [{"operator":"true", "field":"inprogress", "value":""}, {"operator": "contains", "field": "tag", "value": "%s"}]}, "properties": [ "title", "studio", "mpaa", "file", "art" ]  }, "id": "libTvShows"}' %tagname)
    
    json_result = json.loads(json_query_string)
    # If we found any, find all in progress episodes for each one.
    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
        for item in json_result['result']['tvshows']:
            json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "inprogress", "operator": "true", "value":""}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "cast", "streamdetails", "firstaired", "runtime", "writer", "dateadded", "lastplayed" ]}, "id": "1"}' %item['tvshowid'])

            if json_query2:
                json_query2 = json.loads(json_query2)
                if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
                    count = 0
                    for item in json_query2['result']['episodes']:
                        liz = createListItem(item)
                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
                        count +=1
                        if count == limit:
                            break
    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))

def getRecentEpisodes(tagname,limit):
    #if the addon is called with recentepisodes parameter, we return the recentepisodes list of the given tagname
    xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
    # First we get a list of all the TV shows - filtered by tag
    json_query_string = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "sort": { "order": "descending", "method": "dateadded" }, "properties": [ "title","sorttitle" ], "filter": {"operator": "contains", "field": "tag", "value": "%s"} }, "id": "libTvShows"}' %tagname)    
    json_result = json.loads(json_query_string)
    
    # If we found any, put all tv show id's in a list
    if json_result.has_key('result') and json_result['result'].has_key('tvshows'):
        alltvshowIds = list()
        for tvshow in json_result['result']['tvshows']:
            alltvshowIds.append(tvshow["tvshowid"])
        alltvshowIds = set(alltvshowIds)
        
        #get all recently added episodes
        json_query2 = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "sort": {"order": "descending", "method": "dateadded"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "streamdetails", "firstaired", "runtime", "cast", "writer", "dateadded", "lastplayed" ]}, "limits":{"end":%d}, "id": "1"}' %limit)
        count = 0
        if json_query2:
            json_query2 = json.loads(json_query2)
            if json_query2.has_key('result') and json_query2['result'].has_key('episodes'):
                for item in json_query2['result']['episodes']:
                    if item["tvshowid"] in alltvshowIds:
                        liz = createListItem(item)
                        xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=item['file'], listitem=liz)
                        count += 1
                    if count >= limit:
                        break
    xbmcplugin.endOfDirectory(handle=int(sys.argv[1]))
    
def createListItem(item):
       
    liz = xbmcgui.ListItem(item['title'])
    liz.setInfo( type="Video", infoLabels={ "Title": item['title'] })
    liz.setProperty('IsPlayable', 'true')
    liz.setInfo( type="Video", infoLabels={ "duration": str(item['runtime']/60) })
    
    if "episode" in item:
        episode = "%.2d" % float(item['episode'])
        liz.setInfo( type="Video", infoLabels={ "Episode": item['episode'] })
    
    if "season" in item:
        season = "%.2d" % float(item['season'])
        liz.setInfo( type="Video", infoLabels={ "Season": item['season'] })
        
    if season and episode:
        episodeno = "s%se%s" %(season,episode)
        liz.setProperty("episodeno", episodeno)
        
    if "firstaired" in item:
        liz.setInfo( type="Video", infoLabels={ "Premiered": item['firstaired'] })
    
    plot = item['plot']
    liz.setInfo( type="Video", infoLabels={ "Plot": plot })
    
    if "showtitle" in item:
        liz.setInfo( type="Video", infoLabels={ "TVshowTitle": item['showtitle'] })
    
    if "rating" in item:
        liz.setInfo( type="Video", infoLabels={ "Rating": str(round(float(item['rating']),1)) })
    liz.setInfo( type="Video", infoLabels={ "Playcount": item['playcount'] })
    if "director" in item:
        liz.setInfo( type="Video", infoLabels={ "Director": " / ".join(item['director']) })
    if "writer" in item:
        liz.setInfo( type="Video", infoLabels={ "Writer": " / ".join(item['writer']) })
        
    if "cast" in item:
        listCast = []
        listCastAndRole = []
        for castmember in item["cast"]:
            listCast.append( castmember["name"] )
            listCastAndRole.append( (castmember["name"], castmember["role"]) ) 
        cast = [listCast, listCastAndRole]
        liz.setInfo( type="Video", infoLabels={ "Cast": cast[0] })
        liz.setInfo( type="Video", infoLabels={ "CastAndRole": cast[1] })
    
    liz.setProperty("resumetime", str(item['resume']['position']))
    liz.setProperty("totaltime", str(item['resume']['total']))
    liz.setArt(item['art'])
    liz.setThumbnailImage(item['art'].get('thumb',''))
    liz.setIconImage('DefaultTVShows.png')
    liz.setProperty("dbid", str(item['episodeid']))
    liz.setProperty("fanart_image", item['art'].get('tvshow.fanart',''))
    for key, value in item['streamdetails'].iteritems():
        for stream in value:
            liz.addStreamInfo( key, stream )
    
    return liz
    
##### GET EXTRAFANART FOR LISTITEM #####
def getExtraFanArt():
    itemPath = ""
    embyId = ""
    #get extrafanart for listitem - this will only be used for skins that actually call the listitem's path + fanart dir... 
    try:
        #only do this if the listitem has actually changed
        itemPath = xbmc.getInfoLabel("ListItem.FileNameAndPath")
            
        if not itemPath:
            itemPath = xbmc.getInfoLabel("ListItem.Path")
        
        if ("/tvshows/" in itemPath or "/musicvideos/" in itemPath or "/movies/" in itemPath):
            embyId = itemPath.split("/")[-2]

            #we need to store the images locally for this to work because of the caching system in xbmc
            fanartDir = xbmc.translatePath("special://thumbnails/emby/" + embyId + "/")
            
            if not xbmcvfs.exists(fanartDir):
                #download the images to the cache directory
                xbmcvfs.mkdir(fanartDir)
                item = ReadEmbyDB().getFullItem(embyId)
                if item != None:
                    if item.has_key("BackdropImageTags"):
                        if(len(item["BackdropImageTags"]) > 0):
                            totalbackdrops = len(item["BackdropImageTags"]) 
                            for index in range(0,totalbackdrops): 
                                backgroundUrl = API().getArtwork(item, "Backdrop",str(index))
                                fanartFile = os.path.join(fanartDir,"fanart" + str(index) + ".jpg")
                                li = xbmcgui.ListItem(str(index), path=fanartFile)
                                xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=fanartFile, listitem=li)
                                xbmcvfs.copy(backgroundUrl,fanartFile) 
                
            else:
                #use existing cached images
                dirs, files = xbmcvfs.listdir(fanartDir)
                count = 1
                for file in files:
                    count +=1
                    li = xbmcgui.ListItem(file, path=os.path.join(fanartDir,file))
                    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=os.path.join(fanartDir,file), listitem=li)
    except:
        pass
    
    #always do endofdirectory to prevent errors in the logs
    xbmcplugin.endOfDirectory(int(sys.argv[1]))


def addDirectoryItem(label, path, folder=True):
    li = xbmcgui.ListItem(label, path=path)
    li.setThumbnailImage("special://home/addons/plugin.video.emby/icon.png")
    li.setArt({"fanart":"special://home/addons/plugin.video.emby/fanart.jpg"})
    li.setArt({"landscape":"special://home/addons/plugin.video.emby/fanart.jpg"})
    xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)    
    
# if the addon is called without parameters we show the listing...    
def doMainListing():
    
    xbmcplugin.setContent(int(sys.argv[1]), 'files')    
    #get emby nodes from the window props
    embyProperty = WINDOW.getProperty("Emby.nodes.total")
    if embyProperty:
        totalNodes = int(embyProperty)
        for i in range(totalNodes):
            path = WINDOW.getProperty("Emby.nodes.%s.index" %str(i))
            if not path:
                path = WINDOW.getProperty("Emby.nodes.%s.content" %str(i))
            label = WINDOW.getProperty("Emby.nodes.%s.title" %str(i))
            if path:
                addDirectoryItem(label, path)
    
    # some extra entries for settings and stuff. TODO --> localize the labels
    addDirectoryItem("Settings", "plugin://plugin.video.emby/?mode=settings")
    addDirectoryItem("Perform manual sync", "plugin://plugin.video.emby/?mode=manualsync")
    addDirectoryItem("Add user to session", "plugin://plugin.video.emby/?mode=adduser")
    addDirectoryItem("Perform local database reset (full resync)", "plugin://plugin.video.emby/?mode=reset")
    
    xbmcplugin.endOfDirectory(int(sys.argv[1]))                
             
def checkService():

    timeStamp = xbmcgui.Window(10000).getProperty("Emby_Service_Timestamp")
    loops = 0
    monitor = xbmc.Monitor()
    while(timeStamp == ""):
        timeStamp = xbmcgui.Window(10000).getProperty("Emby_Service_Timestamp")
        loops = loops + 1
        if(loops == 5):
            xbmc.log("Emby Service Not Running, no time stamp, exiting")
            addon = xbmcaddon.Addon(id='plugin.video.emby')
            language = addon.getLocalizedString
            xbmcgui.Dialog().ok(language(30135), language(30136), language(30137))
            sys.exit()
        if monitor.waitForAbort(1):
            # Abort was requested while waiting. We should exit
            return
        
    xbmc.log("Emby Service Timestamp: " + timeStamp)
    xbmc.log("Emby Current Timestamp: " + str(int(time.time())))
    
    if((int(timeStamp) + 30) < int(time.time())):
        xbmc.log("Emby Service Not Running, time stamp to old, exiting")
        addon = xbmcaddon.Addon(id='plugin.video.emby')
        language = addon.getLocalizedString        
        xbmcgui.Dialog().ok(language(30135), language(30136), language(30137))
        sys.exit()