#! /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 shutil
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 distversion

import cxguitools
import pyop

import demoutils

# for localization
from cxutils import cxgettext as _

class RegisterDialogController(object):

    mainWindow = None
    xml = None

    modeldialogxml = None
    animateFunctions = []

    def __init__(self):

        try:
            gladepath = os.environ["CX_GLADEPATH"]
        except KeyError:
            gladepath = os.path.join(cxutils.CX_ROOT, "lib", "python", "glade")

        self.gladefile = os.path.join(gladepath, "registerdialog.glade")
        gtk.glade.set_custom_handler(cxguitools.CustomWidgets.custom_widget_handler)

        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('cxregister')
            self.xml.get_widget("RegisterDialog").set_icon(icon)
        except gobject.GError:
            cxlog.warn("Couldn't load icon:\n%s" % traceback.format_exc())

        explanationText = _("""<body>
                             <p>To buy a full version of %(productname)s, visit:</p>
                             <p><a href="http://store.codeweavers.com">http://store.codeweavers.com</a></p>
                             <p>During your purchase you will be asked to create an account using your email
                             address and a password. Enter your email address and password below, and click
                             'Register' to register and unlock your install.</p>
                          </body>""") % {'productname': distversion.PRODUCT_NAME}
        
        self.xml.get_widget("ExplanationTextView").display_html(explanationText)

        registerButton = self.xml.get_widget("RegisterButton")
        registerButton.set_flags(gtk.CAN_DEFAULT)

        registerprogbar = self.xml.get_widget("RegistrationProgbar")
        registerprogbar.set_pulse_step(0.05)
        registerprogbar.hide()

        self.mainWindow = self.xml.get_widget('RegisterDialog')

        self.update_sensitivities(None)

        self.xml.get_widget("EmailEntry").grab_focus()


    def update_sensitivities(self, _caller):

        emailEntry = self.xml.get_widget("EmailEntry")
        passwordEntry = self.xml.get_widget("PasswordEntry")
        registerButton = self.xml.get_widget("RegisterButton")

        if len(passwordEntry.get_text()) and len(emailEntry.get_text()):
            registerButton.set_sensitive(True)
        else:
            registerButton.set_sensitive(False)
            registerButton.grab_default()

    def sensitivities_at_start_registration(self):
        emailEntry = self.xml.get_widget("EmailEntry")
        passwordEntry = self.xml.get_widget("PasswordEntry")
        registerButton = self.xml.get_widget("RegisterButton")
        cancelButton = self.xml.get_widget("CancelButton")
        registerprogbar = self.xml.get_widget("RegistrationProgbar")

        registerButton.set_sensitive(False)
        cancelButton.set_sensitive(False)
        passwordEntry.set_sensitive(False)
        emailEntry.set_sensitive(False)

        self.animateEvent = gobject.timeout_add(100, self.progbar_pulse)

        registerprogbar.show()

    def sensitivities_after_registration(self):
        emailEntry = self.xml.get_widget("EmailEntry")
        passwordEntry = self.xml.get_widget("PasswordEntry")
        registerButton = self.xml.get_widget("RegisterButton")
        cancelButton = self.xml.get_widget("CancelButton")
        registerprogbar = self.xml.get_widget("RegistrationProgbar")

        registerButton.set_sensitive(True)
        cancelButton.set_sensitive(True)
        passwordEntry.set_sensitive(True)
        emailEntry.set_sensitive(True)

        gobject.source_remove(self.animateEvent)

        registerprogbar.hide()
        self.update_sensitivities(None)

    def progbar_pulse(self):
        registerprogbar = self.xml.get_widget("RegistrationProgbar")
        registerprogbar.pulse()
        return True

    def register_clicked(self, _caller):
        emailEntry = self.xml.get_widget("EmailEntry")
        passwordEntry = self.xml.get_widget("PasswordEntry")

        self.sensitivities_at_start_registration()
        registerOp = RegisterOperation(self, emailEntry.get_text(), passwordEntry.get_text())
        pyop.sharedOperationQueue.enqueue(registerOp)

    def register_finished(self, success, errorString):
        self.sensitivities_after_registration()

        self.mainWindow = self.xml.get_widget('RegisterDialog')

        if success:
            cxguitools.CXMessageDlg(_("Registration successful."), buttons=gtk.BUTTONS_OK, response_function=self.quit_requested, parent=self.mainWindow, message_type=gtk.MESSAGE_INFO)
        else:
            cxguitools.CXMessageDlg(primary=_("Registration failed"), secondary=errorString, buttons=gtk.BUTTONS_OK, parent=self.mainWindow, message_type=gtk.MESSAGE_ERROR)

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


