#! /usr/bin/env python
# (c) Copyright 2009-2012. CodeWeavers, Inc.

import os

# Portable which(1) implementation
def which(path, app):
    """Looks for an executable in the specified directory list.

    path is an os.pathsep-separated list of directories and app is the
    executable name. If app contains a path separator then path is ignored.
    If the file is not found, then None is returned.
    """
    if os.path.isabs(app):
        if os.path.isfile(app) and os.access(app, os.X_OK):
            return app
    elif os.sep in app or (os.altsep and os.altsep in app):
        app_path = os.path.join(os.getcwd(), app)
        if os.path.isfile(app_path) and os.access(app_path, os.X_OK):
            return app_path
    else:
        for directory in path.split(os.pathsep):
            if directory == "":
                continue
            app_path = os.path.join(directory, app)
            if os.path.isfile(app_path) and os.access(app_path, os.X_OK):
                return app_path
    return None

import sys
def locate_cx_root():
    """Locate where CrossOver is installed.

    We start by locating our own python script file and walking back up the
    path, traversing symbolic links on the way. Then we verify what we have
    found the right directory by checking for the presence of the cxmenu
    script.
    """
    # pylint: disable-msg=I0011,W0601,W0603
    global CX_ROOT
    if "CX_DEVELOP_ROOT" in os.environ:
        CX_ROOT = os.environ["CX_DEVELOP_ROOT"]
        return

    # figure out argv0
    argv0 = which(os.environ["PATH"], sys.argv[0])
    if not argv0:
        argv0 = sys.argv[0]
        if not os.path.isabs(argv0):
            argv0 = os.path.join(os.getcwd(), argv0)

    # traverse the symbolic links
    dir0 = os.path.dirname(argv0)
    while True:
        if dir0.endswith("/lib"):
            bindir = dir0[0:-3] + "bin"
        else:
            bindir = dir0
        landmark = os.path.join(bindir, "cxmenu")
        if os.path.isfile(landmark):
            break
        if not os.path.islink(argv0):
            break
        argv0 = os.readlink(argv0)
        if not os.path.isabs(argv0):
            argv0 = os.path.join(dir0, argv0)
        dir0 = os.path.dirname(argv0)

    # compute CX_ROOT
    CX_ROOT = os.path.dirname(os.path.normpath(bindir))

    # check CX_ROOT
    landmark = os.path.join(CX_ROOT, "bin", "cxmenu")
    if not os.path.isfile(landmark) or not os.access(landmark, os.X_OK):
        sys.stderr.write("%s:error: could not find CrossOver in '%s'\n" % (os.path.dirname(sys.argv[0]), CX_ROOT))
        sys.exit(1)

    sys.path.append(os.path.join(CX_ROOT, "lib", "python"))

locate_cx_root()
import cxutils
cxutils.CX_ROOT = CX_ROOT


import traceback

import checkgtk
if checkgtk.check_gtk() != checkgtk.OK:
    sys.exit(1)

import gobject
import gtk
import gtk.glade
gtk.gdk.threads_init()

import cxlog
import cxopt

import bottlecollection
import cxguitools
import pyop

# for localization
from cxutils import cxgettext as _

