"""
Pympc is a client for Music Player Daemon.
Copyright (C) 2004  Magnus Bjernstad <bjernstad@gmail.com>

This file is part of Pympc.

Pympc 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.

Pympc 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 Pympc; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""
import gtk, mpdclient, os, base_dialog

TYPE = {'file': 0,
        'dir': 1,
        'parent': 2,
        'playlist': 3}
class Library:
    library_dir = ''
    pos_stack = []

    def __init__(self, app, gui_file):
        self.app = app
        self.gui_popup = gtk.glade.XML(gui_file, 'lib_popup')
        self.gui_popup.signal_autoconnect(self)

        self.gui_main = gtk.glade.XML(gui_file, 'lib_root')
        self.gui_main.signal_autoconnect(self)
        self.w = self.gui_main.get_widget
        self.contents = self.w('lib_root')

        self.tree =  gtk.ListStore(str, int)
        cell = gtk.CellRendererText()
        column  = gtk.TreeViewColumn( 'Library', cell, text=0)
        column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
        self.w('view').set_model(self.tree)
        self.w('view').get_selection().set_mode(gtk.SELECTION_MULTIPLE)
        self.w('view').append_column(column)

    def reload(self):
        l = self.tree
        l.clear()
        self.w('cwd').set_text(self.library_dir)
        if self.library_dir != '':
            l.append([os.pardir, TYPE['parent']])
        try:
            for entry in self.app.c.ls([self.library_dir], onlyDirs=True):
                l.append([os.path.split(entry)[1], TYPE['dir']])
            for entry in self.app.c.ls([self.library_dir], onlyFiles=True):
                l.append([os.path.split(entry)[1], TYPE['file']])
            if self.library_dir == '':
                for entry in self.app.c.getPlaylistNames():
                    l.append(['*%s*' % entry.file , TYPE['playlist']])
        except mpdclient.MpdError:
            self.app.c = False

    def enqueue(self, list, is_playlist=False):
        if not self.app.c:
            return
        try:
            if is_playlist:
                self.app.c.load(list)
            else:
                self.app.c.add(list)
        except mpdclient.MpdError:
            self.app.c = False

    def enqueue_selection(self, tree_selection):
        if tree_selection.get_tree_view().get_model().get_iter_first() == None:
            return
        (model, paths) = tree_selection.get_selected_rows()

        songs = filter(lambda x: model[x][1] in (TYPE['file'], TYPE['dir']), paths)
        playlists = filter(lambda x: model[x][1] == TYPE['playlist'], paths)
        self.enqueue([os.path.join(self.library_dir, model[x][0]) for x in songs])
        self.enqueue([model[x][0][1:-1] for x in playlists], is_playlist=True)

    def play(self):
        if not self.app.c:
            return
        tree_selection = self.w('view').get_selection()
        try:
            self.app.c.clear()
            self.enqueue_selection(tree_selection)
            self.app.c.play()
        except mpdclient.MpdError:
            self.app.c = False

    def update(self):
        if not self.app.c:
            return
        try:
           self.app.c.update()
        except mpdclient.MpdError:
            self.app.c = False

    def delete(self, playlist):
        try:
            self.app.c.rm(playlist)
            self.reload()
        except mpdclient.MpdError:
            self.app.c = False

    def change_dir(self, index):
        if not self.app.c:
            return
        new_path = os.path.normpath(os.path.join(self.library_dir, self.tree[index][0]))
        entry_type = self.tree[index][1]

        try:
            if entry_type == TYPE['dir']:
                self.pos_stack.append((self.first_visible_row(), index))
                self.app.c.ls([new_path])
                self.library_dir = new_path
                self.reload()
                self.scroll_to_cell(0)
            elif entry_type == TYPE['parent']:
                if new_path == os.curdir: new_path = ""
                self.app.c.ls([new_path])
                self.library_dir = new_path
                self.reload()
                self.scroll_to_cell(self.pos_stack[-1][0])
                self.w('view').set_cursor(self.pos_stack.pop()[1])
            elif entry_type == TYPE['file']:
                self.app.c.add([new_path])
        except mpdclient.MpdError:
            self.app.c = False

    def on_popup_menu(self, widget):
        self.popup_menu(widget, 0, 0)
        return True
    def on_play(self, action): self.play()
    def on_add(self, action): self.enqueue_selection(self.w('view').get_selection())
    def on_update(self, action): self.update()
    def on_delete(self, action):
        tree_selection = self.w('view').get_selection()
        (model, paths) = tree_selection.get_selected_rows()
        for pl in filter(lambda x: model[x][1] == TYPE['playlist'], paths):
            name = model[pl][0][1:-1]
            DeletePlaylistDialog(self.app, self.app.w('window'), name)

    def on_dir_change(self, treeview, path, view_column):
        self.change_dir(path)
    def on_button_press(self, widget, event):
        if event.button == 3:
            return widget.get_selection().count_selected_rows() > 1
        elif event.button == 2 and self.tree[0][0] == os.pardir:
            self.change_dir(0)
    def on_button_release(self, widget, event):
        if event.button == 3:
            self.popup_menu(widget, event.button, event.time)
    def popup_menu(self, view, button, time):
        if button in (0, 3):
            (model, pathlist) = view.get_selection().get_selected_rows()
            del_is_active = len(filter(lambda x: model[x][1] == TYPE['playlist'], pathlist)) > 0
            w = self.gui_popup.get_widget
            w('delete').set_sensitive(del_is_active)
            w('play').set_sensitive(len(pathlist) > 0)
            w('add').set_sensitive(len(pathlist) > 0)
            w('lib_popup').popup(None, None, None, button, time)
            return True
    def first_visible_row(self):
        top = self.w('view').get_path_at_pos(0,0)[0]
        cell_area = self.w('view').get_background_area(top, self.w('view').get_column(0))
        return self.w('view').get_path_at_pos(0,cell_area.height/2)[0]
    def scroll_to_cell(self, path):
        self.w('view').scroll_to_cell(path, use_align=True)

class DeletePlaylistDialog(base_dialog.SimpleInputDialog):
    def __init__(self, app, parent, playlist):
            base_dialog.SimpleInputDialog.__init__(self, app, parent, 'Save playlist', 'Delete playlist "%s"?' % playlist)
            self.connect('response', self.__on_response, playlist)
            self.start()
    def __on_response(self, dialog, response_id, playlist):
        if response_id == gtk.RESPONSE_ACCEPT:
            self.app.lib.delete(playlist)
