﻿var m_bhoInstalled = false;
var m_plugin = null;

function installFirefoxExtension(extName, url, iconUrl) {
    if (document.body.onbeforeunload) document.body.onbeforeunload = null;
    if (window.onbeforeunload) window.onbeforeunload = null;
    var params = new Array();

    params[extName] = {
    	URL: url,
    	IconURL: iconUrl,
    	toString: function() { return this.URL; }
    };
    try {
    	InstallTrigger.install(params);
    	return false;
    }
    catch (err1) {
    	try {
    		window.top.InstallTrigger.install(params);
    		return false;
    	}
    	catch (err2) {
    	}
    }
    // InstallTrigger does not work; return "true" to allow <a> to proceed with href.
    return true;
}

function initBHO2(plugin) {
    m_plugin = plugin;
    initBHO();
}

function initBHO() {
    m_bhoInstalled = true;
    m_pluginInitialized = true;
}

function GetPlugin() {
    if (m_extensionInitialized)
        return moz_wrapper;
    if (m_pluginInitialized)
        return (m_plugin != null) ? m_plugin : external;
    var wnd = window.parent;
    while (wnd != null) {
        wnd = (wnd != wnd.parent) ? wnd.parent : null;
    }
    return null;
}

// Firefox extension

var m_extensionInitialized = false;

var FFH_MAX_CALLS = 63; // MUST be an all-bits-are-1 value since it will be used with an AND operator to wrap
var FFH_ARG_NULL = 0;
var FFH_ARG_INT = 1;
var FFH_ARG_STRING = 2;
var FFH_ARG_VOID = 3;
var FFH_ARG_BOOLEAN = 4;

var FFH_ARGTYPES = ["null", "int", "string", "void", "boolean"];
var FFH_INDIV = 'FFH_InDiv';
var FFH_OUTDIV = 'FFH_OutDiv';

var moz_wrapper = {
    func_cnt: 0,
    func_rets: new Array(FFH_MAX_CALLS),
    f_aliases: [],
    _init_listeners: function() {
        /* add listeners now, functions will exist */
        moz_wrapper.f_aliases = [
						{ f_event: "initBHO", f_function: initBHO, f_ret: FFH_ARG_VOID }
					];
        var oo = document.getElementById(FFH_INDIV);
        /* annoying workaround for a FFX >= 2.0 bug where the very first event is being skipped */
        if (oo) {
            /* set listener to capture our return values */
            oo.addEventListener("retFunc", moz_wrapper.func_return, false);
            /* set listener to capture our event calls */
            oo.addEventListener("doFunc", moz_wrapper.event_call, false);
            m_extensionInitialized = moz_wrapper.func_call(["is_installed"]);
        } else alert('Object ' + FFH_INDIV + ' not found!');
    },

    encodeargs: function(args) {
        var hdr;

        var _encodeargs = function(args) {
            var body = '';
            var types = [];

            for (arg in args) {
                var a = args[arg];
                switch (typeof (a)) {
                    case 'string':
                        types.push('string:' + a.length);
                        body += a;
                        break;

                    case 'number':
                        var as = a.toString();
                        types.push('number:' + as.length);
                        body += as;
                        break;

                    case 'object': // functions are not supported, don't worry
                        if (a == null) { // null is considered as object too?
                            types.push('null:0');
                            break;
                        }
                        var ao = _encodeargs(a);
                        body += ao;
                        types.push('object:' + ao.length);
                        break;

                    case 'boolean':
                        types.push('bool:1');
                        body += a ? '1' : '0';
                        break;

                }
            }

            return types.join(',') + "\n" + body;
        };

        hdr = _encodeargs(args);
        return cmd = hdr;
    },

    decodeargs: function(cmd) {
        var args = [];
        var spos, i;
        var header, values, valtype, vallen, seppos;

        if ((spos = cmd.indexOf("\n")) > -1) {
            header = cmd.substring(0, spos).split(",");
            values = cmd.substring(spos + 1);

            spos = 0;
            for (i = 0; i < header.length; i++) {
                seppos = header[i].indexOf(":");
                if (seppos != -1) {
                    valtype = header[i].substring(0, seppos);
                    vallen = parseInt(header[i].substring(seppos + 1));
                    switch (valtype) {
                        case 'string':
                            args.push(values.substr(spos, vallen));
                            break;

                        case 'number':
                            args.push(parseFloat(values.substr(spos, vallen)));
                            break;

                        case 'object':
                            args.push(this.decodeargs(values.substr(spos, vallen)));
                            break;

                        case 'bool':
                            args.push(values.substr(spos, vallen) == '1');
                            break;

                        case 'null':
                            args.push(null);
                            break;

                    }
                }
                spos += vallen;
            }
        }

        return args;
    },

    /* Own event calls */
    event_call: function(evt) {
        var f_alias = null; // function-to-call
        var f_pars = [];
        var f_ret = 0;
        var f_rettype = FFH_ARG_NULL;
        var f_a = moz_wrapper.f_aliases;
        if (!evt) return;

        for (var i = 0; i < f_a.length; i++) {
            if (evt.prevValue == f_a[i].f_event) { // it's this one
                f_alias = i;
                break; // stop searching
            }
        }

        if (f_alias != null) { // explicitly using !=null, because just (f_alias) and f_alias==0 will be considered as false
            var args = moz_wrapper.decodeargs(evt.newValue);
            f_ret = f_a[f_alias].f_function.apply(this, args);
            f_rettype = f_a[f_alias].f_ret;
        }

        if (evt.relatedNode) {
            var evObj = document.createEvent('MutationEvent');
            evObj.initMutationEvent('retFunc', true, false, null, FFH_ARGTYPES[f_rettype], f_ret, "AttrName", evt.attrChange);
            evt.relatedNode.dispatchEvent(evObj);
        }
    },

    /* Extension-function-call code */
    func_call: function(args) {
        if (args.length < 1) return null; /* no functionname defined */
        var func_name = args.shift();
        var func_args = moz_wrapper.encodeargs(args);

        moz_wrapper.func_cnt &= FFH_MAX_CALLS; // wrap

        /* extension is listening on this DIV */
        var fireOnThis = document.getElementById(FFH_OUTDIV);

        if (fireOnThis) {
            var evObj = window.content.document.createEvent('MutationEvent');
            var my_func_cnt = this.func_cnt++; // assign a return position for ourself and increase cnt for other async calls
            evObj.initMutationEvent('doFunc', true, false, document.getElementById(FFH_INDIV),
							func_name, func_args, "AttrName", my_func_cnt);
            fireOnThis.dispatchEvent(evObj);
        } else {
            /* DIV missing, return null */
            return null;
        }

        /* func_return should've filled this array position */
        return moz_wrapper.func_rets[my_func_cnt];
    },

    func_return: function(e) {
        /* gets called for return values of our called functions */
        switch (e.prevValue) {
            case 'string': moz_wrapper.func_rets[e.attrChange] = e.newValue; break;
            case 'int': moz_wrapper.func_rets[e.attrChange] = parseInt(e.newValue); break;
            case 'boolean': moz_wrapper.func_rets[e.attrChange] = (e.newValue == 'true'); break;
            case 'null':
            case 'void':
            default: moz_wrapper.func_rets[e.attrChange] = null;
        }
    }
};

