# -*- coding: utf-8 -*-
#
#       media_overlays/vlc.py
#
#       Copyright 2018 Cimbali <me@cimba.li>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
#
"""
:mod:`pympress.media_overlays.vlc` -- widget to play videos using VLC
---------------------------------------------------------------------
"""

from __future__ import print_function, unicode_literals

import logging
logger = logging.getLogger(__name__)

import os
import vlc

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import GLib

from pympress.util import IS_WINDOWS
from pympress.media_overlays import base


class VlcOverlay(base.VideoOverlay):
    """ Simple VLC widget.

    Its player can be controlled through the 'player' attribute, which is a :class:`~vlc.MediaPlayer` instance.
    """

    #: A single vlc.Instance() to be shared by (possible) multiple players.
    _instance = None

    def __init__(self, *args, **kwargs):
        self.player = self._instance.media_player_new()  # before loading UI, needed to connect "map" signal

        super(VlcOverlay, self).__init__(*args, **kwargs)

        event_manager = self.player.event_manager()
        event_manager.event_attach(vlc.EventType.MediaPlayerEndReached, lambda e: GLib.idle_add(self.hide))
        event_manager.event_attach(vlc.EventType.MediaPlayerLengthChanged,
                                   lambda e: self.update_range(self.player.get_length() / 1000. or 1.))
        event_manager.event_attach(vlc.EventType.MediaPlayerTimeChanged,
                                   lambda e: self.update_progress(self.player.get_time() / 1000. or 1.))


    def handle_embed(self, mapped_widget):
        """ Handler to embed the VLC player in the window, connected to the :attr:`~.Gtk.Widget.signals.map` signal.
        """
        # Do we need to be on the main thread? (especially for the mess from the win32 window handle)
        # assert(isinstance(threading.current_thread(), threading._MainThread))
        if IS_WINDOWS:
            self.player.set_hwnd(base.get_window_handle(self.movie_zone.get_window()))  # get_property('window')
        else:
            self.player.set_xwindow(self.movie_zone.get_window().get_xid())
        return False


    def is_playing(self):
        """ Returns whether the media is currently playing (and not paused).

        Returns:
            `bool`: `True` iff the media is playing.
        """
        return self.player.is_playing()


    def set_file(self, filepath):
        """ Sets the media file to be played by the widget.

        Args:
            filepath (`str`): The path to the media file path
        """
        self.player.set_media(self._instance.media_new(filepath))


    def mute(self, value):
        """ Mutes the player.

        Args:
            value (`bool`): `True` iff this player should be muted
        """
        GLib.idle_add(self.player.audio_set_volume, 0 if value else 100)
        return False


    def do_play(self):
        """ Start playing the media file.

        Should run on the main thread to ensure we avoid vlc plugins' reentrency problems.

        Returns:
            `bool`: `True` iff this function should be run again (:func:`~GLib.idle_add` convention)
        """
        self.player.play()
        return False


    def do_play_pause(self):
        """ Toggle pause mode of the media.

        Should run on the main thread to ensure we avoid vlc plugins' reentrency problems.

        Returns:
            `bool`: `True` iff this function should be run again (:func:`~GLib.idle_add` convention)
        """
        self.player.pause() if self.player.is_playing() else self.player.play()
        return False


    def do_stop(self):
        """ Stops playing in the backend player.
        """
        self.player.stop()


    def do_set_time(self, t):
        """ Set the player at time t.

        Should run on the main thread to ensure we avoid vlc plugins' reentrency problems.

        Args:
            t (`float`): the timestamp, in s

        Returns:
            `bool`: `True` iff this function should be run again (:func:`~GLib.idle_add` convention)
        """
        self.player.set_time(int(round(t * 1000.)))
        return False


    @classmethod
    def setup_backend(cls, vlc_opts = ['--no-video-title-show']):
        """ Prepare/check the VLC backend.

        Args:
            vlc_opts (`list`): the arguments for starting vlc

        Returns:
            `str`: the version of VLC used by the backend
        """
        if IS_WINDOWS and vlc.plugin_path:
            # let python find the DLLs
            os.environ['PATH'] = vlc.plugin_path + ';' + os.environ['PATH']

        VlcOverlay._instance = vlc.Instance(vlc_opts)
        return 'VLC {}'.format(vlc.libvlc_get_version().decode('ascii'))