import os
import re
import time
import xbmc
import xbmcvfs
import xbmcgui
import urllib2
import bjsonrpc
from bjsonrpc.handlers import BaseHandler
from quasar.addon import ADDON, ADDON_PATH
from quasar.logger import log
from quasar.config import JSONRPC_EXT_PORT, QUASARD_HOST
from quasar.osarch import PLATFORM
from quasar.util import toUtf8, notify, getLocalizedString, getLocalizedLabel, system_information
from quasar.overlay import OverlayText
from quasar.dialog_select import DialogSelect
from quasar.dialog_insert import DialogInsert

XBMC_PLAYER = xbmc.Player()

class QuasarRPCServer(BaseHandler):
    public_methods_pattern = r'^[A-Za-z]\w+$'

    _objects = {}
    _failures = {}

    def Reset(self):
        for i in self._objects:
            try:
                self._objects[i].hide()
            except:
                pass
        log.info("Resetting RPC objects...")
        self._objects = {}

    def Refresh(self):
        return xbmc.executebuiltin("Container.Refresh")

    def UpdateAddonRepos(self):
        return xbmc.executebuiltin("UpdateAddonRepos")

    def SystemInformation(self):
        return system_information()

    def Notify(self, header, message, image):
        return notify(getLocalizedLabel(message), header, 3000, image)

    def Keyboard(self, default="", heading="", hidden=False):
        keyboard = xbmc.Keyboard(default, getLocalizedLabel(heading), hidden)
        keyboard.doModal()
        if keyboard.isConfirmed():
            return keyboard.getText()

    def Dialog(self, title, message):
        dialog = xbmcgui.Dialog()
        return dialog.ok(getLocalizedLabel(title), getLocalizedLabel(message))

    def Dialog_Confirm(self, title, message):
        dialog = xbmcgui.Dialog()
        return dialog.yesno(getLocalizedLabel(title), getLocalizedLabel(message))

    def Dialog_Select(self, title, items):
        dialog = xbmcgui.Dialog()
        return dialog.select(getLocalizedLabel(title), items)

    def Dialog_Select_Large(self, title, subject, items):
        build = xbmc.getInfoLabel("System.BuildVersion")
        kodi_version = int(build.split()[0][:2])

        title_encoded = "%s %s" % (getLocalizedLabel(title), toUtf8(subject))

        # For Kodi < 15
        if kodi_version < 15:
            log.warning("Kodi version below 15, using standard xbmc.Dialog()")
            log.warning("See https://github.com/scakemyer/plugin.video.quasar/issues/75")

            dialog = xbmcgui.Dialog()
            for i, item in enumerate(items):
                item = item.replace("\n", " - ")
                items[i] = item
            return dialog.select(title_encoded, items)

        # For Kodi >= 15
        else:
            window = DialogSelect("DialogSelectLarge.xml",
                                  ADDON_PATH,
                                  "Default",
                                  title=title_encoded,
                                  items=items)

            window.doModal()
            retval = window.retval
            del window

            return retval

    def Player_GetPlayingFile(self, *args, **kwargs):
        return XBMC_PLAYER.getPlayingFile()

    def Player_IsPlaying(self, *args, **kwargs):
        return XBMC_PLAYER.isPlaying(*args, **kwargs)

    def Player_IsPaused(self):
        return xbmc.getCondVisibility("Player.Paused")

    def Player_WatchTimes(self):
        error = ""
        watchedTime = "0"
        videoDuration = "0"
        try:
            watchedTime = str(XBMC_PLAYER.getTime())
            videoDuration = str(XBMC_PLAYER.getTotalTime())
            log.debug("Watched: %s, duration: %s" % (watchedTime, videoDuration))
        except Exception as e:
            error = "Stopped playing: %s" % repr(e)

        watchTimes = {
            "watchedTime": watchedTime,
            "videoDuration": videoDuration,
            "error": error
        }
        return watchTimes

    def ConvertLanguage(self, *args, **kwargs):
        return xbmc.convertLanguage(*args, **kwargs)

    def GetPlatform(self):
        return PLATFORM

    def GetAddonInfo(self):
        info = {}
        for key in ("author", "changelog", "description", "disclaimer",
                    "fanart", "icon", "id", "name", "path", "profile", "stars",
                    "summary", "type", "version"):
            info[key] = ADDON.getAddonInfo(key)
        return info

    def AddonFailure(self, addonId):
        if ADDON.getSetting("provider_disable_failing") == u"false":
            return 0

        if addonId in self._failures:
            self._failures[addonId] += 1
        else:
            self._failures[addonId] = 1

        log.warning("Recorded failure %d for %s" % (self._failures[addonId], addonId))

        if self._failures[addonId] > int(ADDON.getSetting("provider_allowed_failures")):
            try:
                time.sleep(10)
                notify(getLocalizedString(30111))
                urllib2.urlopen("%s/provider/%s/disable" % (QUASARD_HOST, addonId))
            except:
                notify(getLocalizedString(30112))
                return 0
        return self._failures[addonId]

    def AddonCheck(self, addonId):
        if addonId in self._failures:
            return self._failures[addonId]
        return 0

    def AddonSettings(self, addonId):
        return xbmc.executebuiltin("Addon.OpenSettings(%s)" % addonId)

    def GetLanguage(self, *args, **kwargs):
        return xbmc.getLanguage(*args, **kwargs)

    def GetLocalizedString(self, *args, **kwargs):
        return ADDON.getLocalizedString(*args, **kwargs).encode('utf-8', 'ignore')

    def GetSetting(self, *args, **kwargs):
        return ADDON.getSetting(*args, **kwargs)

    def GetAllSettings(self):
        settings = []
        settingsFile = os.path.join(ADDON.getAddonInfo("path"), "resources", "settings.xml")
        with open(settingsFile, 'r') as settingsStr:
            fileContent = settingsStr.read()
            keyType = re.findall(r".*id=\"(\w+)\".*type=\"(\w+)\"", fileContent)
        for key, _type in keyType:
            settings.append({
                "key": key,
                "type": _type,
                "value": ADDON.getSetting(key)
            })
        return settings

    def SetSetting(self, *args, **kwargs):
        return ADDON.setSetting(*args, **kwargs)

    def GetCurrentView(self):
        skinPath = xbmc.translatePath('special://skin/')
        xml = os.path.join(skinPath, 'addon.xml')
        f = xbmcvfs.File(xml)
        read = f.read()
        f.close()
        try:
            src = re.search('defaultresolution="([^"]+)', read, re.DOTALL).group(1)
        except:
            src = re.search('<res.+?folder="([^"]+)', read, re.DOTALL).group(1)
        src = os.path.join(skinPath, src, 'MyVideoNav.xml')
        f = xbmcvfs.File(src)
        read = f.read()
        f.close()
        match = re.search('<views>([^<]+)', read, re.DOTALL)
        if match:
            views = match.group(1)
            log.info("Skin's ViewModes: %s" % views)
            for view in views.split(','):
                if xbmc.getInfoLabel('Control.GetLabel(%s)' % view):
                    return view

    def TranslatePath(self, *args, **kwargs):
        return xbmc.translatePath(*args, **kwargs)

    def Log(self, *args, **kwargs):
        return xbmc.log(*args, **kwargs)

    def Dialog_CloseAll(self, *args, **kwargs):
        return xbmc.executebuiltin("Dialog.Close(all, true)")

    def DialogInsert(self, *args, **kwargs):
        window = DialogInsert("DialogInsert.xml", ADDON_PATH, "Default")
        window.doModal()
        retval = {"type": ("cancelled", "url", "file")[window.type], "path": window.retval}
        del window
        return retval

    ###########################################################################
    # DialogProgress
    ###########################################################################
    def DialogProgress_Create(self, *args, **kwargs):
        dialog = xbmcgui.DialogProgress()
        self._objects[id(dialog)] = dialog
        dialog.create(*args, **kwargs)
        return id(dialog)

    def DialogProgress_IsCanceled(self, hwnd, *args, **kwargs):
        return self._objects[hwnd].iscanceled(*args, **kwargs)

    def DialogProgress_Update(self, hwnd, *args, **kwargs):
        return self._objects[hwnd].update(*args, **kwargs)

    def DialogProgress_Close(self, hwnd, *args, **kwargs):
        dialog = self._objects.pop(hwnd)
        dialog.close()
        del dialog

    # Background DialogProgress
    def DialogProgressBG_Create(self, *args, **kwargs):
        dialog = xbmcgui.DialogProgressBG()
        self._objects[id(dialog)] = dialog
        dialog.create(*args, **kwargs)
        return id(dialog)

    def DialogProgressBG_IsFinished(self, hwnd, *args, **kwargs):
        return self._objects[hwnd].isFinished(*args, **kwargs)

    def DialogProgressBG_Update(self, hwnd, *args, **kwargs):
        return self._objects[hwnd].update(*args, **kwargs)

    def DialogProgressBG_Close(self, hwnd, *args, **kwargs):
        dialog = self._objects.pop(hwnd)
        dialog.close()
        del dialog

    # Overlay status
    def OverlayStatus_Create(self):
        overlay = OverlayText()
        overlayId = id(overlay)
        self._objects[overlayId] = overlay
        return overlayId

    def OverlayStatus_Update(self, hwnd, percent, line1, line2, line3):
        text = "\n".join([line1, line2, line3])
        self._objects[hwnd].text = text

    def OverlayStatus_Show(self, hwnd):
        self._objects[hwnd].show()

    def OverlayStatus_Hide(self, hwnd):
        self._objects[hwnd].hide()

    def OverlayStatus_Close(self, hwnd):
        overlay = self._objects.pop(hwnd)
        overlay.hide()
        del overlay


def server_thread():
    try:
        s = bjsonrpc.createserver(port=JSONRPC_EXT_PORT, handler_factory=QuasarRPCServer)
        log.info("quasar: starting jsonrpc service")
        s.serve()
        log.info("quasar: exiting jsonrpc service")
    except Exception:
        import traceback
        map(log.error, traceback.format_exc().split("\n"))
        raise
