# -*- coding: utf-8 -*-

"""

    Copyright (C) 2013-2014 Team-XBMC
    Copyright (C) 2014-2019 Team Kodi

    This file is part of service.xbmc.versioncheck

    SPDX-License-Identifier: GPL-3.0-or-later
    See LICENSES/GPL-3.0-or-later.txt for more information.

"""

import sys

import xbmc  # pylint: disable=import-error
import xbmcaddon  # pylint: disable=import-error
import xbmcgui  # pylint: disable=import-error
import xbmcvfs  # pylint: disable=import-error

try:
    xbmc.translatePath = xbmcvfs.translatePath
except AttributeError:
    pass

ADDON = xbmcaddon.Addon('service.xbmc.versioncheck')
ADDON_VERSION = ADDON.getAddonInfo('version')
ADDON_NAME = ADDON.getAddonInfo('name')
if sys.version_info[0] >= 3:
    ADDON_PATH = ADDON.getAddonInfo('path')
    ADDON_PROFILE = xbmc.translatePath(ADDON.getAddonInfo('profile'))
else:
    ADDON_PATH = ADDON.getAddonInfo('path').decode('utf-8')
    ADDON_PROFILE = xbmc.translatePath(ADDON.getAddonInfo('profile')).decode('utf-8')
ICON = ADDON.getAddonInfo('icon')
KODI_VERSION_MAJOR = int(xbmc.getInfoLabel('System.BuildVersion')[0:2])

MONITOR = xbmc.Monitor()


# Fixes unicode problems
def string_unicode(text, encoding='utf-8'):
    """ Python 2/3 -> unicode/str

    :param text: text to convert
    :type text: unicode (py2) / str (py3) / bytes (py3)
    :param encoding: text encoding
    :type encoding: str
    :return: converted text
    :rtype: unicode (py2) / str (py3)
    """
    try:
        if sys.version_info[0] >= 3:
            text = str(text)
        else:
            text = unicode(text, encoding)  # pylint: disable=undefined-variable
    except:  # pylint: disable=bare-except
        pass
    return text


def normalize_string(text):
    """ Normalize string

    :param text: text to normalize
    :type text: unicode (py2) / str (py3) / bytes (py3)
    :return: normalized text
    :rtype: unicode (py2) / str (py3)
    """
    try:
        text = unicodedata.normalize('NFKD', string_unicode(text)).encode('ascii', 'ignore')  # pylint: disable=undefined-variable
    except:  # pylint: disable=bare-except
        pass
    return text


def localise(string_id):
    """ Localise string id

    :param string_id: id of the string to localise
    :type string_id: int
    :return: localised string
    :rtype: unicode (py2) / str (py3)
    """
    string = normalize_string(ADDON.getLocalizedString(string_id))
    return string


def log(txt):
    """ Log text at xbmc.LOGDEBUG level

    :param txt: text to log
    :type txt: str / unicode / bytes (py3)
    """
    if sys.version_info[0] >= 3:
        if isinstance(txt, bytes):
            txt = txt.decode('utf-8')
        message = '%s: %s' % (ADDON_NAME, txt)
    else:
        if isinstance(txt, str):
            txt = txt.decode('utf-8')
        message = (u'%s: %s' % (ADDON_NAME, txt)).encode('utf-8')  # pylint: disable=redundant-u-string-prefix
    xbmc.log(msg=message, level=xbmc.LOGDEBUG)


def notification(heading, message, icon=None, time=15000, sound=True):
    """ Create a notification

    :param heading: notification heading
    :type heading: str
    :param message: notification message
    :type message: str
    :param icon: path and filename for the notification icon
    :type icon: str
    :param time: time to display notification
    :type time: int
    :param sound: is notification audible
    :type sound: bool
    """
    if not icon:
        icon = ICON
    xbmcgui.Dialog().notification(heading, message, icon, time, sound)


def get_password_from_user():
    """ Prompt user to input password

    :return: password
    :rtype: str
    """
    pwd = ''
    keyboard = xbmc.Keyboard('', ADDON_NAME + ': ' + localise(32022), True)
    keyboard.doModal()
    if keyboard.isConfirmed():
        pwd = keyboard.getText()
    return pwd


def message_upgrade_success():
    """ Upgrade success notification
    """
    notification(ADDON_NAME, localise(32013))


def message_restart():
    """ Prompt user to restart Kodi
    """
    if dialog_yes_no(32014):
        xbmc.executebuiltin('RestartApp')


