const FAKE_NODE_ID = 'QWERT_call_log';

var startDate = new Date();

function TestSuiteAPI(backend, test_script, login, password, url) {
    this._init(backend, test_script, login, password, url);
}

TestSuiteAPI.prototype = {
    _init: function(backend, test_script, login, password, url) {
        this._out = [];

        this._login = login;
        this._password = password;
        this._url = url;

        this._result = false;

        var setTimeout = backend.setTimeout;
        var assert = backend.assert;
        var assertTrue = backend.assertTrue;
        var assertFalse = backend.assertFalse;
        var assertEquals = backend.assertEquals;
        var assertNotEquals = backend.assertNotEquals;
        var assertNull = backend.assertNull;
        var assertNotNull = backend.assertNotNull;
        var assertUndefined = backend.assertUndefined;
        var assertNotUndefined = backend.assertNotUndefined;
        var assertNaN = backend.assertNaN;
        var assertNotNaN = backend.assertNotNaN;
        var fail = backend.fail;

        var makeAuthorizer = function(loginNodeId, passwordNodeId, login, password) {
            function authorize(loginNodeId, passwordNodeId, login, pass) {
                var name = document.getElementById(loginNodeId);
                var password = document.getElementById(passwordNodeId);
                name.value = login;
                password.value = pass;
                password.form.submit();
            }
            return "(function(){var authorize = " + authorize + "; authorize('" + loginNodeId + "', '" + passwordNodeId + "', '" + login + "', '" + password + "');})();";
        };

        this._log = [];

        backend.connect("load", this._onLoad.bind(this));
        backend.connect("unload", this._getLog.bind(this));
        this._backend = backend;

        eval(backend.getContent(test_script));

        this.test = new Test(this);
    },

    _prepare: function() {
        eval(this._backend.getContent('../scripts/third_party/convert2RegExp.js'));

        this.injectScript(this._backend.getContent('testUtils.js'));

        let src = '';
        let content = this._backend.getContent(this.test.scriptName);
        src += content;

        var matches = src.match(/^\/\/ @include.+$/gm).map(function (x) {
                                                               return UW_convert2RegExp(x.substr(x.match(/^\/\/ @include\s+/)[0].length));
                                                           });

        function getParams(name) {
            var result = String(src).match(new RegExp('^// @' + name + '.+$', 'gm'));
            if (!result)
                return [];
            return result.map(function (x) {
                                  return x.substr(x.match(new RegExp('^// @' + name + '\\s+', 'gm'))[0].length);
                              });
        }
        var dependencies = getParams('require');
        for (let i = 0; i < dependencies.length; i++) {
            content = this._backend.getContent('../common/' + dependencies[i]);
            src = content + src;
        }

        var uri = this._backend.getLocation();
        var correctPage = false;
        for (let i = 0; i < matches.length; i++) {
            if (uri.match(matches[i])) {
                correctPage = true;
            }
        }

        if (correctPage)
            this.injectScript(src);
    },

    _getLog: function() {
        try {
            var i;
            let log = JSON.parse(this._backend.getTextFromNode(FAKE_NODE_ID));
            for (i = 0; i < log.length; i++) {
                this._log.push(log[i]);
            }

            log = JSON.parse(this._backend.getTextFromNode('QWERT_console_log'));
            for (i = 0; i < log.length; i++) {
                this._out.push(log[i]);
            }
        } catch (x) {
        }
    },

    _onLoad: function() {
        if (this._backend.saveHTML) {
            this._backend.saveHTML(this.test.scriptName.replace('/', ' '), startDate);
        }

        if (!this.test)
            return;

        this._prepare();

        this.test.onLoad(this._backend.getLocation());
    },

    open: function(url) {
        this._backend.loadURI(url);
    },
    finish: function() {
        this._getLog();
        let result = false;
        try {
            this.test.validateCallLog(this._log, this._out);
            this._processReportLog()
            result = true;
        } catch (x) {
            var i;
            for (i = 0; i < this._log.length; i++) {
                this._backend.print('Log[' + i + ']: ' + this._log[i].func);
            }
            this._backend.print("Validation failure calling: '"
                                + x.comment
                                + "', error: "
                                + x.jsUnitMessage
                               );
        }

        if (result) {
            this._backend.print(this.test.scriptName + ' PASS');
            this._result = true;
        } else {
            this._backend.print(this.test.scriptName + ' FAILED');
        }
        this._end();
    },
    invokeCallback: function(funcName, id) {
        if (id) {
            this.injectScript('Unity._invoke("' + funcName + '", "' + id + '")');
        } else {
            this.injectScript('Unity._invoke("' + funcName + '")');
        }
    },
    result: function() {
        return this._result;
    },

    _end: function() {
        this._backend.finish();
    },
    skipTest: function() {
        this._backend.print(this.test.scriptName + ' SKIPPED');
        this._end();
    },
    injectScript: function(src) {
        this._backend.injectScript(src);
    },

    getLogin: function() {
        return this._login;
    },
    getPassword: function() {
        return this._password;
    },
    getUrl: function() {
        return this._url;
    },
    _processReportLog: function () {
        var i;
        for (i = 0; i < this._out.length; i++) {
            var found, logEntry = this._out[i];

            found = logEntry.match(/^REPORT: ((\w+): .*)/);
            if (found !== null) {
                this._backend.assertFalse(found[1], found[2] === 'ERROR');
            }
        }
    }
};
