#!/usr/bin/python -u

"""

ECLiPt Roaster Applet

"""

from sys import path

path.append("/usr/lib/eroaster")

import gnome.applet
import log4py
import os
import GDK

from constants import title, version, eraDataCD, eraAudioCD, eraCopyCD, iconpath, eraCDImage
from tools import split, TRUE, FALSE, cleanlist, which
from string import replace, strip, lower, join
from time import sleep
from types import InstanceType
from gtk import mainloop, create_pixmap_from_xpm, GtkPixmap, timeout_add, events_pending
from gtk import mainiteration, DEST_DEFAULT_DROP, DEST_DEFAULT_MOTION
from gnome.ui import STOCK_MENU_ABOUT, GnomeAbout, GnomeErrorDialog
try:
    from gnome.tools import targets
except:
    from gnometools import targets

class ERoasterApplet:

    def __init__(self):
        self.log4py = log4py.Logger()
        # self.log4py.set_loglevel(log4py.LOGLEVEL_DEBUG)
        self.__ERoasterApplet_command = which("eroaster")
        self.applet = gnome.applet.AppletWidget("eroaster")
        self.applet.set_tooltip("%s %s" % (title, version))
        self.applet.register_stock_callback("about", STOCK_MENU_ABOUT, ("About"), self.about_eroaster_applet)
        self.applet.set_events(self.applet.get_events() | GDK.BUTTON_PRESS_MASK | GDK.ENTER_NOTIFY_MASK | GDK.LEAVE_NOTIFY_MASK)
        self.applet.connect("button_press_event", self.run_eroaster)
        self.applet.connect("enter_notify_event", self.__ERoasterApplet_highlight_applet)
        self.applet.connect("leave_notify_event", self.__ERoasterApplet_darken_applet)
        self.applet.connect("drag_data_received", self.__ERoasterApplet_dnd_receive)
        self.applet.drag_dest_set(DEST_DEFAULT_DROP | DEST_DEFAULT_MOTION, targets, GDK.ACTION_COPY | GDK.ACTION_MOVE)

        self.pixbright, self.maskbright = create_pixmap_from_xpm(self.applet, None, "%s/applet-bright.xpm" % iconpath)
        self.pixdark, self.maskdark = create_pixmap_from_xpm(self.applet, None, "%s/applet.xpm" % iconpath)
        self.pixburn, self.maskburn = create_pixmap_from_xpm(self.applet, None, "%s/applet-burn.xpm" % iconpath)
        self.app_pix = GtkPixmap(self.pixdark, self.maskdark)
        self.app_pix.show()

        self.burning = FALSE

        self.applet.add(self.app_pix)
        self.applet.show()

    # Drag and Drop data receive
    def __ERoasterApplet_dnd_receive(self, window, context, x, y, data, info, time):
        filenames = cleanlist(split(data.data,"\n"))
        startuptype = None
        files = ""
        if (len(filenames) == 1):
            self.log4py.debug("Single file received by drag & drop")
            filename = self.__ERoasterApplet_check_filename(filenames[0])
            if (filename[:5] == "file:"):
                filename = filename[5:]
            if (filename[:7] == "/dev/cd") or (filename[:8] == "/dev/scd"):
                startuptype = eraCopyCD
            elif (os.path.isdir(filename)):
                startuptype = eraDataCD
                filelist = os.listdir(filename)
                for i in range(len(filelist)):
                    filelist[i] = "%s/%s" % (filename, filelist[i])
                filename = join(filelist, "\" \"")
            elif (self.__ERoasterApplet_isaudiofile(filename) == TRUE):
                startuptype = eraAudioCD
            elif (self.__ERoasterApplet_isisoimage(filename) == TRUE):
                startuptype = eraCDImage
            elif (self.__ERoasterApplet_isplaylist(filename) == TRUE):
                file = open(filename, "r")
                all_files = file.readlines()
                file.close()
                for index in range(len(all_files)):
                    file = strip(all_files[index])
                    if (os.path.exists(file)):
                        files = "%s \"%s\"" % (files, file)
                if (strip(files) == ""):
                    GnomeErrorDialog("The specified playlist contains no valid files")
                else:
                    startuptype = eraAudioCD
            else:
                GnomeErrorDialog("Sorry, I don't know how to handle \"%s\"" % filename)
            if (startuptype != None) and (files == ""):
                files = "\"%s\"" % (filename)
        else:
            self.log4py.debug("Multiple files received by drag & drop")
            startuptype = eraAudioCD
            for i in range(len(filenames)):
                filename = self.__ERoasterApplet_check_filename(filenames[i])
                if (self.__ERoasterApplet_isaudiofile(filename) == FALSE) and (startuptype == eraAudioCD):
                    startuptype = eraDataCD
                files = "%s \"%s\"" % (files, filename)

        if (startuptype != None):
            self.run_eroaster("%s %s" % (startuptype, files))

    # Highlight the applet icon when moving the mouse over it
    def __ERoasterApplet_highlight_applet(self, *args):
        if (self.burning == FALSE):
            self.app_pix.set(self.pixbright, self.maskbright)

    # Darken the applet icon when mouse leaves the icon
    def __ERoasterApplet_darken_applet(self, *args):
        if (self.burning == FALSE):
            self.app_pix.set(self.pixdark, self.maskdark)

    def __ERoasterApplet_isaudiofile(self, filename):
        """ Is the given file a audio file (extensions mp3, wav or ogg) """
        extension = lower(os.path.splitext(filename)[1])
        if (extension == ".mp3") or (extension == ".wav") or (extension == ".ogg"):
            return TRUE
        else:
            return FALSE

    def __ERoasterApplet_isisoimage(self, filename):
        """ Is the given file a iso image (extension iso or img) """
        extension = lower(os.path.splitext(filename)[1])
        if (extension == ".iso") or (extension == ".img"):
            return TRUE
        else:
            return FALSE

    def __ERoasterApplet_isplaylist(self, filename):
        """ Is the given file a xmms playlist (extension .m3u) """
        extension = lower(os.path.splitext(filename)[1])
        if (extension == ".m3u"):
            return TRUE
        else:
            return FALSE

    def __ERoasterApplet_check_filename(self, filename):
        """ Cleans the filename received by the drag & drop event """
        if (filename[:5] == "file:"):
            filename = filename[5:]
        while (filename[:2] == "//"):
            filename = filename[1:]
        filename = replace(filename, "%20", " ")
        filename = replace(filename, "\000", "")
        filename = strip(filename)
        return filename

    def run_eroaster(self, args, event = None):
        if (type(args) == InstanceType):
            args = ""
        self.log4py.debug("Arguments: %s" % args)
        if (self.__ERoasterApplet_command == ""):
            self.log4py.error("ERoaster executable not found")
        else:
            command = "%s %s" % (self.__ERoasterApplet_command, args)
            self.execute(command)

    # Execute some command
    def execute(self, command):
        self.log4py.debug("Executing: %s" % command)
        self.burning = TRUE
        self.app_pix.set(self.pixburn, self.maskburn)
        result = os.fork()
        if (result == 0):
            os.execv("/usr/bin/env", ["/usr/bin/env"] + split(command, " ", "\""))
        else:
            pid = 0
            while (pid == 0):
                sleep(0.1)
                pid = os.waitpid(result, os.WNOHANG)[0]
                while (events_pending()):
                    mainiteration()
            self.app_pix.set(self.pixdark, self.maskdark)
            self.burning = FALSE

    # Define a About Box
    def about_eroaster_applet(self, args):
        description = 'ERoaster is a GNOME frontend for writing, copying and grabbing data and audio CDs using cdrecord, mkisofs and some other tools.'
        description = "%s\nAvailable from:\n     http://www.eclipt.at\n     http://www.its4you.at\n     http://eroaster.sourceforge.net" % description
        description = "%s\nSend comments, bug reports or any other to the e-mail address above." % description
        GnomeAbout(title, version, 'May be distributed under the terms of the GPL2', ['Martin Preishuber (Martin.Preishuber@eclipt.at)'], description).show()

    def clean_handler(self):
        return TRUE

    # Main program
    def main(self):
        self.cleanhandler = timeout_add(1000, self.clean_handler)
        mainloop()

eroaster_applet = ERoasterApplet()
eroaster_applet.main()
