# applet.py - A GNOME applet that shows what Moosic is currently playing.
#
# Copyright (C) 2003 Daniel Pearson <daniel.pearson@umbc.edu>
# Copyright (C) 2003 Paramjit Oberoi <param@cs.wisc.edu>
#
# 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import pygtk
pygtk.require('2.0')
import gtk, gnome.applet

import socket, errno, os, os.path, sys
import xmlrpclib, moosic_factory

from applet_ui import *
from applet_config import *

# Class representing the applet
# An instance of this class is instantiated for each applet

class MoosicApplet:
    def refresh(self):
        call_array = [{'methodName':'length','params':[]},
                      {'methodName':'current','params':[]},
                      {'methodName':'is_paused','params':[]},
                      {'methodName':'is_queue_running','params':[]},
                      {'methodName':'list','params':[[0,1]]},
                      {'methodName':'is_looping','params':[]},
                     ]
        try: result_array = self.moosic.system.multicall(call_array)
        except socket.error, e:
            if e[0] in (errno.ECONNREFUSED, errno.ENOENT):
                self.ui.update_tooltip('[moosicd not running]')
            else:
                self.ui.update_tooltip('[unexpected socket error]')
            self.update_song_name("[not connected]", False)
            self.connected = False
            return gtk.TRUE

        # # Make sure that our connection to the server is working properly.
        # try: self.moosic.no_op()
        # except socket.error, e:
        #     if e[0] in (errno.ECONNREFUSED, errno.ENOENT):
        #         self.ui.update_tooltip('[moosicd not running]')
        #     else:
        #         self.ui.update_tooltip('[unexpected socket error]')
        #     self.update_song_name("[not connected]", False)
        #     self.connected = False
        #     return gtk.TRUE

        update_display = False
        if not self.connected:
            self.connected = True
            update_display = True

        # current_song = self.moosic.current().data.decode('latin-1').encode('utf-8')
        # paused = self.moosic.is_paused()
        # stopped = not current_song
        # queue_length = self.moosic.length()
        # queue_running = self.moosic.is_queue_running()

        current_song = result_array[1][0].data.decode('latin-1').encode('utf-8')
        paused = result_array[2][0]
        looping = result_array[5][0]
        stopped = not current_song
        queue_length = result_array[0][0]
        queue_running = result_array[3][0]
        if queue_length:
            first_in_queue = result_array[4][0][0].data.decode('latin-1').encode('utf-8')
        else:
            first_in_queue = None

        if self.paused != paused:
            self.paused = paused
            if paused: self.ui.paused()
            else: self.ui.unpaused()
            update_display = True

        if self.stopped != stopped:
            self.stopped = stopped;
            update_display = True

        if self.queue_running != queue_running:
            self.queue_running = queue_running
            if queue_running: self.ui.queue_running()
            else: self.ui.queue_not_running()

        if self.looping != looping:
            self.looping = looping
            if looping: self.ui.loop_mode_enabled()
            else: self.ui.loop_mode_disabled()

        if self.queue_length != queue_length:
            self.queue_length = queue_length
            if self.config.display_qlength:
                #self.ui.qlen_label.set_text("%d" % queue_length)
                self.ui.qlen_label.set_markup("<b>%d</b>" % queue_length)
            update_display = True

        if self.current_song != current_song:
            self.current_song = current_song
            update_display = True

        if self.first_in_queue != first_in_queue:
            self.first_in_queue = first_in_queue
            update_display = True

        if update_display:
            # update stop/play/add button
            if stopped:
                if self.queue_length: self.ui.stopped()
                else: self.ui.empty()
            else: self.ui.playing()

            # update song name and tooltip
            if stopped:
                if queue_length:
                    self.ui.update_tooltip("[next item] " + first_in_queue)
                else:
                    self.ui.update_tooltip("[queue empty]")
                if self.config.display_qlength or queue_length:
                    self.update_song_name("[nothing playing]", False)
                else:
                    self.update_song_name("[queue empty]", False)
            elif paused:
                self.ui.update_tooltip("[paused] " + current_song)
                self.update_song_name(current_song, True)
            else:
                self.ui.update_tooltip(current_song)
                self.update_song_name(current_song, True)

        #if self.moosic.is_looping(): is_looping="1"
        #else: is_looping = "0"
        #self.menu.set_property("/commands/Loop", {"state":is_looping})
        #print self.menu.get_prop("/commands/Loop")

        #pdb.set_trace()

        return gtk.TRUE

    def update_song_name(self, s, munge):
        if munge:
            if (self.config.strip_dir): s = os.path.basename(s)
            if (self.config.strip_ext): s = os.path.splitext(s)[0]
            if (self.config.strip_prefix):
                dirname, filename = os.path.split(s)
                for pfx in self.config.prefixes:
                    n = filename.rfind(pfx)
                    if n != -1: filename = filename[n+len(pfx):]
                s = os.path.join(dirname,filename)
            if (self.config.replace_underscores): s = s.replace("_"," ")
            s = s.strip()

        self.ui.label.set_text(s)

    # ---- Utility functions for controlling moosicd

    def construct_file_list(self, lst, result=None):
        if result is None: item_list = []
        else: item_list = result
        for item in lst:
            if not os.path.isdir(item):
                item_list.append(xmlrpclib.Binary(item))
            else:
                dirlist = os.listdir(item)
                # ignore dotfiles and dotdirs?
                dirlist = [os.path.join(item,x) for x in dirlist]
                self.construct_file_list(dirlist, item_list)
        return item_list

    def add(self, run_queue=False):
        def callback(dlg,response):
            if response==gtk.RESPONSE_OK:
                selections = dlg.get_selections()
                self.moosic.append(self.construct_file_list(selections))
                if run_queue: self.moosic.run_queue()
                last_sel = selections[-1]
                if not os.path.isdir(last_sel):
                    last_sel = os.path.dirname(last_sel)
                os.chdir(last_sel)
            dlg.destroy()

        f = gtk.FileSelection("Add Entries to Moosic Queue")
        f.set_select_multiple(True)
        f.hide_fileop_buttons()
        f.connect("response",callback)
        f.show_all()


    def play_stop_add(self):
        if self.stopped:
            if not self.queue_length: self.add(True)
            else: self.moosic.run_queue()
        else:
            self.moosic.stop()

    def pause_toggle(self):
        self.moosic.toggle_pause()

    def prev(self):
        self.moosic.previous()

    def next(self):
        self.moosic.next()

    def sort(self):
        self.moosic.sort()

    def shuffle(self):
        self.moosic.shuffle()

    def qstop(self):
        self.moosic.halt_queue()

    def clear(self):
        self.moosic.clear()

    def wipe(self):
        self.moosic.halt_queue()
        self.moosic.next()
        self.moosic.clear()

    def toggle_queue_running(self):
        if self.queue_running:
            self.moosic.halt_queue()
        else:
            self.moosic.run_queue()

    def toggle_loop_mode(self):
        self.moosic.toggle_loop_mode()

    def __init__(self, applet, iid):
        self.stopped = True
        self.paused = False
        self.looping = None
        self.queue_running = False
        self.queue_length = None
        self.current_song = None
        self.first_in_queue = None
        self.connected = False

        self.moosic = moosic_factory.LocalMoosicProxy()
        self.config = MoosicAppletConfig(self)
        self.ui = MoosicAppletUI(applet, self)


def moosic_applet_factory(applet, iid):
    MoosicApplet(applet,iid)
    return gtk.TRUE

# Run as application?
if len(sys.argv) == 2 and sys.argv[1] == "run-moosicapplet-as-application":
    main_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    main_window.set_title("Moosic Applet")
    main_window.connect("destroy", gtk.mainquit) # quit the event loop on destruction
    app = gnome.applet.Applet()
    moosic_applet_factory(app, None)
    app.reparent(main_window)
    main_window.show_all()
    gtk.main()
    sys.exit()

gnome.applet.bonobo_factory("OAFIID:GNOME_MoosicApplet_Factory", gnome.applet.Applet.__gtype__, "hello", "0", moosic_applet_factory)
