'''
Video Gstplayer
===============

.. versionadded:: 1.8.0

Implementation of a VideoBase with Kivy :class:`~kivy.lib.gstplayer.GstPlayer`
This player is the preferred player, using Gstreamer 1.0, working with python 3.
'''

try:
    from kivy.lib.gstplayer import GstPlayer, get_gst_version
except ImportError:
    from kivy.core import handle_win_lib_import_error
    handle_win_lib_import_error(
        'VideoGstplayer', 'gst', 'kivy.lib.gstplayer._gstplayer')
    raise
from kivy.graphics.texture import Texture
from kivy.core.video import VideoBase
from kivy.logger import Logger
from kivy.clock import Clock
from threading import Lock
from functools import partial
from os.path import realpath
from weakref import ref
from urllib.request import pathname2url

Logger.info('VideoGstplayer: Using Gstreamer {}'.format(
    '.'.join(map(str, get_gst_version()))))


def _on_gstplayer_buffer(video, width, height, data):
    video = video()
    # if we still receive the video but no more player, remove it.
    if not video:
        return
    with video._buffer_lock:
        video._buffer = (width, height, data)


def _on_gstplayer_message(mtype, message):
    if mtype == 'error':
        Logger.error('VideoGstplayer: {}'.format(message))
    elif mtype == 'warning':
        Logger.warning('VideoGstplayer: {}'.format(message))
    elif mtype == 'info':
        Logger.info('VideoGstplayer: {}'.format(message))


class VideoGstplayer(VideoBase):

    def __init__(self, **kwargs):
        self.player = None
        self._buffer = None
        self._buffer_lock = Lock()
        super(VideoGstplayer, self).__init__(**kwargs)

    def _on_gst_eos_sync(self):
        Clock.schedule_once(self._do_eos, 0)

    def load(self):
        Logger.debug('VideoGstplayer: Load <{}>'.format(self._filename))
        uri = self._get_uri()
        wk_self = ref(self)
        self.player_callback = partial(_on_gstplayer_buffer, wk_self)
        self.player = GstPlayer(uri, self.player_callback,
                                self._on_gst_eos_sync, _on_gstplayer_message)
        self.player.load()

    def unload(self):
        if self.player:
            self.player.unload()
            self.player = None
        with self._buffer_lock:
            self._buffer = None
        self._texture = None

    def stop(self):
        super(VideoGstplayer, self).stop()
        self.player.stop()

    def pause(self):
        super(VideoGstplayer, self).pause()
        self.player.pause()

    def play(self):
        super(VideoGstplayer, self).play()
        self.player.set_volume(self.volume)
        self.player.play()

    def seek(self, percent, precise=True):
        self.player.seek(percent)

    def _get_position(self):
        return self.player.get_position()

    def _get_duration(self):
        return self.player.get_duration()

    def _set_volume(self, value):
        self._volume = value
        if self.player:
            self.player.set_volume(self._volume)

    def _update(self, dt):
        buf = None
        with self._buffer_lock:
            buf = self._buffer
            self._buffer = None
        if buf is not None:
            self._update_texture(buf)
            self.dispatch('on_frame')

    def _update_texture(self, buf):
        width, height, data = buf

        # texture is not allocated yet, create it first
        if not self._texture:
            self._texture = Texture.create(size=(width, height),
                                           colorfmt='rgb')
            self._texture.flip_vertical()
            self.dispatch('on_load')

        if self._texture:
            self._texture.blit_buffer(
                data, size=(width, height), colorfmt='rgb')

    def _get_uri(self):
        uri = self.filename
        if not uri:
            return
        if '://' not in uri:
            uri = 'file:' + pathname2url(realpath(uri))
        return uri
