# Copyright (c) 2014-2018 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
# 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 3 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, see <http://www.gnu.org/licenses/>.

from gi.repository import Gtk, GLib

from lollypop.define import App
from lollypop.widgets_utils import Popover
from lollypop.objects import Track
from lollypop.widgets_row_queue import QueueRow


class QueuePopover(Popover):
    """
        Popover showing queue
    """

    def __init__(self):
        """
            Init Popover
        """
        Popover.__init__(self)
        self.set_position(Gtk.PositionType.BOTTOM)
        self.__last_drag_id = None
        self.connect("map", self.__on_map)
        self.connect("unmap", self.__on_unmap)

        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/QueuePopover.ui")
        builder.connect_signals(self)

        self.__clear_button = builder.get_object("clear-button")

        self.__view = Gtk.ListBox()
        self.__view.get_style_context().add_class("trackswidget")
        self.__view.set_selection_mode(Gtk.SelectionMode.NONE)
        self.__view.set_activate_on_single_click(True)
        self.__view.connect("row-activated", self.__on_row_activated)
        self.__view.show()

        builder.get_object("scrolled").add(self.__view)
        self.add(builder.get_object("widget"))

    def populate(self):
        """
            Populate widget with queue rows
        """
        if App().player.queue:
            self.__clear_button.set_sensitive(True)
        self.__add_items(list(App().player.queue))

#######################
# PROTECTED           #
#######################
    def _on_button_clicked(self, widget):
        """
            Clear queue
            @param widget as Gtk.Button
        """
        self.__stop = True
        self.__clear(True)
        self.hide()

#######################
# PRIVATE             #
#######################
    def __clear(self, clear_queue=False):
        """
            Clear the view
        """
        for child in self.__view.get_children():
            child.destroy()
        if clear_queue:
            App().player.clear_queue()

    def __add_items(self, items, previous_row=None):
        """
            Add items to the view
            @param item ids as [int]
            @param previous_row as QueueRow
        """
        if items and not self.__stop:
            track_id = items.pop(0)
            row = self.__row_for_track_id(track_id)
            row.set_previous_row(previous_row)
            if previous_row is not None:
                previous_row.set_next_row(row)
            self.__view.add(row)
            GLib.idle_add(self.__add_items, items, row)

    def __row_for_track_id(self, track_id):
        """
            Get a row for track id
            @param track id as int
        """
        row = QueueRow(Track(track_id))
        row.connect("insert-track", self.__on_insert_track)
        row.connect("remove-track", self.__on_remove_track)
        return row

    def __on_map(self, widget):
        """
            Connect signals, populate, and resize
            @param widget as Gtk.Widget
        """
        self.__stop = False
        window_size = App().window.get_size()
        height = window_size[1]
        width = min(500, window_size[0])
        self.set_size_request(width, height * 0.7)
        self.populate()
        self._signal_id1 = App().player.connect("current-changed",
                                                self.__on_current_changed)
        self.set_sensitive(not App().player.is_locked)

    def __on_unmap(self, widget):
        """
            Disconnect signals
            @param widget as Gtk.Widget
        """
        self.__clear()
        self.__stop = True
        if self._signal_id1 is not None:
            App().player.disconnect(self._signal_id1)
            self._signal_id1 = None

    def __on_current_changed(self, player):
        """
            Pop first item in queue if it"s current track id
            @param player object
        """
        if len(self.__view.get_children()) > 0:
            row = self.__view.get_children()[0]
            if row.id == player.current_track.id:
                row.destroy()

    def __on_child_destroyed(self, row):
        """
            Check clear button aspect
            @param row as QueueRow
        """
        self.__clear_button.set_sensitive(len(self.__view.get_children()) != 0)

    def __on_row_activated(self, widget, row):
        """
            Play item
            @param widget as Gtk.ListBox
            @param row as QueueRow
        """
        if not App().player.is_locked:
            App().player.load(Track(row.id))
            GLib.idle_add(row.destroy)

    def __on_insert_track(self, row, new_track_id, down):
        """
            Insert a new row at position
            @param row as PlaylistRow
            @param new_track_id as int
            @param down as bool
        """
        self.__last_drag_id = new_track_id
        position = self.__view.get_children().index(row)
        new_row = self.__row_for_track_id(new_track_id)
        new_row.show()
        if down:
            position += 1
        self.__view.insert(new_row, position)
        App().player.insert_in_queue(new_row.track.id, position)
        if down:
            new_row.set_previous_row(row)
            new_row.set_next_row(row.next_row)
            if row.next_row is not None:
                row.next_row.set_previous_row(new_row)
            row.set_next_row(new_row)
        else:
            new_row.set_previous_row(row.previous_row)
            new_row.set_next_row(row)
            if row.previous_row is not None:
                row.previous_row.set_next_row(new_row)
            row.set_previous_row(new_row)

    def __on_remove_track(self, row):
        """
            Remove row's track
            @param row as PlaylistRow
        """
        if row.track.id != self.__last_drag_id:
            App().player.remove_from_queue(row.track.id)
        if row.previous_row is None:
            row.next_row.set_previous_row(None)
        elif row.next_row is None:
            row.previous_row.set_next_row(None)
        else:
            row.next_row.set_previous_row(row.previous_row)
            row.previous_row.set_next_row(row.next_row)
        self.__last_drag_id = None
