#!/usr/bin/python2

from main import client, DISPLAY, HOME, USERHOME
from main import LOGFILE, LOG_PATH, PID_PATH, REGISTRY_PATH, SOCKET_PATH
from main.DisplayList import DisplayList
from utils import i18n

import optparse
import utils

import os
import sys

import __builtin__
__builtin__._ = i18n.Translator("gdesklets")

_DISPLAYLIST = os.path.join(USERHOME, "displays")
_DSPLIST = DisplayList(_DISPLAYLIST)


#
# Check if user starts gdesklets as root
#
def check_user():

    if (os.getuid() == 0):
        print _("You must NOT run gDesklets as super user (root).")
        sys.exit(1)

    utils.makedirs(os.path.join(USERHOME, "Displays"))
    utils.makedirs(os.path.join(USERHOME, "Controls"))
    utils.makedirs(os.path.join(LOG_PATH))
    utils.makedirs(os.path.join(REGISTRY_PATH))
    # chmod'ing USERHOME and subdirs to 700, otherwise it might become a
    # security risk
    os.chmod(USERHOME, 0700)
    os.chmod(REGISTRY_PATH, 0700)
    os.chmod(LOG_PATH, 0700)



#
# Runs dependency checks and returns whether all checks went fine.
#
def check_system():

    print _("Checking requirements:")

    for modules, predicate, message, required in (
        ( ("sys",), lambda m : m.version_info[:2] >= (2, 4),
          _("Python version >= %(pyver)s is required.") % {"pyver": "2.4.0"},
          True
        ),
        ( ("xml.parsers.expat",),
          lambda m: m.parsers.expat.version_info != (1, 95, 7),
          _("libexpat version 1.95.7 is broken. Please upgrade!"),
          True
        ),
        ( ("xml.sax",), lambda m: m,
          _("SAX parser is required, some SuSE versions ship without it."),
          True
        ),
        ( ("gtk",), lambda m : m.pygtk_version >= (2, 10, 0) and \
                              m.gtk_version >= (2, 10, 0),
          _("GTK python bindings (pygtk2) version >= %(pygtk_ver)s and "
            "GTK+ version >= %(gtk_ver)s are required.") %
                {"pygtk_ver": "2.10.0", "gtk_ver": "2.10.0"},
          True
        ),
        ( ("bonobo.ui",), lambda m : m,
          _("bonobo python bindings are required."),
          False
        ),
        ( ("dbus",), lambda m : m,
          _("DBus python bindings are useful, but optional."),
          False
        )
    ):

        loaded = None
        for m in modules:
            print " - %s " % m,
            if not required:
                print _("(optional) "),
            print "... ",
            try:
                loaded = __import__(m)
                print _("found")
                break
            except Exception:
                pass
            print _("missing")

        if required:
            try:
                if (not predicate(loaded)):
                    raise RuntimeError
            except Exception:
                print _("Version check failed.")
                # 'message' has already been translated
                print "\n%s\n" % message
                print _("Please make sure that the required software is "
                        "installed.\nAlso try to avoid having multiple versions "
                        "of a library/binding on your system.\ngDesklets won't "
                        "work if you don't have all necessary dependencies "
                        "installed\non your system.\n\nTHE STARTUP WILL BE "
                        "CANCELLED NOW!\n")
                return False


    print _("Requirements checking done. Your system looks ok!")
    return True


def check_first_run():

    if (not os.path.exists(USERHOME)):
        print _("\nYou're running gDesklets for the first time.\ngDesklets "
                "will start a requirements check now...\n")
        if (not check_system()):
            sys.exit(1)


def usage_and_exit():

    """ prints how to use gdesklets"""

    print _(
        "\n"
        "Orders:\n"
        "  open    <files>   (Opens the given desklet files)\n"
        "  start             (Runs the gDesklets daemon, this is default)\n"
        "  stop              (Stops the gDesklets daemon)\n"
        "  list              (Lists open desklets)\n"
        "  restart           (Restarts the gDesklets daemon)\n"
        "  profile <profile> (Switches to the given profile)\n"
        "  profile           (Shows the current and the available profiles)\n"
        "  shell             (Opens the graphical shell)\n"
        "  slay              (Kills the daemon -- use in emergency)\n"
        "  status            (Checks daemon status)\n"
        "  about             (Prints information about gDesklets)\n"
        "  version           (Prints gDesklets version)\n"
        "  configure         (Opens the configuration dialog)\n"
        "  help              (Displays this text)\n"
        "  check             (Checks requirements)\n"
        "\n"
        )
    sys.exit(1)


