#!/usr/bin/env gjs

const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const WebKit = imports.gi.WebKit;
const Cairo = imports.cairo;

const Lang = imports.lang;
const Mainloop = imports.mainloop;
const JsUnit = imports.jsUnit;

var TOP_SRCDIR = '';

var headless = true; // Requires X11
var passTest = false;
var slowDownFactor = 1;

// Parameters
var login = '';
var password = '';
var url = '';

function Backend() {
    this._init();
}

Backend.prototype = {
    _init: function () {

        Gtk.init(null, null);

        this._scrolledWindow = new Gtk.ScrolledWindow();

        if (!headless) {
            this._window = new Gtk.Window({ type: Gtk.WindowType.TOPLEVEL, decorated: true });
            this._window.set_position(Gtk.WindowPosition.CENTER);
            this._window.connect('destroy', function() {
                Gtk.main_quit();
            });

            this._scrolledWindow.set_size_request(1024, 800);
            this._window.add(this._scrolledWindow);

            this._window.show_all();
        }
        this._webview = new WebKit.WebView({ visible: true });
        let settings = this._webview.get_settings();
        settings.enable_plugins = true;
        settings.html5_local_storage_database_path = '/tmp/webapps_' + Math.random(); // FIXME: g_file_new_tmp didn't work
        settings.enable_xss_auditor = false;

        this._scrolledWindow.add(this._webview);
    },

    saveHTML: function(name, date) {
        if (!this._saveCounter)
            this._saveCounter = 1;
        else
            this._saveCounter++;

        let resultsDir = TOP_SRCDIR + 'results/' + name + '/' + date.toISOString();

        GLib.mkdir_with_parents(resultsDir, 999);

        // TODO: after WebKitGtk 1.11 release, replace with webkit_web_view_save
        let source = this._webview.get_dom_document().get_document_element().get_inner_html();

        GLib.file_set_contents(resultsDir + '/page' + this._saveCounter + '.html', source);
    },

    connect: function(eventName, callback) {
        if (eventName == "load") {
            this._webview.connect('notify::load-status', function(view, frame) {
                if (this._webview.load_status == WebKit.LoadStatus.FINISHED
                    || this._webview.load_status == WebKit.LoadStatus.FAILED) {
                    callback();
                }
            }.bind(this));
        } else if (eventName == "unload") {
            this._webview.connect('navigation-policy-decision-requested', callback);
        } else {
            throw new Error();
        }
    },

    getContent: function(path) {
        if (path.match(/^\//)) {
            let [res, content] = GLib.file_get_contents(path);
            return String(content);
        }
        let [res, content] = GLib.file_get_contents(TOP_SRCDIR + path);
        return String(content);
    },

    loadURI: function(uri) {
        this._webview.load_uri(uri);
    },

    assert: function() {
        return JsUnit.assert.apply(null, arguments);
    },
    assertTrue: function() {
        return JsUnit.assertTrue.apply(null, arguments);
    },
    assertFalse: function() {
        return JsUnit.assertFalse.apply(null, arguments);
    },
    assertEquals: function() {
        return JsUnit.assertEquals.apply(null, arguments);
    },
    assertNotEquals: function() {
        return JsUnit.assertNotEquals.apply(null, arguments);
    },
    assertNull: function() {
        return JsUnit.assertNull.apply(null, arguments);
    },
    assertNotNull: function() {
        return JsUnit.assertNotNull.apply(null, arguments);
    },
    assertUndefined: function() {
        return JsUnit.assertUndefined.apply(null, arguments);
    },
    assertNotUndefined: function() {
        return JsUnit.assertNotUndefined.apply(null, arguments);
    },
    assertNaN: function() {
        return JsUnit.assertNaN.apply(null, arguments);
    },
    assertNotNaN: function() {
        return JsUnit.assertNotNaN.apply(null, arguments);
    },
    fail: function() {
        return JsUnit.fail.apply(null, arguments);
    },

    injectScript: function(src) {
        this._webview.execute_script('(function() { ' + String(src) + '})();');
    },

    getLocation: function() {
        return String(this._webview.get_uri());
    },

    getTextFromNode: function(nodeName) {
        return this._webview.get_dom_document().get_element_by_id(nodeName).get_text_content();
    },

    print: function(str) {
        print(str);
    },

    finish: function() {
        Gtk.main_quit();
    },

    setTimeout: function(callback, ms) {
        Mainloop.timeout_add(ms * slowDownFactor, function() {
            callback();
            return false;
        });
    }
};

if (ARGV.length && ARGV[0] == '--show-window') {
    headless = false;
    ARGV.shift();
}

if (ARGV.length > 2 && ARGV[0] == '--slow-down-factor') {
    slowDownFactor = Number(ARGV[1]);
    if (!slowDownFactor) {
        printerr('Invalid slowDownFactor');
        slowDownFactor = 1;
    }
    ARGV.shift();
    ARGV.shift();
}

if (ARGV.length > 2 && ARGV[0] == '--login') {
    login = ARGV[1];
    if (!login) {
        printerr('Invalid login');
    }
    ARGV.shift();
    ARGV.shift();
}

if (ARGV.length > 2 && ARGV[0] == '--password') {
    password = ARGV[1];
    if (!password) {
        printerr('Invalid password');
    }
    ARGV.shift();
    ARGV.shift();
}

if (ARGV.length > 2 && ARGV[0] == '--url') {
    url = ARGV[1];
    if (!url) {
        printerr('Invalid URL');
    }
    ARGV.shift();
    ARGV.shift();
}

if (ARGV.length == 1) {
    let file = Gio.file_new_for_path(ARGV[0]);

    TOP_SRCDIR = String(file.get_parent().get_path() + '/');

    [res, content] = GLib.file_get_contents(TOP_SRCDIR + "testSuiteApi.js");
    eval(String(content));

    let suite = new TestSuiteAPI(new Backend(), file.get_path(), login, password, url);
    Gtk.main();
    if (suite.result() == false) {
        1;
    } else {
        0;
    }
} else {
    printerr('Usage: test.js [--show-window] [--slow-down-factor seconds] --login username --pasword password [--url http://site.url/] pathToTestScript');
    1;
}
