# 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

from gettext import gettext as _

from lollypop.widgets_playlist_smart import SmartPlaylistRow
from lollypop.widgets_playlist_edit import PlaylistEditWidget
from lollypop.view import View
from lollypop.logger import Logger
from lollypop.define import App, Sizing


class SmartPlaylistView(View):
    """
        Show a view allowing user to create a smart playlist
    """

    def __init__(self, playlist_id):
        """
            Init PlaylistView
            @param playlist_id as int
        """
        View.__init__(self, False)
        self.__playlist_id = playlist_id
        self.__size_group = Gtk.SizeGroup()
        self.__size_group.set_mode(Gtk.SizeGroupMode.BOTH)
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Lollypop/SmartPlaylistView.ui")
        builder.connect_signals(self)
        widget = builder.get_object("widget")
        grid = Gtk.Grid()
        grid.set_orientation(Gtk.Orientation.VERTICAL)
        grid.show()
        grid.add(widget)
        self.__playlist_editor = PlaylistEditWidget(playlist_id)
        self.__playlist_editor.set_property("halign", Gtk.Align.CENTER)
        grid.add(self.__playlist_editor)
        self.connect("size-allocate", self.__on_size_allocate)
        self._viewport.add(grid)
        self.__listbox = builder.get_object("listbox")
        self._scrolled.set_property("expand", True)
        self.__match_toggle = builder.get_object("match_toggle")
        self.__operand_combobox = builder.get_object("operand_combobox")
        self.__select_combobox = builder.get_object("select_combobox")
        self.__limit_spin = builder.get_object("limit_spin")
        self.__add_rule_button = builder.get_object("add_rule_button")
        self.__top_box = builder.get_object("top_box")
        self.__sub_top_box = builder.get_object("sub_top_box")
        self.__bottom_box = builder.get_object("bottom_box")
        if App().playlists.get_smart(playlist_id):
            self.__match_toggle.set_active(True)
        else:
            self.__playlist_editor.populate()
            self.__playlist_editor.show()
        self.add(self._scrolled)

    def populate(self):
        """
            Setup an initial widget based on current request
        """
        sql = App().playlists.get_smart_sql(self.__playlist_id)
        if sql is None:
            return
        try:
            if sql.find(" UNION ") != -1:
                operand = "OR"
            else:
                operand = "AND"
            self.__operand_combobox.set_active_id(operand)
        except Exception as e:
            self.__operand_combobox.set_active(0)
            Logger.warning("SmartPlaylistView::populate: %s", e)
        # Setup rows
        for line in sql.split("((")[1:]:
            widget = SmartPlaylistRow(self.__size_group)
            try:
                widget.set(line.split("))")[0])
            except Exception as e:
                Logger.error("SmartPlaylistView::populate: %s", e)
            widget.show()
            self.__listbox.add(widget)
        try:
            split_limit = sql.split("LIMIT")
            limit = int(split_limit[1].split(" ")[1])
            self.__limit_spin.set_value(limit)
        except Exception as e:
            Logger.warning("SmartPlaylistView::populate: %s", e)
        try:
            split_order = sql.split("ORDER BY")
            split_spaces = split_order[1].split(" ")
            orderby = split_spaces[1]
            # UNION does not support RANDOM() in OrderBy
            if orderby == "rand":
                orderby = "random()"
            if split_spaces[2] in ["ASC", "DESC"]:
                orderby += " %s" % split_spaces[2]
            self.__select_combobox.set_active_id(orderby)
        except Exception as e:
            self.__select_combobox.set_active(0)
            Logger.warning("SmartPlaylistView::populate: %s", e)