class Command(object):

    def __init__(self, args):

        self.__args = args
        self.__command = "" 
        self.__displays = None



    def __client_daemon(self):

        """ Returns the daemon if available, otherwise informs the user that
            something went wrong """

        try:
            ndaemon = client.get_daemon()

        except StandardError, exc:
            print _("Error while starting gdesklets-daemon\n"
                   "More information about this crash is available in \"%s\"."
                   % LOGFILE)
            print _("Exception was: %s\n" % `exc`)
            return

        ndaemon.set_remove_command(os.path.abspath(sys.argv[0]) + " _remove")

        return ndaemon



    def __open_profile(self, profile):

        """ Opens passed profile """

        daemon = self.__client_daemon()
        displays = _DSPLIST.get_displays(profile)
        for myident in displays:
            try:
                mypath = _DSPLIST.lookup_display(myident)[-1]
            except KeyError, exc:
                log(`exc`)
                continue

            try:
                daemon.open_display_with_id(mypath, myident)
            except Exception:
                print _("Could not open desklet %s.") % mypath
                continue



    def __close_profile(self, profile):

        """ Closes passed profile """

        daemon = self.__client_daemon()
        displays = _DSPLIST.get_displays(profile)
        for myident in displays:
            daemon.close_display(myident)



    def parse_cmdline(self):

        parser = optparse.OptionParser(usage="%prog [options] order")

        parser.add_option("-n", "--no-tray-icon",
                        action="store_true",
                        dest="no_tray_icon",
                        help="Avoid to show the icon on the tray",
                        default=False)

        parser.add_option("-d", "--debug",
                        action="store_true",
                        dest="debug",
                        help="Avoid show the icon on the tray",
                        default=False)

        parser.add_option("-c", "--check-first",
                        action="store_true",
                        dest="check_first",
                        help="Launch pre-existing display ",
                        default=False)

        parser.add_option("-p", "--sm-config-prefix",
                        action="store",
                        type="string",
                        dest="sm_config_prefix",
                        help="I have no idea!")

        parser.add_option("-i", "--sm-client-id",
                        action="store",
                        dest="sm_client_id",
                        help="I have no idea!")

        options, args = parser.parse_args()

        if not args: self.__command = "start"
        else: self.__command = args.pop(0)

        if (self.__command == "open"):
            if (len(args) == 0):
                parser.print_help()
                usage_and_exit()

            daemon = self.__client_daemon()
            prof = _DSPLIST.get_profile()
            
            if options.check_first:
                self.__displays = _DSPLIST.get_displays(prof)

            for item in args:
                found_display = False
                if (0 < item.find("://") < 8):
                   path = item
                else:
                   path = os.path.abspath(item)

                try:
                    if self.__displays:
                        for ident in self.__displays:
                            saved_path = _DSPLIST.lookup_display(ident)[1]
                            if saved_path == path:
                                daemon.open_display_with_id(path, ident)
                                found_display = True

                    if not self.__displays or found_display is False:
                        print "Entering to NEW one..."
                        ident = daemon.open_display(path)
                        _DSPLIST.add_display(prof, path, ident)
                        _DSPLIST.commit()
                except Exception:
                    print _("Could not open desklet %s.") % path
                    continue

        elif (self.__command == "start"):
            print _("Starting gdesklets-daemon...")
            myprofile = _DSPLIST.get_profile()
            self.__open_profile(myprofile)

        elif (self.__command == "stop"):
            if (client.daemon_is_running()):
                print _("Shutting down gdesklets-daemon...")
                self.__client_daemon().shutdown()

        elif (self.__command == "shell"):
            cmd = "%s >/dev/null &" % (os.path.join(HOME, "gdesklets-shell"))
            os.system(cmd)

        elif (self.__command == "list"):
            myprofile = _DSPLIST.get_profile()
            display_list = _DSPLIST.get_displays(myprofile)

            if (display_list):
                print _("Currently open displays in profile \"%s\":\n"
                        % (myprofile,))
                for display in display_list:
                    print _DSPLIST.lookup_display(display)[1]
            else:
                print _("Currently there aren't any desklets in profile "
                        "\"%s\"" % (myprofile,))

        elif (self.__command == "restart"):
            print _("Restarting gdesklets-daemon...")

            if (client.daemon_is_running()):
                cmd = "%s stop && sleep 3 && %s start" \
                      % (sys.argv[0], sys.argv[0])
            else:
                cmd = "%s start" % (sys.argv[0],)

            os.system(cmd)

        elif (self.__command == "status"):

            if (client.daemon_is_running()):
                print _("gdesklets-daemon is running")
            else:
                print _("gdesklets-daemon is not running")

        elif (self.__command == "profile"):
            current_profile = _DSPLIST.get_profile()
            print _("Current profile: %s") % (current_profile,)

            if (args):
                new_profile = args.pop()
                if (new_profile != current_profile):
                   # close displays of the old profile
                   self.__close_profile(current_profile)
                   # start displays of the new profile
                   self.__open_profile(new_profile)
                   _DSPLIST.set_profile(new_profile)
                   _DSPLIST.commit()
                   print _("New profile: %s") % (new_profile,)
            else:
                profiles_list = ", ".join(_DSPLIST.get_profiles())
                print _("Available profiles: %s") % (profiles_list,)

        elif (self.__command == "version"):
            name, version = self.__client_daemon().version()
            print _("This is %(prog_name)s, version %(prog_version)s.") % \
                        {"prog_name": name, "prog_version": version}

        elif (self.__command == "about"):
            name, copy_right, gnu = self.__client_daemon().about()
            print "%s\n%s\n\n%s" % (name, copy_right, gnu)

        elif (self.__command == "configure"):
            self.__client_daemon().configure()

        elif (self.__command == "help"):
            usage_and_exit()

        elif (self.__command == "_remove"):
            ident = args.pop()
            _DSPLIST.remove_display(ident)
            try:
                _DSPLIST.commit()
            except StandardError:
                log("Could not remove \"%s\"." % (ident,))

        elif (self.__command == "slay"):

            import time
            import signal

            try:
                pid = int(open(PID_PATH).read())
            except Exception:
                sys.exit(_("Nothing to slay."))

            for sig in signal.SIGINT, signal.SIGTERM, signal.SIGKILL:

                try:
                    os.kill(pid, sig)
                except OSError:
                    break

                time.sleep(1)

            try:
                os.remove(PID_PATH)
                os.remove(os.path.join(SOCKET_PATH, DISPLAY))
            except OSError:
                pass


        elif (self.__command == "check"):

            if (not check_system()):
                sys.exit(1)

        else:
            print _("Invalid command. Please try one of the following "
                    "commands:")
            parser.print_help()
            usage_and_exit()



command = Command(sys.argv[1:])

check_user()
check_first_run()
command.parse_cmdline()