if (window.navigator.userAgent.toLowerCase().indexOf("firefox") != -1)
    window.addEventListener("load", moz_wrapper._init_listeners, false);


/////////////////////////////////////////////////////////////////////////////
//IE Min and Max version
var isIE = false;
var minIEversion = 6
var maxIEversion = 8

//Firefox Min and Max version
var minFFversion = 2
var maxFFversion = 3

//sysversion array, all operating systems and versions are present here
sysversion = new Array()
sysversion[0] = new Array()
sysversion[0][0] = ["Windows", "95;95", "98;98", "NT 4.0;NT4", "NT 5.0;2000", "NT 5.2;2003 server", "NT 5.1;XP", "NT 6.0;Vista", "Win 9x 4.90;ME", "CE;CE", "NT 6.1;7"]
sysversion[0][1] = ["Mac", "OS 9;OS 9", "OS X;OS X"]
sysversion[0][2] = ["Linux"]
sysversion[0][3] = ["Symbian"]
sysversion[0][4] = ["Nintendo", "Wii"]

function checkBrowser() {
    if (navigator.appName.match(/internet explorer/ig)) isIE = true;
    browserVersion = navigator.userAgent;
    if (!isIE) {
        browserVersion = navigator.appName + " " + parseFloat(navigator.appVersion)
        if (browserVersion.match(/netscape/ig)) {
            if (navigator.userAgent.match(/firefox/ig)) {
                browserVersion = navigator.userAgent.slice(navigator.userAgent.search(/firefox/i)).split(/\s/)[0]
            }
            else if (navigator.userAgent.match(/chrome/ig)) {
                var chromeVer = navigator.userAgent.match(/chrome\/.+\s/ig).toString().replace(/chrome\//ig, "");
                browserVersion = "Google Chrome " + retrieveMajorMinor(chromeVer);
            }
            else if (navigator.userAgent.match(/safari/ig)) {
                var safariVer = navigator.userAgent.match(/version\/.+\s/ig).toString().replace(/version\//ig, "");
                browserVersion = "Safari " + retrieveMajorMinor(safariVer);
            }
            else {
                browserVersion = 'Netscape gebaseerde browser';
            }
        }
    }
    else {
        browserVersion = navigator.appName + navigator.appVersion.split(/;/g)[1]
    }

    // detect if browser is firefox or internet explorer when not end function and return false
    if (browserVersion.match(/internet explorer/ig) || browserVersion.match(/firefox/ig)) {
        if (isIE) {
            //check Browser version IE
            var ieVersion = navigator.appVersion.split(/;/g)[1];
            if (ieVersion.trim) ieVersion = ieVersion.trim(); // only in IE9 standards
            ieVersion = parseInt(ieVersion.split(/\s/)[1]);
            browserVersion = browserVersion.replace(/MSIE/ig, "").replace(/microsoft/ig, "");
            if (ieVersion >= minIEversion)
                this.isBrowserSupported = true;
            if (ieVersion > minIEversion)
                this.isBrowserOptimal = true;
        }
        else {
            //check Browser version Firefox
            fireFoxVersion = parseInt(browserVersion.split(/\//)[1].split(/\./ig)[0])
            browserVersion = browserVersion.replace(/\//ig, " v");
            if (fireFoxVersion >= minFFversion) {
                this.isBrowserSupported = true;
                this.isBrowserOptimal = true;
            }
        }
    }
}

function checkPlugin() {
    if (isIE) {
        if (m_bhoInstalled) {
            this.isPluginInstalled = true;
            if (m_plugin == null)
            { setPluginVersion = external.version }
            else
            { setPluginVersion = m_plugin.version }
        }
        else
        { setPluginVersion = 0 }

    }
    else {
        if (moz_wrapper.func_call(["get_version"]) != undefined) {
            this.isPluginInstalled = true;
            setPluginVersion = moz_wrapper.func_call(["get_version"]) 
        }
        else
        { setPluginVersion = 0 }
    }
}

function doTest(evnt) {
    this.resultsArray = ""
    this.resultsArray = new Array();
    this.resultsArray[0] = new Array();
    this.eventCatcher = evnt;
    this.isPluginInstalled = false;
    this.isBrowserSupported = false;
    this.isBrowserOptimal = false;
}

doTest.prototype.browser = checkBrowser
doTest.prototype.plugin = checkPlugin

function startTest(e) {
    if (!e)// event catcher, when e is not present e will be set as window.event
    {
        if (window.event) {
            var e = window.event
        }
    }

    var testResults = new doTest(e);
    testResults.browser();
    testResults.plugin();
    return testResults;
}


function XmlLib() {
    this.CreateXslProcessor = function(u) {
        var d = this.LoadXml(u);

        if (typeof ActiveXObject != 'undefined') {
            var df = this.CreateXmlDocument(true); // free threaded
            df.loadXML(d.xml);

            var t = this.CreateXslTemplate();
            t.stylesheet = df;
            return t.createProcessor();
        }
        else {
            var prc = new XSLTProcessor();
            prc.importStylesheet(d);
            return prc;
        }
    }

    this.LoadXml = function(u) {
        var request = this.CreateHttpRequest()
        var errMsg;
        request.open("GET", u, false)
        request.send(null);

        if (request.status == 200) {
            var ctype = request.getResponseHeader("Content-Type");
            if (ctype.indexOf("text/xml") >= 0) {
                var doc = this.GetResponseXML(request);
                return doc;
            }
        }
    }

    this.CreateXmlDocument = function() {
        var xmlDocument = null;

        if (document.implementation && document.implementation.createDocument) {
            xmlDocument = document.implementation.createDocument("", "", null);
            xmlDocument.async = false;
        }
        else {
            var progid = "Msxml2.DOMDocument";

            if (arguments[0])
                progid = "Msxml2.FreeThreadedDOMDocument";

            try { xmlDocument = new ActiveXObject(progid + ".3.0"); }
            catch (e) { xmlDocument = new ActiveXObject(progid); }

            xmlDocument.async = false;
            xmlDocument.validateOnParse = true;
            xmlDocument.setProperty("SelectionLanguage", "XPath");
        }

        return xmlDocument;
    }
    

    this.CreateHttpRequest = function() {
        var xmlHttp = null;
        try { xmlHttp = new XMLHttpRequest(); }
        catch (eout) {
            try { xmlHttp = new ActiveXObject("MSXML2.XMLHTTP.3.0"); }
            catch (ein) { xmlHttp = new ActiveXObject("MSXML2.XMLHTTP"); }
        }
        return xmlHttp;
    }

    this.GetResponseXML = function(request) {
        var doc = request.responseXML;
        return doc;
    }

    this.CreateXslTemplate = function() {
        var xsl = null;
        try {
            xsl = new ActiveXObject("Msxml2.XSLTemplate.3.0");
        }
        catch (e) {
            try {
                xsl = new ActiveXObject("Msxml2.XSLTemplate"); // try versionindependent progid
            }
            catch (x) {
            }
        }
        return xsl;
    }

    this.Transform = function(xmlUrl, xsl) {
        var doc = this.CreateXmlDocument(true);
        if (typeof ActiveXObject != 'undefined') {
            var d = this.LoadXml(xmlUrl);
            doc.loadXML(d.xml);
            xsl.input = doc;
            xsl.transform();
            return xsl.output;
        }
        else {
            doc.load(xmlUrl);
            return (new XMLSerializer).serializeToString(xsl.transformToDocument(doc));
        }
    }
}