class RegisterOperation(pyop.PythonOperation):

    def __init__(self, inRegisterController, inLogin, inPassword):
        pyop.PythonOperation.__init__(self)
        self.registerController = inRegisterController
        self.login = inLogin
        self.password = inPassword
        self.success = False
        self.errorString = None

    def __unicode__(self):
        return "RegisterOperation with username " + self.login

    def main(self):

        while True:
            tempLicenseFile, tempSigFile, downloadErrorString = demoutils.download_and_split_license_file(self.login, self.password) 
            if not tempSigFile:
                self.success = False
                self.errorString = downloadErrorString
                break

            (isDemo, username, _date, _licenseid, _revoked) = demoutils.demo_status(tempLicenseFile, tempSigFile)
            if isDemo:
                if not username:
                    self.errorString = _("Unable to download a valid license file.")
                else:
                    self.errorString = _("Your support contract is not valid for this product. You may need to purchase a support extension or an additional license.")
                os.remove(tempLicenseFile)
                os.remove(tempSigFile)
                self.success = False
                break

            cert_dir = os.path.join(cxutils.CX_ROOT, "etc")
            license_file = os.path.join(cert_dir, "license.txt")
            sig_file = os.path.join(cert_dir, "license.sig")
            # Use shutil.move() to avoid trouble with cross-filesystem renames
            shutil.move(tempLicenseFile, license_file)
            shutil.move(tempSigFile, sig_file)

            self.success = True
            self.errorString = None
            break


    def finish(self):
        self.registerController.register_finished(self.success, self.errorString)
        pyop.PythonOperation.finish(self)


def maybe_do_su():
    licenseDir = os.path.join(cxutils.CX_ROOT, "etc")
    if not demoutils.can_register_as_current_user(licenseDir):
        args = [os.path.join(cxutils.CX_ROOT, "bin", "cxsu"), "--ignore-home"]
        args.extend(sys.argv)
        cxutils.run(args)
        sys.exit()


def main():
    # Parse the command line options
    opt_parser = cxopt.Parser(usage="%prog [--help]",
                              description="Registers and unlocks a demo version of CrossOver.")
    (_options, args) = opt_parser.parse_args()
    if args:
        opt_parser.error("unexpected argument '%s'" % args[0])

    cxguitools.set_default_icon('cxregister')

    cert_dir = os.path.join(cxutils.CX_ROOT, "etc")
    license_file = os.path.join(cert_dir, "license.txt")
    sig_file = os.path.join(cert_dir, "license.sig")

    demoStatus =  demoutils.demo_status(license_file, sig_file)

    if not demoStatus[0]:
        # I'm not sure how we got here, but let's have another go at removing
        #  the menu entry anyway.
        demoutils.remove_registration_menu()
        if demoStatus[1]:
            msg = _("This install of %(product)s has already been registered by:\n\n%(name)s\n\nIt is fully enabled. Thank you for your support!") % {'product': distversion.PRODUCT_NAME, 'name': demoStatus[1]}
        else:
            msg = _("This install of %s is already fully enabled.\n\nThank you for your support!") % distversion.PRODUCT_NAME
        cxguitools.CXMessageDlg(msg , buttons=gtk.BUTTONS_OK, response_function=sys.exit, message_type=gtk.MESSAGE_INFO)
        gtk.main()
    else:
        maybe_do_su()
        RegisterDialogController()
        gtk.main()

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