#######################
# PROTECTED           #
#######################
    def __get_or_request(self):
        """
            Get request for AND operand
            @return str
        """
        request = ""
        orderby = self.__select_combobox.get_active_id()
        for child in self.__listbox.get_children():
            if child.sql is None:
                continue
            request += "SELECT DISTINCT(tracks.rowid)"
            if orderby == "random()":
                request += ", random() as rand"
            else:
                request += ", %s" % orderby
            request += " FROM tracks"
            subrequest = " WHERE %s" % child.sql
            if subrequest.find("genres.") != -1:
                request += ", %s" % "genres"
            if subrequest.find("artists.") != -1:
                request += ", %s" % "artists"
            if subrequest.find("albums.") != -1:
                request += ", %s" % "albums"
            if subrequest.find("track_genres.") != -1:
                request += ", %s" % "track_genres"
            if subrequest.find("track_artists.") != -1:
                request += ", %s" % "track_artists"
            request += subrequest + " UNION "
        request = request[:-7]  # " UNION "
        if orderby == "random()":
            request += " ORDER BY rand"
        else:
            request += " ORDER BY %s" % orderby
        request += " LIMIT %s" % int(self.__limit_spin.get_value())
        return request

    def __get_and_request(self):
        """
            Get request for AND operand
            @return str
        """
        request = "SELECT DISTINCT(tracks.rowid) FROM tracks"
        subrequest = " WHERE"
        for child in self.__listbox.get_children():
            if child.sql is not None:
                subrequest += " %s AND" % child.sql
        subrequest = subrequest[:-3]
        if subrequest.find("genres.") != -1:
            request += ", %s" % "genres"
        if subrequest.find("artists.") != -1:
            request += ", %s" % "artists"
        if subrequest.find("albums.") != -1:
            request += ", %s" % "albums"
        if subrequest.find("track_genres.") != -1:
            request += ", %s" % "track_genres"
        if subrequest.find("track_artists.") != -1:
            request += ", %s" % "track_artists"
        orderby = self.__select_combobox.get_active_id()
        subrequest += " ORDER BY %s" % orderby
        subrequest += " LIMIT %s" % int(self.__limit_spin.get_value())
        return request + subrequest

    def _on_save_button_clicked(self, button):
        """
            Save SQL request
            @param button as Gtk.Button
        """
        operand = self.__operand_combobox.get_active_id()
        if len(self.__listbox.get_children()) == 0:
            request = ""
            App().playlists.set_smart(self.__playlist_id, False)
        elif operand == "AND":
            request = self.__get_and_request()
        else:
            request = self.__get_or_request()
        App().playlists.set_smart_sql(self.__playlist_id, request)
        # FIXME
        App().window.container.reload_view()

    def _on_add_rule_button_clicked(self, button):
        """
            Add a new rule
            @param button as Gtk.Button
        """
        self.__populate()

    def _on_match_check_button_toggled(self, button):
        """
            Enable/Disable smart playlist
            @param button as GtkButton
        """
        App().playlists.set_smart(self.__playlist_id, button.get_active())
        if button.get_active():
            button.set_label(_("Match music for "))
            self.__sub_top_box.show()
            self.__bottom_box.show()
            self.__add_rule_button.show()
            self.__listbox.show()
            self.__playlist_editor.hide()
        else:
            button.set_label(_("Smart playlist"))
            self.__sub_top_box.hide()
            self.__bottom_box.hide()
            self.__add_rule_button.hide()
            self.__listbox.hide()
            self.__playlist_editor.populate()
            self.__playlist_editor.show()

    def _on_map(self, widget):
        """
            Disable global shortcuts
            @param widget as Gtk.Widget
        """
        if App().settings.get_value("show-sidebar"):
            App().window.emit("can-go-back-changed", True)
            App().window.emit("show-can-go-back", True)

#######################
# PRIVATE             #
#######################
    def __populate(self):
        """
            Setup an initial widget
        """
        widget = SmartPlaylistRow(self.__size_group)
        widget.show()
        self.__listbox.add(widget)

    def __on_size_allocate(self, widget, allocation):
        """
            Set child widget size
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if allocation.width < Sizing.BIG:
            self.__top_box.set_orientation(Gtk.Orientation.VERTICAL)
            self.__bottom_box.set_orientation(Gtk.Orientation.VERTICAL)
        else:
            self.__top_box.set_orientation(Gtk.Orientation.HORIZONTAL)
            self.__bottom_box.set_orientation(Gtk.Orientation.HORIZONTAL)
        width = max(Sizing.SMALL - 100, allocation.width / 2)
        self.__playlist_editor.set_size_request(width, -1)
