var http = require('http'),
    path = require('path'),
    temp = require('temp'),
    URL = require('url'),
    runtime = require("../lib/runtime");

    /**
 * Start a Web server on a random port then call done().
 * @param app An instance of express
 */
module.exports.startServer = function (app, done) {
    server = http.createServer(app);
    server.on('error', function (error) {
        done(error);
    });
    server.on('listening', function() {
        var addr = server.address();
        app.set('port', addr.port);
        server.port = addr.port;
        server.baseUrl = 'http://localhost:' + addr.port + '/';
        done();
    });
    server.listen(0);
    return server;
};

module.exports.WebdriverTest = {};

/**
 * Wrapper around Mocha and Selenium for UI tests.
 *
 * Automagically make this.driver and this.server available from
 * the test bodies (within "it" callbacks). this.driver is the
 * WebDriver object (see examples in
 * https://code.google.com/p/selenium/wiki/WebDriverJs).
 * this.server is an http.Server instance running the app.
 * Additionally, navigating to relative URLs (e.g. "/") is
 * supported.
 *
 * @param description Like Mocha's first parameter to describe()
 * @param suiteBody Like Mocha's second parameter to describe()
 */
module.exports.WebdriverTest.describe = function (description, suiteBody) {
    if (! suiteBody) {
        return wdtesting.describe(description);
    }
    var webdriver = require('selenium-webdriver'),
        wdtesting = require('selenium-webdriver/testing');

    var mochaBefore = before;
    return wdtesting.describe(description, function () {
        var self = this;
        this.timeout(10000);  // Pump up default value
        this.setUpFakeData = module.exports.WebdriverTest.setUpFakeData;

        // For some reason wdtesting.before won't wait for the callback:
        mochaBefore(function(done) {
            if (! self.app) {
                self.app = require("../app");
            }
            self.server = module.exports.startServer(self.app, done);
        });

        wdtesting.before(function () {
            self.driver = new webdriver.Builder().
                withCapabilities(webdriver.Capabilities.chrome()).build();
            decorateDriver(self.driver, self.server.baseUrl);
        });
        wdtesting.after(function() {
            self.driver.quit();
        });

        var itOrig = global.it;
        function it(description, testBody) {
            if (! testBody) {
                return itOrig(description);
            }
            return wdtesting.it(description, function () {
                this.driver = self.driver;
                this.app = self.app;
                testBody.call(this);
            });
        }

        // Not the most elegant (as compared to say, running suiteBody inside
        // vm.runInNewContext), but gets the job done:
        try {
            global.it = it;
            return suiteBody.call(self);
        } finally {
            global.it = itOrig;
        }
    });
};

module.exports.WebdriverTest.setUpFakeData = function() {
    runtime.srvDir(temp.mkdirSync("BlueBoxNocFakeData"));
    var mochaBefore = before;
    var perl = require('../lib/perl');
    mochaBefore(function (done) {
        perl.runPerl(
            [path.resolve(runtime.srcDir(), "devsupport/make-fake-data.pl")],
            "",
            function (perlOut, perlExitCode, perlErr) {
                if (perlExitCode) {
                    done(perlErr);
                } else {
                    done();
                }
            }
        );
    });
};

function decorateDriver(driverObj, baseUrl) {
    var navigateOrig = driverObj.navigate;
    driverObj.navigate = (function () {
        var navigator = navigateOrig.call(driverObj);
        var toOrig = navigator.to;
        navigator.to = function (url) {
            if (! URL.parse(url).host) {
                url = URL.resolve(baseUrl, url);
            }
            return toOrig.call(navigator, url);
        }
        return navigator;
    }).bind(driverObj);
}

@@ -1,12 +1,53 @@
 var 
+debug = require('debug')('testlib'),%0A    
 http = r
@@ -2428,376 +2428,8 @@
 );%0A%0A
-        var itOrig = global.it;%0A        function it(description, testBody) %7B%0A            if (! testBody) %7B%0A                return itOrig(description);%0A            %7D%0A            return wdtesting.it(description, function () %7B%0A                this.driver = self.driver;%0A                this.app = self.app;%0A                testBody.call(this);%0A            %7D);%0A        %7D%0A%0A
     
@@ -2569,40 +2569,108 @@
     
-try %7B%0A            global.it = it
+var itOrig = global.it;%0A        try %7B%0A            global.it = decorateIt(itOrig, self, wdtesting.it)
 ;%0A  
@@ -3352,16 +3352,619 @@
 %7D);%0A%7D;%0A%0A
+function decorateIt(itOrig, self, itFromWdtesting) %7B%0A    var it = function(description, testBody) %7B%0A        if (!testBody) %7B%0A            return itOrig(description);%0A        %7D%0A        return itFromWdtesting(description, function () %7B%0A            this.driver = self.driver;%0A            this.app = self.app;%0A            testBody.call(this);%0A        %7D);%0A    %7D;%0A    // The more you know: selenium-webdriver's it.only is implemented%0A    // in terms of it, and looks it up from the context (a.k.a. global%0A    // object) at run time. We don't want to wrap it twice.%0A    it.only = itOrig.only;%0A    return it;%0A%7D%0A%0A
 function

Support `it.only' like `it'