class ResetDialogController(object):

    mainWindow = None
    xml = None

    modeldialogxml = None

    def __init__(self):
        #-----------------------------------------------------------------------
        #  Parse Arguments
        #-----------------------------------------------------------------------
        opt_parser = cxopt.Parser(usage="%prog [--bottle BOTTLE] [--no-ui [--all-bottles] [--close|--kill]]  [--help]",
                                  description="Closes or forcefully terminates Windows applications.")
        opt_parser.add_option("--bottle", dest="bottle", help=_("Only stop the Wine processes in the specified bottle"))
        opt_parser.add_option("--no-ui", "--noui", dest="noui", help=_("Run from the command line"), action="store_true", default=False)
        opt_parser.add_option("--all-bottles", dest="allbottles", help=_("Stop the Wine processes in all bottles (default)"), action="store_true", default=False)
        opt_parser.add_option("--close", dest="close", help=_("Simulate a Windows shutdown"), action="store_true", default=False)
        opt_parser.add_option("--kill", dest="kill", help=_("Forcefully terminate the Wine processes"), action="store_true", default=False)
        (options, args) = opt_parser.parse_args()

        # Do more checks and provide defaults
        if args:
            opt_parser.error(_("unexpected argument '%s'") % args[0])
        if options.noui:
            if options.bottle and options.allbottles:
                opt_parser.error(_("the --bottle and --all-bottles options are mutually exclusive"))
            if options.close and options.kill:
                opt_parser.error(_("the --close and --kill options are mutually exclusive"))
        else:
            if options.kill or options.close or options.allbottles:
                opt_parser.error(_("the --all-bottles, --close and --kill options can only be used with the --no-ui option"))


        #-----------------------------------------------------------------------
        #  If --no-ui, then do everything right now.
        #-----------------------------------------------------------------------
        if options.noui:
            if options.bottle:
                bottleList = [options.bottle]
            else:
                if "CX_BOTTLE" not in os.environ or options.allbottles:
                    bottleList = bottlecollection.sharedCollection().bottleList()
                else:
                    bottleList = [os.environ["CX_BOTTLE"]]

            partialFailure = False
            for bottleName in bottleList:
                if options.kill:
                    partialFailure |= (bottlecollection.sharedCollection().bottleObject(bottleName).force_quit() != True)
                else:
                    partialFailure |= (bottlecollection.sharedCollection().bottleObject(bottleName).quit() != True)

            sys.exit(partialFailure)


        #-----------------------------------------------------------------------
        #  Setup the GUI
        #-----------------------------------------------------------------------
        self.resetOp = None
        self.forceQuitOp = None
        self.resetFailed = False
        cxguitools.set_default_icon("cxreset")
        try:
            gladepath = os.environ["CX_GLADEPATH"]
        except KeyError:
            gladepath = os.path.join(cxutils.CX_ROOT, "lib", "python", "glade")

        self.gladefile = os.path.join(gladepath, "resetdlg.glade")

        if not gtk.glade.textdomain() == "crossover":
            locale_path = os.path.join(CX_ROOT, "share", "locale")
            gtk.glade.bindtextdomain("crossover", locale_path)
            gtk.glade.textdomain("crossover")
        self.xml = gtk.glade.XML(self.gladefile)
        self.xml.signal_autoconnect(self)

        try:
            icon = cxguitools.get_std_icon('cxreset')
            self.xml.get_widget("ResetDlg").set_icon(icon)
        except gobject.GError:
            cxlog.warn("Couldn't load icon:\n%s" % traceback.format_exc())


        #-----------------------------------------------------------------------
        #  Set up progress bar
        #-----------------------------------------------------------------------
        progbar = self.xml.get_widget("ProgBar")
        progbar.set_pulse_step(.05)
        progbar.hide()


        #-----------------------------------------------------------------------
        #  Fill Bottle popup list
        #-----------------------------------------------------------------------
        bottlePopupWidget = self.xml.get_widget("BottlePopup")
        self.bottleListStore = gtk.ListStore(str, object)
        bottlePopupWidget.set_model(self.bottleListStore)
        collection = bottlecollection.sharedCollection()

        newrow = self.bottleListStore.append()
        self.bottleListStore.set_value(newrow, 0, _("All Bottles"))
        self.bottleListStore.set_value(newrow, 1, "")
        selectIter = newrow

        self.allBottles = []

        for bottleName in sorted(collection.bottleList()):
            self.allBottles.append(bottleName)
            newrow = self.bottleListStore.append()
            self.bottleListStore.set_value(newrow, 0, bottleName)
            self.bottleListStore.set_value(newrow, 1, bottleName)
            if bottleName == options.bottle:
                selectIter = newrow

        if selectIter:
            bottlePopupWidget.set_active_iter(selectIter)
        else:
            bottlePopupWidget.set_active_iter(self.bottleListStore.get_iter_first())

        self.set_widget_sensitivities(self)

    def quit_requested(self, _caller):
        gtk.main_quit()

    def progbar_pulse(self):
        progBar = self.xml.get_widget("ProgBar")
        progBar.pulse()
        return True

    def set_widget_sensitivities(self, _caller):
        progBar = self.xml.get_widget("ProgBar")

        if self.forceQuitOp != None:
            self.xml.get_widget("BottlePopup").set_sensitive(False)
            self.xml.get_widget("ResetButton").set_sensitive(False)
            self.xml.get_widget("ForceQuitButton").set_sensitive(False)
            self.xml.get_widget("CloseButton").set_sensitive(False)
            progBar.show()
        if self.resetOp != None:
            self.xml.get_widget("BottlePopup").set_sensitive(False)
            self.xml.get_widget("ResetButton").set_sensitive(False)
            self.xml.get_widget("ForceQuitButton").set_sensitive(True)
            self.xml.get_widget("CloseButton").set_sensitive(False)
            progBar.show()
        else:
            self.xml.get_widget("BottlePopup").set_sensitive(True)
            self.xml.get_widget("ResetButton").set_sensitive(True)
            self.xml.get_widget("ForceQuitButton").set_sensitive(self.resetFailed)
            self.xml.get_widget("CloseButton").set_sensitive(True)
            progBar.hide()


    def reset_bottle(self, _caller):
        self.animateEvent = gobject.timeout_add(100, self.progbar_pulse)

        if self.get_selected_bottle_name() == "":
            self.resetOp = bottlecollection.QuitBottleOperation(self.allBottles, False, self)
        else:
            self.resetOp = bottlecollection.QuitBottleOperation([self.get_selected_bottle_name()], False, self)

        self.resetFailed = False

        self.set_widget_sensitivities(self)
        pyop.sharedOperationQueue.enqueue(self.resetOp)

    def force_quit_bottle(self, _caller):
        self.animateEvent = gobject.timeout_add(100, self.progbar_pulse)

        if self.get_selected_bottle_name() == "":
            self.forceQuitOp = bottlecollection.QuitBottleOperation(self.allBottles, True, self)
        else:
            self.forceQuitOp = bottlecollection.QuitBottleOperation([self.get_selected_bottle_name()], True, self)

        self.resetFailed = False

        self.set_widget_sensitivities(self)
        pyop.sharedOperationQueue.enqueue(self.forceQuitOp)


    def opFinished(self, runCommandOp):
        if runCommandOp == self.forceQuitOp:
            self.forceQuitOp = None
        else:
            self.resetOp = None
            self.resetFailed = not runCommandOp.succeeded
        self.set_widget_sensitivities(self)

        gobject.source_remove(self.animateEvent)


    def bottle_changed(self, _widget):
        self.resetFailed = False
        self.set_widget_sensitivities(self)


    def get_selected_bottle_name(self):
        bottlecollection.sharedCollection()
        bottlePopup = self.xml.get_widget("BottlePopup")
        activeIndex = bottlePopup.get_active_iter()
        selectedBottleName = self.bottleListStore.get_value(activeIndex, 1)
        return selectedBottleName



if __name__ == "__main__":
    ResetDialogController()
    gtk.main()
    sys.exit()



