
(function() {

var cookie_leadsource, leadsources;


/** The cookie to use to store the current leadsource
 */
cookie_leadsource = {
    cookie: 'leadsource',
    domain: '.optilead.co.uk'
};


/** The leadsources
 *
 * Leadsource attributes:
 *    referrer: A regexp to match the referrer against. Must match if present
 *    loction:  A regexp to match the location against. Must match if present
 *    priority: Priority of leadsource. Lower = more important
 *    timeout:  Timeout of this leadsource, for when users do not match any
                missing/null == timeout at end of browser session
 *    replace_numbers:  Array of objects with .from and .to to change
 *                      .from must be a string with no spaces
 *                      .to must be in the format you want the number to appear
 *
 * We determine if the customer has come from a search engine if the referrer
 * has a "&q=" parameter in it. No, it's not perfect.
 *
 * We determine if the customer has come from google if the referrer domain
 * has a ".google." part in it. No, it's not perfect either.
 */
leadsources = {
    /*
     * Anyone coming in from a search engine with a search term of 'Optilead'
     * sees the current number.
     */
    anysearch_optilead: {
        referrer: /(\?|\?[^#]*&)q=[^&#]*optilead/i,
        priority: 5,
        timeout: null
    },

    /*
     * Anyone who comes from a search engine with ANY other search term see's
     * a different 0844
     */
    anysearch_other: {
        referrer: /(\?|\?[^#]*&)q=/i,
        priority: 10,
        replace_numbers: [
            { from: '08444482222', to: '0844 409 8220' }
        ],
        timeout: null
    },

    /*
     * anyone who comes in from google with any PPC campaign ID sees another
     * 0844 number.
     */
    google_ppc: {
        referrer: /^[^:]*:\/\/[^\/]*\.google\./i,
        location: /(\?|\?[^#]+&)gclid=/i,
        priority: 0,
        replace_numbers: [
            { from: '08444482222', to: '0844 409 8221' }
        ],
        timeout: null
    },

    /* test */
    test: {
        location: /test.html$/i,
        priority: 100,
        replace_numbers: [
            { from: '08444482222', to: '01508 480 241' }
        ],
        timeout: null
    }
};


/** URL encode a value.
 *
 * \param s String to encode
 * \param slash Replacment for slash character ('/') - optional.
 *
 * Needed at least for encoding cookie values. Even though some recommend to
 * use encodeURIcomponent() when encoding cookie values[0], that function does
 * not encode parentheses, which are not legal HTTP "token" characters[1],
 * which are in turn the allowable characters in cookies[2]. :-(
 *
 * All characters are encoded except " ", ",", "-", ".", 0-9, A-Z, a-z
 *
 * [0] https://developer.mozilla.org/en/document.cookie
 * [1] http://tools.ietf.org/html/rfc2616#section-2.2
 * [2] http://tools.ietf.org/html/rfc2965#section-3.1
 */
function _fujswclib_urlEncode(s, slash) {
    var enc, i, c;
    enc = '';
    for (i = 0; i < s.length; ++i) {
        c = s.charCodeAt(i);
        if (c <= 0xf) {
            enc += '%0' + c.toString(16);
        }
        else if (c == 0x2f) {
            enc += slash || '%2f';
        }
        else if ((c >= 0x10 && c <= 0x19)
                || (c >= 0x21 && c <= 0x2b)
                || (c >= 0x3a && c <= 0x40)
                || (c >= 0x5b && c <= 0x60)
                || (c >= 0x7b && c <= 0x7f))
        {
            enc += '%' + c.toString(16);
        }
        else if (c >= 0x80) {
            enc += encodeURIComponent(String.fromCharCode(c));
        }
        else {
            enc += String.fromCharCode(c);
        }
    }
    return enc;
}

/** Create/write a cookie
 */
function _fujswc_createCookie(cookie, value) {
    var date, expires, str;
    if (cookie.timeout) {
        date = new Date();
        date.setTime(date.getTime() + (cookie.timeout * 1000));
        expires = '; expires=' + date.toGMTString();
    }
    else {
        expires = '';
    }
    str = cookie.cookie + '=' + _fujswclib_urlEncode(value) + expires + '; path=/';
    if (cookie.domain) {
        str += '; domain=' + cookie.domain;
    }
    document.cookie = str;
}

/** Read a cookie
 */
function _fujswc_readCookie(cookie)
{
    var nameEQ = cookie.cookie + '=',
        ca = document.cookie.split(';'),
        i, c;
    for (i = 0; i < ca.length; ++i) {
        c = ca[i];
        while (c.charAt(0) === ' ') {
            c = c.substring(1, c.length);
        }
        if (c.indexOf(nameEQ) === 0) {
            c = c.substring(nameEQ.length, c.length);
            try {
                return decodeURIComponent(c);
            }
            catch (e) {
                return c;
            }
        }
    }
    return null;
}

/** slice() function for the "arguments" parameter of functions.
 *
 * "arguments" is not an array, even though it has a "length" property and
 * operator[] which acts like a 0-based numerical array index. Because it is not
 * a real array, it does not have a "slice()" member function.
 */
function _fujswc_argSlice(args, start)
{
    var a, i;
    for (a = [], i = start; i < args.length; ++i) {
        a.push(args[i]);
    }
    return a;
}

/** Send a log
 */
function _fujswc_log(data)
{
    alert(data);
}

/** Send an error log
 */
function _fujswc_logErr(err, data)
{
    var s;

    try {
        s = 'error'
            + '/file/' + err.fileName
            + '/line/' + err.lineNumber
            + '/type/' + err.name
            + '/stack/' + err.stack
            + '/msg/' + err.message
            + '/data/' + data;
    }
    catch (e2) {
        s = 'Unexpected error: ' + e2;
    }

    /*alert(s);*/
    return _fujswc_log(s);
}

/** Remove whitespace
 *
 * IE has broken \s
 */
function _fujswc_nows(str)
{
    return str.replace(/[ \f\n\r\t\v\u00A0\u2028\u2029]+/g, '');
}

/** Get a text node within a document element
 *
 * \param elem Element to get text node from
 * \param fn Function to check for text node to return
 *
 * fn is called for each text node within elem. If fn returns a "truthy"
 * value then processing stops and that value is returned.
 */
function _fujswc_getTextNode(elem, fn)
{
    function internal(node) {
        var name, i, r;

        switch (node.nodeType) {
        case 1:  /*ELEMENT_NODE*/
            name = node.tagName.toLowerCase();
            if (name == 'script'
                    || name == 'noscript')
            {
                break;
            }
            for (i = 0; i < node.childNodes.length; ++i) {
                r = internal(node.childNodes.item(i));
                if (r) {
                    return r;
                }
            }
            break;

        case 3:  /*TEXT_NODE*/
        case 4:  /*CDATA_SECTION_NODE*/
            return fn(node);

        case 9:  /*DOCUMENT_NODE*/
            return internal(node.documentElement);

        /*case 2:*/  /*ATTRIBUTE_NODE*/
        /*case 5:*/  /*ENTITY_REFERENCE_NODE*/
        /*case 6:*/  /*ENTITY_NODE*/
        /*case 7:*/  /*PROCESSING_INSTRUCTION_NODE*/
        /*case 8:*/  /*COMMENT_NODE*/
        /*case 10:*/ /*DOCUMENT_TYPE_NODE*/
        /*case 11:*/ /*DOCUMENT_FRAGMENT_NODE*/
        /*case 12:*/ /*NOTATION_NODE*/
        /*    break;*/
        }

        return null;
    }

    if (!elem || !fn) {
        return null;
    }

    return internal(elem);
}

/** \brief Adds an event listener to an element.
 *
 * \param elem Element to add event to.
 * \param evt Event to add listener on.
 * \param fn Function to call on the event.
 * \param arguments[3...] other arguments to be passed to \p fn.
 *
 * When #fn is called, it will be called with the event as the first parameter,
 * and any extra args passed to this function (args 3...) will be passed
 * as extra args to #fn (i.e. as args 1...)
 */
function _fujswc_addEventListener(elem, evt, fn)
{
    var args = _fujswc_argSlice(arguments, 3);

    /* The listener closure fn. Makes sure that the event is passed as arg 1
     * and that all other arguments are passed as subsequent args
     */
    function cfn(e) {
        if (!e) {
            /* Stupid IE */
            e = window.event;
        }
        if (!e.target) {
            /* Even more stupid IE */
            e.target = e.srcElement;
        }
        try {
            return fn.apply(this, [e].concat(args));
        }
        catch (err) {
            _fujswc_logErr(err,
                    'Listening on elem ' + elem.id + ' for ' + evt);
            return;
        }
    }

    if (!elem) {
        return;
    }
    if (typeof(elem) == 'string') {
        elem = document.getElementById(elem);
        if (!elem) {
            return;
        }
    }

    if (elem.addEventListener) {
        elem.addEventListener(evt, cfn, false);
    }
    else if (elem.attachEvent) {
        elem.attachEvent('on' + evt, cfn);
    }
}


function start()
{
    var ls, i, lsdata, re_num;

    ls = _fujswc_readCookie(cookie_leadsource);

    for (i in leadsources) {
        if ((!leadsources[i].referrer
                    || leadsources[i].referrer.test(document.referrer.toString()))
                && (!leadsources[i].location
                    || leadsources[i].location.test(document.location.toString()))
                && (!ls
                        || !leadsources[ls]
                        || leadsources[i].priority < leadsources[ls].priority))
        {
            ls = i;
        }
    }

    if (ls && leadsources[ls]) {
        lsdata = leadsources[ls];
        _fujswc_createCookie({
                    cookie: cookie_leadsource.cookie,
                    timeout: lsdata.timeout,
                    domain: cookie_leadsource.domain
                }, ls);
    }

    if (lsdata && lsdata.replace_numbers) {
        re_num = new RegExp('0'
                + '[ \f\n\r\t\v\u00A0\u2028\u2029]*[128]'
                + '([ \f\n\r\t\v\u00A0\u2028\u2029]*\\d){8,9}', 'g');

        _fujswc_getTextNode(document,
                function(node) {
                    var text = node.data,
                        changes = false,
                        res,
                        num;

                    re_num.lastIndex = 0;
                    while ((res = re_num.exec(text)) !== null) {
                        num = _fujswc_nows(res[0]);
                        for (i = 0; i < lsdata.replace_numbers.length; ++i) {
                            if (lsdata.replace_numbers[i].from == num) {
                                text = text.substr(0, res.index)
                                    + lsdata.replace_numbers[i].to
                                    + text.substr(re_num.lastIndex);
                                re_num.lastIndex = res.index
                                    + lsdata.replace_numbers[i].to.length;
                                changes = true;
                            }
                        }
                    }
                    if (changes) {
                        node.data = text;
                    }
                });
    }
}


_fujswc_addEventListener(window, 'load', start);

}());