def dialog_yes_no(line1=0, line2=0):
    """ Prompt user with yes/no dialog

    :param line1: string id for the first line of the dialog
    :type line1: int
    :param line2: string id for the second line of the dialog
    :type line2: int
    :return: users selection (yes / no)
    :rtype: bool
    """
    return xbmcgui.Dialog().yesno(ADDON_NAME, '[CR]'.join([localise(line1), localise(line2)]))


def linux_upgrade_message(msg):
    """ Prompt user with upgrade suggestion message

    :param msg: string id for prompt message
    :type msg: int
    """
    wait_for_end_of_video()

    if ADDON.getSetting('lastnotified_version') < ADDON_VERSION:
        answer = xbmcgui.Dialog().ok(
            ADDON_NAME,
            '[CR]'.join([localise(msg), localise(32001), localise(32002)])
        )
    else:
        answer = False
        log('Already notified one time for upgrading.')

    return answer


def non_linux_upgrade_message(version_installed, version_available, version_stable, old_version):
    """ Prompt user with upgrade suggestion message

    :param version_installed: currently installed version
    :type version_installed: dict
    :param version_available: available version
    :type version_available: dict
    :param version_stable: latest stable version
    :type version_stable: dict
    :param old_version: whether using an old version
    :type old_version: bool / 'stable'
    """
    # shorten releasecandidate to rc
    if version_installed['tag'] == 'releasecandidate':
        version_installed['tag'] = 'rc'
    if version_available['tag'] == 'releasecandidate':
        version_available['tag'] = 'rc'
    # convert json-rpc result to strings for usage
    msg_current = '%i.%i %s%s' % (version_installed['major'],
                                  version_installed['minor'],
                                  version_installed['tag'],
                                  version_installed.get('tagversion', ''))
    msg_available = version_available['major'] + '.' + version_available['minor'] + ' ' + \
                    version_available['tag'] + version_available.get('tagversion', '')
    msg_stable = version_stable['major'] + '.' + version_stable['minor'] + ' ' + \
                 version_stable['tag'] + version_stable.get('tagversion', '')
    msg = localise(32034) % (msg_current, msg_available)

    wait_for_end_of_video()

    # hack: convert current version number to stable string
    # so users don't get notified again. remove in future
    if ADDON.getSetting('lastnotified_version') == '0.1.24':
        ADDON.setSetting('lastnotified_stable', msg_stable)

    # Show different dialogs depending on if there's a newer stable available.
    # Also split them between xbmc and kodi notifications to reduce possible confusion.
    # People will find out once they visit the website.
    # For stable only notify once and when there's a newer stable available.
    # Ignore any add-on updates as those only count for != stable
    if old_version == 'stable' and ADDON.getSetting('lastnotified_stable') != msg_stable:
        xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32032), localise(32033)]))
        ADDON.setSetting('lastnotified_stable', msg_stable)

    elif old_version != 'stable' and ADDON.getSetting('lastnotified_version') != msg_available:
        xbmcgui.Dialog().ok(ADDON_NAME, '[CR]'.join([msg, localise(32035), localise(32033)]))

        ADDON.setSetting('lastnotified_version', msg_available)

    else:
        log('Already notified one time for upgrading.')


def abort_requested():
    """ Kodi 13+ compatible xbmc.Monitor().abortRequested()

    :return: whether abort requested
    :rtype: bool
    """
    if KODI_VERSION_MAJOR > 13:
        return MONITOR.abortRequested()

    return xbmc.abortRequested


def wait_for_abort(seconds):
    """ Kodi 13+ compatible xbmc.Monitor().waitForAbort()

    :param seconds: seconds to wait for abort
    :type seconds: int / float
    :return: whether abort was requested
    :rtype: bool
    """
    if KODI_VERSION_MAJOR > 13:
        return MONITOR.waitForAbort(seconds)

    for _ in range(0, seconds * 1000 / 200):
        if xbmc.abortRequested:
            return True
        xbmc.sleep(200)

    return False


def wait_for_end_of_video():
    """ Wait for video playback to end
    """
    # Don't show notify while watching a video
    while xbmc.Player().isPlayingVideo() and not abort_requested():
        if wait_for_abort(1):
            # Abort was requested while waiting. We should exit
            break
    i = 0
    while i < 10 and not abort_requested():
        if wait_for_abort(1):
            # Abort was requested while waiting. We should exit
            break
        i += 1
