/* ----------------------------------------------------------------------------
Version: hdp-global-1.0.0.js
Author: Andrea Ottolina - AKQA
Description: Global Akqa JavaScript functions
-------------------------------------------------------------------------------
jQuery is unsed in noConflict mode due to the Prototype
library used by Sitecore CMS for it's inline page editing
-------------------------------------------------------------------------------
The most efficient jQuery selector is '#id', followed by 'tag.class'
-------------------------------------------------------------------------------
The library is namespaced into the AKQA object.
Mainly is built on Singleton and split in different *Managers* each for
every main functionality

Singleton structure
var myInstance = (function() {
  var privateVar = '';
  
  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // all private members are accesible here
    },
    publicMethod2: function () {
    }
  };
}());

-------------------------------------------------------------------------------
Please validate against JSLint (http://www.jslint.com/)
---------------------------------------------------------------------------- */

/*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
/*global window, jQuery, Cufon, console*/
//"use strict";

//wrap code in a closure to allow use of $
(function ($) {

    AKQA.log = function () {
        var enabled = false;
        if (enabled && window.console) {
            console.log(arguments);
        }
        return false;
    };

    AKQA.SettingsForTypeOnLoad = {
        'type-home-page': { footerAnimateOpened: false, footerFadeIn: true, navigationFadeIn: true },
        'type-work-home': { footerAnimateOpened: true },
        'type-client': { footerAnimateOpened: true },
        'type-case-study': { footerAnimateOpened: false },
        'type-office': { footerAnimateOpened: true }
    };

    AKQA.Events = {
        BACKGROUND_IMAGE_READY: 'AKQAEVENT.BackgroundImageReady',
        BODY_CLASS_UPDATED: 'AKQAEVENT.BodyClassUpdated',
        CAROUSEL_DATA_READY: 'AKQAEVENT.CarouselDataReady',
        CAROUSEL_HIDDEN: 'AKQAEVENT.CarouselHidden',
        CAROUSEL_IMAGE_READY: 'AKQAEVENT.CarouselImagesReady',
        CONTENT_DATA_READY: 'AKQAEVENT.ContentDataReady',
        CONTENT_HIDDEN: 'AKQAEVENT.ContentHidden',
        CONTENT_VISIBLE: 'AKQAEVENT.ContentVisible',
        COVER_HIDDEN: 'AKQAEVENT.CoverHidden',
        COVER_VISIBLE: 'AKQAEVENT.CoverVisible',
        FADE_IMAGE_READY: 'AKQAEVENT.FadeImageReady',
        FADE_VISIBLE: 'AKQAEVENT.FadeVisible',
        FADE_HIDDEN: 'AKQAEVENT.FadeHidden',
        PAGER_DATA_READY: 'AKQAEVENT.PagerDataReady'
    }
    AKQA.Events.CONTENT_REPLACE = [AKQA.Events.CONTENT_DATA_READY, AKQA.Events.COVER_VISIBLE].join(' ');
    AKQA.Events.ANIMATE_CONTENT = [AKQA.Events.BACKGROUND_IMAGE_READY, AKQA.Events.FADE_IMAGE_READY].join(' ');
    AKQA.Events.ANIMATE_CAROUSEL = [AKQA.Events.CAROUSEL_IMAGE_READY, AKQA.Events.COVER_VISIBLE, AKQA.Events.CAROUSEL_HIDDEN].join(' ');

    AKQA.MManager = (function () {

        function replace() {
            //AKQA.log('MManager');
            $('.m').replaceWith(function (i, html) {
                var html = ('' + html).replace(/ dot /gi, '&#46;').replace(/ at /gi, '&#64;');
                var a = html.match(/(<br\s*\/?>)?\s*\(([^)]+)\)/i);
                if (a) {
                    html = html.replace(a[0], '');
                    a = a[2];
                } else {
                    a = html.match(/[a-z0-9._&#;-]+(&#64;|@)[a-z0-9._&#;-]+/i);
                    if (a) {
                        a = a[0];
                    } else {
                        return html;
                    }
                }
                return '<a title="' + a + '" href="' + '&#109;&#97;' + '&#105;&#108;' + '&#116;&#111;&#58;' + a + '">' + html + '</a>';
            });
        };

        return {
            init: replace,
            refreshPage: replace
        }
    } ());

    AKQA.AnimationManager = (function () {
        var self = {};
        if (AKQA.DeviceManager.useCSSTransitions()) {

            function getProperty($element, name) {
                return $element.data('__' + name) || $element.css(name);
            }

            function saveProperty($element, name) {
                $element.data('__' + name, getProperty($element, name));
            }

            function saveProperties($element, properties) {
                for (var i = 0; i < properties.length; i++) {
                    saveProperty($element, properties[i]);
                }
            }

            //css3 animations
            self.fadeTo = function (element, opacity, duration, delay, callback) {
                $(element).filter(':hidden').css('opacity', 0).show().end().each(function () {
                    var self = this;
                    setTimeout(function () {
                        var animCss = ';opacity:' + opacity +
                            ';-webkit-transition-property:opacity' +
                            ';-webkit-transition-delay:' + delay + 'ms' +
                            ';-webkit-transition-timing-function:' + 'ease' +
                            ';-webkit-transition-duration:' + duration + 'ms';
                        if (AKQA.DeviceManager.isiOS()) {
                            // Stops flickering for CSS-animated elements in iOS WebKit.
                            // Note: Exposing this fix to WebKit in Android 2.2 causes several rendering problems.
                            animCss += ';-webkit-transform:translate3d(0,0,0)';
                        }
                        self.style.cssText += animCss;
                    }, 0);
                    setTimeout(function () {
                        if (opacity == 0) {
                            $(self).hide();
                        }
                        if (typeof callback !== 'undefined') {
                            callback.call(self);
                        }
                    }, delay + duration);
                });
            }
            self.slideDown = function (element, duration, delay, callback) {
                $(element).each(function () {
                    var self = this;
                    var $self = $(this);
                    saveProperties($self, ['padding-top', 'padding-bottom', 'margin-top', 'margin-bottom', 'overflow']);
                    if ($self.is(':hidden')) {
                        $self.css({
                            height: 0,
                            paddingTop: 0,
                            paddingBottom: 0,
                            marginTop: 0,
                            marginBottom: 0,
                            overflow: 'hidden'
                        }).show().end();
                        setTimeout(function () {
                            self.style.cssText +=
                            ';height:' + self.scrollHeight + 'px' +
                            ';padding-top:' + getProperty($self, 'padding-top') +
                            ';padding-bottom:' + getProperty($self, 'padding-bottom') +
                            ';margin-top:' + getProperty($self, 'margin-top') +
                            ';margin-bottom:' + getProperty($self, 'margin-bottom') +
                            ';-webkit-transition-property:height padding-top padding-bottom margin-top margin-bottom' +
                            ';-webkit-transition-delay:' + delay + 'ms' +
                            ';-webkit-transition-timing-function:' + 'ease' +
                            ';-webkit-transition-duration:' + duration + 'ms';
                        }, 0);
                        setTimeout(function () {
                            $self.css({
                                overflow: getProperty($self, 'overflow')
                            });
                            if (typeof callback !== 'undefined') {
                                callback.call(self);
                            }
                        }, delay + duration);
                    } else {
                        if (typeof callback !== 'undefined') {
                            callback.call(self);
                        }
                    }
                });
            }
            self.slideUp = function (element, duration, delay, callback) {
                $(element).each(function () {
                    var self = this;
                    var $self = $(this);
                    saveProperties($self, ['padding-top', 'padding-bottom', 'margin-top', 'margin-bottom', 'overflow']);
                    setTimeout(function () {
                        self.style.cssText +=
                        ';height:0' +
                        ';padding-top:0' +
                        ';padding-bottom:0' +
                        ';margin-top:0' +
                        ';margin-bottom:0' +
                        ';-webkit-transition-property:height padding-top padding-bottom margin-top margin-bottom' +
                        ';-webkit-transition-delay:' + delay + 'ms' +
                        ';-webkit-transition-timing-function:' + 'ease' +
                        ';-webkit-transition-duration:' + duration + 'ms';
                    }, 0);
                    setTimeout(function () {
                        $self.css({
                            height: self.scrollHeight,
                            paddingTop: getProperty($self, 'padding-top'),
                            paddingBottom: getProperty($self, 'padding-bottom'),
                            marginTop: getProperty($self, 'margin-top'),
                            marginBottom: getProperty($self, 'margin-bottom'),
                            overflow: 'hidden'
                        }).hide();
                        if (typeof callback !== 'undefined') {
                            callback.call(self);
                        }
                    }, delay + duration);
                });
            }

        } else {

            //jquery animations
            self.fadeTo = function (element, opacity, duration, delay, callback) {
                $(element).delay(delay).fadeTo(duration, opacity, function () {
                    // need to remove filter on IE. Also opacity style goes from 0 to 1 even if in ie is from 0 to 100
                    if (opacity === 0) {
                        $(this).hide().css({ 'opacity': '', 'filter': '' });
                    }
                    if (opacity === 1) {
                        $(this).show().css({ 'opacity': '', 'filter': '' });
                    }
                    if (typeof callback !== 'undefined') {
                        callback.call(this)
                    }
                });
            }
            self.slideDown = function (element, duration, delay, callback) {
                $(element).delay(delay).slideDown(duration, callback);
            }
            self.slideUp = function (element, duration, delay, callback) {
                $(element).delay(delay).slideUp(duration, callback);
            }
        }
        return self;
    } ());

    AKQA.FontManager = (function () {

        var useCufon = false,
            useFontFace = false,
            cufonMatrix = {
                style1: {
                    selectors: '#copy h3, label, button',
                    font: 'Albertina',
                    hover: false,
                    reliable: true
                },
                style2: {
                    selectors: '.copy p, #copy p, #copy .source a, #touts li a, #page-carousel li a, .link-button, .location, .type-search-results #main p',
                    font: 'Albertina',
                    hover: true,
                    reliable: true
                },
                style3: {
                    selectors: '#copy li',
                    font: 'Albertina',
                    hover: false,
                    reliable: true
                },
                /*style4: {
                selectors: '.jqTransformSelectWrapper',
                font: 'Albertina',
                hover: true,
                reliable: true
                },*/
                style5: {
                    selectors: 'h1',
                    font: 'Trajan-Pro',
                    hover: true,
                    reliable: true
                },
                style6: {
                    selectors: 'h2, .copy h3',
                    font: 'Trajan-Pro',
                    hover: false,
                    reliable: true
                },
                style7: {
                    selectors: '#footer-content button, #footer-content label',
                    font: 'Trajan-Pro',
                    hover: false,
                    reliable: true
                },
                style8: {
                    selectors: '#nav .menu li:not(.bullet), #sub-nav .menu li',
                    font: 'Trajan-Pro',
                    hover: true,
                    reliable: true
                },
                style9: {
                    selectors: '#footer-content .menu li',
                    font: 'Trajan-Pro',
                    hover: true,
                    reliable: true
                }
            };

        if (AKQA.DeviceManager.useFontFace()) {
            useFontFace = true;
            try { Typekit.load(); } catch (e) { }
        }

        if (AKQA.DeviceManager.useCufon()) {
            useCufon = true;
            for (var cufonStyle in cufonMatrix) {
                // This control is no longer necessary... but it's here for legacy
                if (!(AKQA.DeviceManager.isIE() && !cufonMatrix[cufonStyle].reliable)) {
                    Cufon.replace(cufonMatrix[cufonStyle].selectors, { fontFamily: cufonMatrix[cufonStyle].font, hover: cufonMatrix[cufonStyle].hover });
                }
            }
        }

        return {
            refreshPage: function () {
                if (useCufon) {
                    //AKQA.log('Font Manager', arguments.callee.caller);
                    Cufon.refresh();
                }
            },
            init: function () {
                if (useCufon) {
                    Cufon.now();
                }
            }
        };
    } ());

    AKQA.FormManager = (function () {
        function validate(selector, options) {
            $(selector).validate($.extend(options, {
                errorPlacement: function (error, element) {
                    error.insertAfter(element.parents('.form-field').find('label:first-child'));
                },
                showErrors: function (errorMap, errorList) {
                    $(selector).find('label.error').remove(); //remove all previous errors
                    this.defaultShowErrors();
                    AKQA.FontManager.refreshPage();
                },
                onfocusout: false,
                onkeyup: false,
                invalidHandler: function (form, validator) {
                    setTimeout(function () {
                        $(selector).find('label.error').each(function () {
                            $this = $(this);
                            $this.removeAttr('style');
                            if ($this.parents('#form').length) {
                                var position = $this.offset();
                                var $fieldContainer = $this.parents('.form-field');
                                var center = position.left + $this.width() / 2;
                                var lblHeight = $this.siblings('label').height();
                                if (center < $(document).width() / 2 - 50) {
                                    $this.css({
                                        visibility: 'visible',
                                        textAlign: 'right',
                                        top: lblHeight,
                                        marginLeft: -$this.width() - 10
                                    });
                                } else {
                                    $this.css({
                                        visibility: 'visible',
                                        textAlign: 'left',
                                        top: lblHeight,
                                        marginLeft: $fieldContainer.width() + 10
                                    });
                                }
                            }
                            if (AKQA.DeviceManager.isIE() && AKQA.DeviceManager.IEVersion() < 9) {
                                $this.show();
                            } else {
                                $this.fadeTo(400, 1);
                            }
                        });

                        $(selector).find('input, textarea, select').unbind('keyup.fieldChange change.fieldChange');

                        $(selector).find('input.error, textarea.error, select.error').bind('keyup.fieldChange change.fieldChange', function (event) {
                            if (event.keyCode != 9) {
                                if (AKQA.DeviceManager.isIE() && AKQA.DeviceManager.IEVersion() < 9) {
                                    $(this).parents('.form-field').find('label.error').css('visibility', 'hidden');
                                } else {
                                    $(this).parents('.form-field').find('label.error').fadeTo(400, 0);
                                }
                            }
                        });

                        AKQA.FontManager.refreshPage();
                    }, 5);
                }
            }));
        }

        return {
            validate: validate
        }
    } ());

    AKQA.ClickManager = (function () {

        function ajaxTransition($ref) {
            var re = /^http:\/\/[^\/]+/i;
            var hrefDomain = $ref.attr('href').match(re) ? $ref.attr('href').match(re)[0] : null;
            var currentDomain = document.location.href.match(re) ? document.location.href.match(re)[0] : null;
            var location = document.location.href.replace(re, '');
            var href = $ref.attr('href').replace(re, '').replace(/\/?#.*/, '');
            if ((hrefDomain === null || hrefDomain === currentDomain) && (
                    href.match(/^\/?$/) ||
                    href.match(/^\/work\b/i) ||
                    href.match(/^\/approach\b/i) ||
                    href.match(/^\/career\b/i) ||
                    href.match(/^\/contact\b/i) ||
                    href.match(/^\/privacy-policy$/i))) {
                if (!location.match(/^\/#.*$/)) {
                    href = href.replace(/^\/?$/, '/#/');
                    href = href.replace(/^\/work((\/.+)?)$/i, '/#/work$1');
                    href = href.replace(/^\/approach((\/.+)?)$/i, '/#/approach$1');
                    href = href.replace(/^\/career((\/.+)?)$/i, '/#/career$1');
                    href = href.replace(/^\/contact((\/[^\/]+)?)((\/.+)?)$/i, '/#/contact$1$3');
                    if (href.match(/^\/privacy-policy$/i)) {
                        //only used when privacy policy is shown from non-ajax page
                        AKQA.Modals.showPrivacyPolicy(href);
                    } else {
                        document.location.href = href;
                    }
                } else if (href.match(/^\/privacy-policy$/)) {
                    href = location.replace(/^[^#]*#/, '').replace(/\/$/, '') + '/privacy-policy';
                    $.address.value(href);
                } else if (href.match(/^\/?$/) && location.match(/^\/#\/?$/)) {
                    //second special case to refresh home page
                    AKQA.DeeplinkingManager.refreshPage();
                } else if (href.match(/^\/work$/) && location.match(/^\/#\/work$/)) {
                    //special case to refresh work page
                    AKQA.DeeplinkingManager.refreshPage();
                } else {
                    $.address.value(href);
                }
                setTimeout(function () {
                    AKQA.PageManager.Navigation.update();
                }, 0);
                return true;
            }
            return false;
        };

        function playMobileVideo($ref) {
            var href = $ref.attr('href');
            $.get(href, function (data) {
                $container = $(data);
                var videoURL = $container.find('video').attr('src') || $container.find('source').attr('src');
                document.location.href = videoURL;
            });
        };

        function popupCenter($ref, title, w, h) {
            var title = title || 'AKQA',
                w = w || 600,
                h = h || 400,
                left = (screen.width / 2) - (w / 2),
                top = (screen.height / 2) - (h / 2),
                href = $ref.attr('href');

            var targetWin = window.open(href, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left);
        };

        function handleClicks() {
            $('a').live('click', function (event) {
            	var $link = $(this);
                
                // D. Odell: force links to /work/paris on the homepage to link to /work instead
                if ($link.attr('href') === '/work/paris' || $link.attr('href') === '/work/bonjour') {
                	$link.attr('href', '/work');
                }
                
                
                if ($link.hasClass('nav-videos')) {
                    //special case for smartphones
                    if (!AKQA.DeviceManager.isMobileWebkit() || AKQA.DeviceManager.isiOS()) {
                        ajaxTransition($link);
                    } else {
                        playMobileVideo($link);
                    }
                } else if ($link.hasClass('nav-facebook-share')) {
                    popupCenter($link);
                } else if ($link.attr('href').match(/^#footer-content$/)) {
                    if ($link.hasClass('open')) {
                        AKQA.PageManager.Footer.close();
                    } else {
                        AKQA.PageManager.Footer.open();
                    }
                } else if (ajaxTransition($link)) {
                    //continue
                } else {
                    //treat as normal link
                    return true;
                }
                event.stopImmediatePropagation();
                return false;
            });
        };

        return {
            init: handleClicks
        }
    } ());

    AKQA.DeeplinkingManager = (function () {
        var url, urlPathNames, pathNames, root = 0, hasLanguage = false, doDeeplink = false,
        footerLinksToSelectWithMatchingDepth = {
            work: 2,
            approach: 2,
            contact: 2
        },
        deeplinkHistory = [],
        pageType = [],
        updatePageType = function () {
            var $body = $('body'),
                bodyClasses = (bodyClasses = AKQA.Utility.replaceClassFromData($body)) ? bodyClasses : $body.attr('class'),
                bodyId = (bodyId = AKQA.Utility.replaceIdFromData($body)) ? bodyId : $body.attr('id'),
                type;
            if (type = bodyClasses.match(/type-[^ ]+/i)) {
                pageType.unshift(type[0]);
                AKQA.EventManager.publish(AKQA.Events.BODY_CLASS_UPDATED);
            }
        },
        updateFooterLinks = function () {
            var deeplinkValue = $.address.pathNames(),
                compareUrl,
                links = $('#footer-content').find('li');
            //this function checks a set number of items in the deeplink path, and if they match, it highlight the relevant link in the footer.
            if (typeof footerLinksToSelectWithMatchingDepth[deeplinkValue[0]] != 'undefined') {
                compareUrl = deeplinkValue.slice(0, footerLinksToSelectWithMatchingDepth[deeplinkValue[0]]);
                compareUrl = '/' + compareUrl.join('/');
                links.each(function () {
                    if ($(this).find('a').attr('href').toLowerCase().replace(/.aspx/i, '') === compareUrl) {
                        $(this).addClass('selected');
                    } else {
                        $(this).removeClass('selected');
                    }

                });
            }
        },
        updateHistory = function () {
            //AKQA.log('updateHistory');
            pathNames = $.address.pathNames();
            AKQA.log('update hisotry:', pathNames);
            AKQA.log('update hisotry:', deeplinkHistory);
            deeplinkHistory.unshift((pathNames.length) ? pathNames : ['home']);
            AKQA.log('update hisotry:', deeplinkHistory);
        },
        setCoverColour = function (destinationUrl) {
            if (destinationUrl.match(/^\/(approach|career|contact)\b/i) &&
                !('/' + deeplinkHistory[1].join('/')).match(/^\/work(\/[^\/]+)?/)) {
                AKQA.PageManager.Cover.setColour('white');
            } else {
                AKQA.PageManager.Cover.setColour('black');
            }
        },
        doAction = function (isInternal) {
            var loadUrl = $.address.value(),
                previousUrl = '/' + deeplinkHistory[1].join('/'),
                redirectUrl = loadUrl,
                modalMatcher = /(\/|%2F)(images|video|map|privacy-policy)$/i,
                withTransition = false,
                modalType;

            //hide footer to prevent refresh issues if switching sections
            if (deeplinkHistory[0][0] !== deeplinkHistory[1][0] || deeplinkHistory[0][0] === 'career') { //career to be replaced with a different logic
                AKQA.PageManager.Footer.close();
            }

            //set cover colour based on destination url
            setCoverColour(loadUrl);

            if (modalMatcher.test(loadUrl)) {
                //handle modals

                withTransition = (deeplinkHistory[0].length - 1 > deeplinkHistory[1].length ||
                    deeplinkHistory[0][deeplinkHistory[0].length - 2] != deeplinkHistory[1][deeplinkHistory[0].length - 2]);

                modalType = loadUrl.match(modalMatcher)[2];
                if (modalType == 'privacy-policy') {
                    loadUrl = '/privacy-policy'
                }

                AKQA.Modals.show(modalType, loadUrl);
                redirectUrl = loadUrl.replace(modalMatcher, '');

                AKQA.PageManager.Content.update(redirectUrl, withTransition, modalType !== 'video');
                if (modalType == 'video') {
                    AKQA.PageManager.fadeInNav();
                }

            } else if (previousUrl.replace(modalMatcher, '') == $.address.path()) {

                //hide modal
                AKQA.Modals.close(false);

            } else {

                //hide modal
                AKQA.Modals.close(false);

                //handle ordinary pages
// We have two bugs that collide each other: [AKQA-749] & [AKQA-968]
// Originally the code was like below:
// withTransition = (deeplinkHistory[0][deeplinkHistory[0].length - 1] != deeplinkHistory[1][deeplinkHistory[0].length - 1]);
// However it caused [AKQA-749]
// in order to fix it, I changed it like this:
// withTransition = ((deeplinkHistory[0][deeplinkHistory[0].length - 1] != deeplinkHistory[1][deeplinkHistory[0].length - 1]) || (deeplinkHistory[0][0].match(/^(home|work)\b/i)));
// but then we got the bug [AKQA-968]
// I'm now changing it to:
// withTransition = (deeplinkHistory[0][deeplinkHistory[0].length - 1] != deeplinkHistory[1][deeplinkHistory[0].length - 1]);
// Hoping to fix both without breaking anything else...
// withTransition = (deeplinkHistory[0][deeplinkHistory[0].length - 1] != deeplinkHistory[1][deeplinkHistory[0].length - 1] || Boolean(deeplinkHistory[0][0].match(/^(home)\b/i)));
                
                withTransition = (deeplinkHistory[0][deeplinkHistory[0].length - 1] != deeplinkHistory[1][deeplinkHistory[0].length - 1] || Boolean(deeplinkHistory[0][0].match(/^(home)\b/i)));
                
                AKQA.log(withTransition);
                AKQA.log(deeplinkHistory[0] + ' - ' + deeplinkHistory[1]);

                //refresh page content
                switch (deeplinkHistory[0][0]) {
                    case 'work':
                        switch (pathNames.length) {
                            case 1:
                                AKQA.PageManager.Carousel.update(loadUrl);
                                break;
                            case 2:
                                AKQA.PageManager.Carousel.update(loadUrl);
                                break;
                            case 3:
                                //video fade
                                if (!AKQA.DeviceManager.isMobileWebkit() &&
                                    deeplinkHistory[1].length == 4 &&
                                    deeplinkHistory[1][3] == 'video') {
                                    AKQA.PageManager.fadeInContent();
                                    break;
                                }
                                AKQA.PageManager.Content.update(loadUrl, withTransition);
                                break;
                            case 4:
                                AKQA.PageManager.Content.update(loadUrl, false);
                                break;
                            default:
                                AKQA.PageManager.Content.update(loadUrl, withTransition);
                                break;
                        }
                        break;
                    case 'approach':
                        switch (pathNames.length) {
                            case 2:
                                AKQA.PageManager.Content.update(loadUrl, false);
                                break;
                            default:
                                AKQA.PageManager.Content.update(loadUrl, withTransition);
                                break;
                        }
                        break;
                    case 'career':
                        AKQA.PageManager.Content.update(loadUrl, true);
                        break;
                    default:
                        AKQA.PageManager.Content.update(loadUrl, withTransition);
                        break;
                }
            }
        },
        init = (function () {
            deeplinkHistory.push(['home']);
            //video redirect for mobile devices
            if (AKQA.DeviceManager.isMobileWebkit()) {
                var url = document.location.href;
                if (url.match(/\/video$/i)) {
                    document.location.href = url.replace(/\/video$/i, '');
                }
            }
        } ());

        //executed on every change
        $.address.change(function (event) {
            updateHistory();
            updateFooterLinks();
        });

        $.address.externalChange(function (event) {
            var url = document.location.href.replace(/^http:\/\/[^\/]+/, '').replace(/#.*/, '');
            if (url.match(/^\/?$/i)) {
                doAction();
            } else if (url.match(/^\/work\/[^\/]*$/i)) {
                setCoverColour(url);
                AKQA.PageManager.Carousel.update(url);
            } else {
                setCoverColour(url);
                AKQA.PageManager.Content.update();
            }
            AKQA.PageManager.Navigation.update();
        });

        //executed when page a deeplinked link is clicked
        $.address.internalChange(function (event) {
            doAction(true);
        });

        return {
            refreshPage: function () {
                //updateHistory();
                doAction(true);
            },
            updatePageType: updatePageType,
            getCurrentPageType: function () {
                return pageType[0];
            },
            currentDeeplinkPath: deeplinkHistory[0]
        };
    } ());

    AKQA.LoadManager = (function () {
        return {
            loadJSON: function (url, callback) {
                $.getJSON(url + '?json=1', callback);
            },
            loadImages: function (images, callback) {
                var counter = 0;
                images = $.isArray(images) ? images : [images];

                function checkImages() {
                    counter += 1;
                    if (counter === images.length && typeof callback === 'function') {
                        callback();
                    }
                }

                for (var i = 0; i < images.length; i += 1) {
                    var img;
                    if (images[i]) {
                        img = new Image();
                        img.onload = function () {
                            checkImages();
                        };
                        img.onerror = checkImages;
                        img.onabort = checkImages;
                        img.src = images[i];
                    } else {
                        checkImages();
                    }

                }
            },
            loadContent: function (url, selectors, updateBodyClass, callback) {
                $.each(selectors, function (index, selector) {
                    $(selector).data('data', null);
                });
                $.ajax({
                    url: url,
                    dataType: 'text',
                    success: function (data, status) {
                        var data = data.replace(/\n|\r/g, ' '),
                            body = data.replace(/<\/body>.*/i, '</div>').match(/<body.*/i)[0].replace(/<body/ig, '<div'),
                            title = data.match(/<title>([^<]+)<\/title>/i)[1],
                            bodyClasses, bodyId,
                            scripts = body.match(/<script class="ajax"[^>]*>(.|\n|\r)*?<\/script>/ig),
                            $body = $(body),
                            $form = $body.find('form');

                        //strip scripts
                        body.replace(/<script[^>]*>(.|\n|\r)*?<\/script>/ig, '');

                        //update title
                        $.address.title(title);

                        if (updateBodyClass) {

                            bodyId = $body.attr('id');
                            bodyClasses = $body.attr('class');

                            $('body').data({
                                classes: bodyClasses,
                                id: bodyId
                            });
                        }
                        
                        //update form action and viewstate

                        $('form').attr('action', $form.attr('action')).attr('enctype', $form.attr('enctype')).attr('encoding', $form.attr('enctype'));
                        $('#__VIEWSTATE').replaceWith($body.find('#__VIEWSTATE'));
                        $('#__EVENTVALIDATION').remove();
                        $('#__VIEWSTATE').after($body.find('#__EVENTVALIDATION'));

                        $.each(selectors, function (index, selector) {
                            $(selector).data('data', $body.find(selector).clone());
                            if (index === selectors.length - 1) {
                                if (typeof callback === 'function') {
                                    callback();
                                }
                            }
                        });

                        //execute scripts
                        if (scripts) {
                            $('body').append(scripts.join(''));
                        }
                    },
                    error: function () {
                        //we need to think how to handle this
                    }
                });
            }
        };
    } ());

    AKQA.Loader = (function () {
        return {
            show: function (callback) {
                $loader = $('#loader');
                if ($loader.length === 0) {
                    $loader = $('<div id="loader"><div class="spinner"></div></div>');
                    $('body').append($loader);
                    $loader.hide();
                }
                $loader.bind('mouseover mousemove', function () {
                    return false;
                });
                $loader.fadeIn(callback);
                return false;
            },
            hide: function (callback) {
                $('#loader').fadeOut(callback);
                return false;
            }
        };
    } ());

    AKQA.EventManager = (function () {
        return {
            subscribe: function (event, fn) {
                $(this).unbind(event, fn).bind(event, fn);
            },
            resign: function (event, fn) {
                $(this).unbind(event, fn);
            },
            publish: function (event) {
                $(this).trigger(event);
            }
        };
    } ());

    AKQA.Utility = (function () {
        return {
            getUrlFromCss: function (property) {
                return property.replace(/"/g, '').replace(/url\(|\)$/ig, '');
            },
            replaceIdFromData: function ($item) {
                var replacement = $item.data('id');
                $item.attr('id', replacement);
                return replacement;
            },
            replaceClassFromData: function ($item) {
                var replacement = $item.data('classes');
                $item.attr('class', replacement);
                return replacement;
            },
            replaceFromData: function (item) {
                // this 'if' has been added to avoid problem with pager arrow which are not available in the contact section.
                $item = $(item);
                if ($item.length) {
                    var replacement = $item.data('data').html();
                    replacement = (replacement) ? replacement.replace(/\/%7E\//g, '\/\~\/') : '';
                    if (AKQA.DeviceManager.isiPhone() || AKQA.DeviceManager.isiPod()) {
                        //strips linebreaks on iOS
                        replacement = $(replacement);
                        replacement.find('#copy p').each(function () {
                            var html = $(this).html();
                            html = html.replace(/<br\s?>/ig, '');
                            $(this).replaceWith('<p class="' + this.className + '">' + html + '</p>');
                        });
                    }
                    $item.html(replacement);
                }
            },
            swapCss: function (elem, options, callback) {
                var old = {};
                // Remember the old values, and insert the new ones
                for (var name in options) {
                    old[name] = elem.style[name];
                    elem.style[name] = options[name];
                }
                callback.call(elem);
                // Revert the old values
                for (var name in options) {
                    elem.style[name] = old[name];
                }
            },
            cufonHoverFix: function (selector) {
                if (!AKQA.DeviceManager.isIE()) { //this makes the text gigling in IE but the fix below was meant to be for firefox... so I'm filtering this for the moment
                    $(selector).hover(function () {
                        AKQA.FontManager.refreshPage();
                    }, function () {
                        setTimeout(function () {
                            AKQA.FontManager.refreshPage();
                        }, 0);
                    });
                }
            },
            adjustFooter: function () {
                $('#page-footer').css({ bottom: $(window).height() - $(document).height() });
            }
        };
    } ());

    AKQA.ScrollManager = (function () {
        var self = {};
        self.init = function () {
            if (AKQA.DeviceManager.isiOS()) {
                var lastFrameHeight = 0;
                setInterval(function () {
                    var frameHeight = parseInt($('#akqa-frame').height(), 10);
                    if (frameHeight !== lastFrameHeight) {
                        $("body").css({ 'height': frameHeight + 116 }); //116 is the offset height of the primary nav.
                        AKQA.Utility.adjustFooter();
                        lastFrameHeight = frameHeight;
                    }
                }, 250);
            }
        };
        self.refreshPage = self.init;
        return self;
    } ());


    AKQA.PageManager = (function () {
        var animationSpeed = 600,
        animationDelay = 1000,
        docElement = document.documentElement,
        Background, Fade, Navigation, Content, Footer, Carousel, Cover, Pager,
        contentReplaceHandler = null, contentAnimationHandler = null, carouselAnimationHandler = null;

        Background = (function (ref) {
            var self = {},
            $obj;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                }
            };
            self.update = function () {
                var imgUrl = AKQA.Utility.getUrlFromCss($obj.css('background-image'));
                if (imgUrl !== 'none') {
                    self.hasImage = true;
                    AKQA.LoadManager.loadImages(imgUrl, function () {
                        AKQA.EventManager.publish(AKQA.Events.BACKGROUND_IMAGE_READY);
                    });
                } else {
                    self.hasImage = false;
                    AKQA.EventManager.publish(AKQA.Events.BACKGROUND_IMAGE_READY);
                }
            };
            self.show = function () {
                $obj.show();
                return $obj;
            };
            return self;
        } ('#page-background'));

        Fade = (function (ref) {
            var self = {},
            $obj;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                }
            };
            self.update = function () {
                var imgUrl = AKQA.Utility.getUrlFromCss($obj.css('background-image'));
                if (imgUrl !== 'none') {
                    self.hasImage = true;
                    AKQA.LoadManager.loadImages(imgUrl, function () {
                        AKQA.EventManager.publish(AKQA.Events.FADE_IMAGE_READY);
                    });
                } else {
                    self.hasImage = false;
                    AKQA.EventManager.publish(AKQA.Events.FADE_IMAGE_READY);
                }
            };
            self.fadeIn = function (callback, delay) {
                $obj.stop(true);
                if (AKQA.DeviceManager.isiOS()) {
                    setTimeout(function () {
                        $obj.show();
                        if (typeof callback === 'function') {
                            callback();
                        }
                        AKQA.EventManager.publish(AKQA.Events.FADE_VISIBLE);
                    }, animationSpeed + delay);
                }
                else {
                    AKQA.AnimationManager.fadeTo($obj, 1, animationSpeed, delay, function () {
                        if (typeof callback === 'function') {
                            callback();
                        }
                        AKQA.EventManager.publish(AKQA.Events.FADE_VISIBLE);
                    });
                }
                return $obj;
            };
            self.get$Obj = function () {
                return $obj;
            };
            self.hide = function () {
                AKQA.EventManager.publish(AKQA.Events.FADE_HIDDEN);
                $obj.hide();
            };
            return self;
        } ('#page-fade'));

        Navigation = (function (ref) {
            var self = {},
            $obj;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                }
            };
            self.hide = function () {
                $obj.find('.menu').hide();
                return $obj;
            };
            self.fadeIn = function (callback, delay) {
                $obj.find('.menu').stop(true);
                if (AKQA.DeviceManager.isIE() && AKQA.DeviceManager.IEVersion() < 9) {
                    setTimeout(function () {
                        $obj.find('.menu').show();
                        if (typeof callback === 'function') {
                            callback();
                        }
                    }, animationSpeed + delay);
                } else {
                    AKQA.AnimationManager.fadeTo($obj.find('.menu'), 1, animationSpeed, delay, function () {
                        if (typeof callback === 'function') {
                            callback();
                        }
                    });
                }
                return $obj;
            };
            self.update = function () {
                var location = document.location.href.toLowerCase().replace(/^http:\/\/[^\/]+\/(#\/?)?/, '');
                $obj.find('li').each(function () {
                    var $this = $(this);
                    var href = $(this).find('a').attr('href').toLowerCase().replace(/^http:\/\/[^\/]+|^\//, '');
                    if (href.split('/').shift() == location.split('/').shift()) {
                        $this.addClass('selected');
                    } else {
                        $this.removeClass('selected');
                    }
                });
                // We've got a full page refresh already... this shouldn't be necessary.
                // AKQA.FontManager.refreshPage();
            };

            return self;
        } ('#nav'));

        Footer = (function (ref) {
            var self = {},
            $obj, $contentDiv, $triggerButton, $linkButton,
            open = false,
            moving = '';

            function slideUp(time, delay) {
                if (moving !== 'slidingUp') {
                    moving = 'slidingUp';
                    var speed = (typeof time !== 'undefined') ? time : animationSpeed;
                    $contentDiv.stop(true, true);
                    AKQA.AnimationManager.slideUp($contentDiv, speed, delay ? delay : 0, function () {
                        $triggerButton.removeClass('open');
                        moving = '';
                    });
                }
            }

            function slideDown(time, delay) {
                if (moving !== 'slidingDown') {
                    moving = 'slidingDown';
                    if (!$contentDiv.is(':visible')) {
                        AKQA.Utility.swapCss($contentDiv[0], { display: 'block' }, function () {
                            $('#footer-form').jqTransform();
                        });
                    }
                    AKQA.MManager.refreshPage();
                    AKQA.FontManager.refreshPage();
                    var speed = (typeof time !== 'undefined') ? time : animationSpeed;
                    $contentDiv.stop(true);
                    AKQA.AnimationManager.slideDown($contentDiv, speed, delay ? delay : 0, function () {
                        $triggerButton.addClass('open');
                        moving = '';
                    });
                }
            }

            function footerAnimationHandler() {
                var pageOptions;
                if (pageOptions = AKQA.SettingsForTypeOnLoad[AKQA.DeeplinkingManager.getCurrentPageType()]) {
                    if (pageOptions.footerAnimateOpened) {
                        slideDown(2 * animationSpeed, 2000);
                    } else if (!pageOptions.footerAnimateOpened) { // this avoid to match undefined
                        slideUp(2 * animationSpeed);
                    }
                }
            }

            self.init = function () {
                AKQA.EventManager.subscribe(AKQA.Events.BODY_CLASS_UPDATED, footerAnimationHandler);
                if (!$obj) {
                    $obj = $(ref);
                    $contentDiv = $obj.find('#footer-content');
                    $triggerButton = $obj.find('#footer-top a');
                }
            };
            self.fadeIn = function (callback, delay) {
                $obj.stop(true);
                AKQA.AnimationManager.fadeTo($obj, 1, animationSpeed, delay, function () {
                    if (typeof callback === 'function') {
                        callback();
                    }
                });
                return $obj;
            };
            self.close = slideUp;
            self.open = slideDown;
            self.get$Obj = function () {
                return $obj;
            };
            return self;
        } ('#page-footer'));

        Carousel = (function (ref) {
            var self = {},
            $obj,
            $caseStudies;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                    if (!$obj[0]) {
                        $obj = $('<div>').attr('id', ref.replace('#', ''));
                    }
                    $obj.insertBefore(Footer.get$Obj());
                }
            };
            self.update = function (url) {
                AKQA.EventManager.resign(AKQA.Events.CONTENT_REPLACE, contentReplaceHandler);
                AKQA.EventManager.resign(AKQA.Events.ANIMATE_CONTENT, contentAnimationHandler);
                AKQA.EventManager.resign(AKQA.Events.ANIMATE_CAROUSEL, carouselAnimationHandler);
                AKQA.EventManager.subscribe(AKQA.Events.ANIMATE_CAROUSEL, newCarouselAnimationHandler());
                Cover.fadeIn();
                self.fadeOut();
                Pager.bindSlide();
                if (url) {
                    if (!$('#pager-prev').length) {
                        $('#page-in-wrap').after('<div id="pager-prev" class="pager-arrow prev"></div><div id="pager-next" class="pager-arrow next"></div>');
                    }
                    AKQA.LoadManager.loadContent(url, [ref, '#pager-prev', '#pager-next', '#footer-content'], true, function () {
                        AKQA.EventManager.publish(AKQA.Events.CAROUSEL_DATA_READY);
                        AKQA.EventManager.publish(AKQA.Events.PAGER_DATA_READY);
                    });
                } else {
                    $obj.data('data', $obj.clone());
                    AKQA.EventManager.publish(AKQA.Events.CAROUSEL_DATA_READY);
                    AKQA.DeeplinkingManager.updatePageType();
                }
            };
            self.move = function (direction) {
                var $studyToHide, $studyToShow,
                posToShow;

                if (direction === 'next') {
                    $studyToHide = $caseStudies.filter(':visible').eq(0);
                    $studyToShow = $caseStudies.eq($caseStudies.index($studyToHide) + 3);
                } else if (direction === 'prev') {
                    $studyToHide = $caseStudies.filter(':visible').last();
                    posToShow = $caseStudies.index($studyToHide) - 3; // jquery 1.4: .eq(-n) goes backward from last 
                    if (posToShow >= 0) {
                        $studyToShow = $caseStudies.eq(posToShow);
                    }
                }
                if ($studyToHide && $studyToShow) {
                    if ($studyToHide.length && $studyToShow.length) {
                        /* first version */
                        // $studyToHide.hide().parent('li').hide(animationSpeed);
                        // $studyToShow.show().parent('li').show(animationSpeed);
                        /* end first version */
                        $studyToHide.parent('li').hide(animationSpeed, function () {
                            $studyToHide.hide()
                        });
                        $studyToShow.show().parent('li').show(animationSpeed);
                        return true;
                    }
                }
                return false;
            };
            self.fadeOut = function () {
                if ($obj.is(':visible')) {
                    /*if (AKQA.DeviceManager.useCSSTransitions()) {
                    AKQA.AnimationManager.fadeTo($obj, 0, animationSpeed, 0, function() {
                    //$(this).css({display: 'none', opacity: 1});
                    AKQA.EventManager.publish(AKQA.Events.CAROUSEL_HIDDEN);
                    });
                    } else {*/
                    $obj.animate({ opacity: 0 }, {
                        queue: false,
                        duration: animationSpeed,
                        //Odd... but this is the only way I found to fix a bug where the fade is not completed when you click on "our-approach" 
                        step: function () {
                            if ($(this).css('opacity') < 0.1) {
                                $(this).css({ opacity: '0', display: 'none' });
                            }
                        },
                        complete: function () {
                            $(this).css({ display: 'none', opacity: '' });
                            AKQA.EventManager.publish(AKQA.Events.CAROUSEL_HIDDEN);
                        }
                    });
                    //}
                } else {
                    AKQA.EventManager.publish(AKQA.Events.CAROUSEL_HIDDEN);
                }
            };
            self.fadeIn = function () {
                var display = '';

                $caseStudies = $obj.find('li a').hide();
                $obj.show();

                if ($caseStudies.length === 1) {
                    display = 'single';
                } else if ($caseStudies.length === 2) {
                    display = 'double';
                }
                $caseStudies.parent().addClass(display);
                $caseStudies.each(function (index) {
                    if (index < 3) {
                        AKQA.AnimationManager.fadeTo($(this), 1, 2 * animationSpeed, index * animationSpeed);
                        //$(this).delay(index * animationSpeed).fadeIn(2 * animationSpeed);
                    } else {
                        $(this).parent().hide();
                    }
                });

            };
            self.get$Obj = function () {
                return $obj;
            };
            return self;
        } ('#page-carousel'));

        Content = (function (ref) {
            var self = {},
            $obj;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                }
                // D. Odell: force links to /work/paris on the homepage to link to /work instead
		        $('#section-home a[href=/work/paris],#section-home a[href=/work/bonjour]').attr('href', '/work');
            };
            self.update = function (url, withTransition, fadeInContentOnComplete) {
                AKQA.EventManager.resign(AKQA.Events.ANIMATE_CAROUSEL, carouselAnimationHandler);
                AKQA.EventManager.resign(AKQA.Events.CONTENT_REPLACE, contentReplaceHandler);
                AKQA.EventManager.resign(AKQA.Events.ANIMATE_CONTENT, contentAnimationHandler);
                AKQA.EventManager.subscribe(AKQA.Events.CONTENT_REPLACE, newContentReplaceHandler());
                AKQA.EventManager.subscribe(AKQA.Events.ANIMATE_CONTENT, newContentAnimationHandler(fadeInContentOnComplete));
                if (withTransition) {
                    Cover.fadeIn(function () {
                        Fade.hide();
                        Content.hide();
                    });
                } else {
                    AKQA.EventManager.publish(AKQA.Events.COVER_VISIBLE);
                }
                Carousel.fadeOut();
                Pager.unbindSlide();
                if (url) {
                    if (!$('#pager-prev').length) {
                        $('#page-in-wrap').after('<div id="pager-prev" class="pager-arrow prev"></div><div id="pager-next" class="pager-arrow next"></div>');
                    }
                    AKQA.LoadManager.loadContent(url, [ref, '#pager-prev', '#pager-next', '#footer-content'], true, function () {
                        AKQA.EventManager.publish(AKQA.Events.CONTENT_DATA_READY);
                        AKQA.EventManager.publish(AKQA.Events.PAGER_DATA_READY);
                    });
                } else {
                    AKQA.DeeplinkingManager.updatePageType();
                    Background.update();
                    Fade.update();
                }
            };
            self.fadeIn = function (callback, delay) {
                if (!$obj.is(':visible')) {
                    AKQA.Utility.swapCss($obj[0], { display: "block" }, function () {
                        $('#form').jqTransform();
                    });
                }
                AKQA.MManager.refreshPage();
                AKQA.FontManager.refreshPage();
                $obj.stop(true);
                if (AKQA.DeviceManager.isIE() && AKQA.DeviceManager.IEVersion() < 9) {
                    setTimeout(function () {
                        $obj.show();
                        if (typeof callback === 'function') {
                            callback();
                        }
                        AKQA.EventManager.publish(AKQA.Events.CONTENT_VISIBLE);
                    }, animationSpeed + delay ? delay : 1);
                } else {
                    AKQA.AnimationManager.fadeTo($obj, 1, animationSpeed, delay ? delay : 1, function () {
                        if (typeof callback === 'function') {
                            callback();
                        }
                        AKQA.EventManager.publish(AKQA.Events.CONTENT_VISIBLE);
                    });
                }
                // D. Odell 27 Jan 2012
                $('#section-home a[href=/work/paris],#section-home a[href=/work/bonjour]').attr('href', '/work');
            };
            self.hide = function () {
                $obj.hide();
                AKQA.EventManager.publish(AKQA.Events.CONTENT_HIDDEN);
            };
            self.empty = function () {
                $obj.empty();
            };
            self.get$Obj = function () {
                return $obj;
            };
            return self;
        } ('#content'));

        Cover = (function (ref) {
            var self = {},
            $obj;

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                    if (!$obj[0]) {
                        $obj = $('<div>').attr('id', ref.replace('#', ''));
                    }
                    $obj.insertBefore(Footer.get$Obj());
                }
            };
            self.fadeIn = function (callback) {
                $obj.stop(true);
                AKQA.AnimationManager.fadeTo($obj, 1, animationSpeed, 0, function () {
                    if (typeof callback === 'function') {
                        callback();
                    }
                    AKQA.EventManager.publish(AKQA.Events.COVER_VISIBLE);
                });
            };
            self.fadeOut = function (callback) {
                $obj.stop(true);
                AKQA.AnimationManager.fadeTo($obj, 0, animationSpeed, 1, function () {
                    $(this).css('display', 'none');
                    if (typeof callback === 'function') {
                        callback();
                    }
                    AKQA.EventManager.publish(AKQA.Events.COVER_HIDDEN);
                });
            };
            self.setColour = function (colour, force) {
                $obj.css('background-color', colour);
            }
            return self;
        } ('#page-cover'));

        Pager = (function (ref) {
            var self = {},
            $obj,
            slideHandler = function (event) {
                var moved;
                if ($(this).hasClass('next')) {
                    moved = Carousel.move('next');
                } else if ($(this).hasClass('prev')) {
                    moved = Carousel.move('prev');
                }
                if (moved) {
                    event.preventDefault();
                    event.stopImmediatePropagation();
                }
            };

            self.init = function () {
                if (!$obj) {
                    $obj = $(ref);
                }
            };

            self.bindSlide = function () {
                $obj.unbind('click', slideHandler).bind('click', slideHandler);
            };

            self.unbindSlide = function () {
                $obj.unbind('click', slideHandler);
            };

            return self;
        } ('.pager-arrow'));

        var className = docElement.className;
        className = className.replace(/\bno-js\b/, 'js');
        className += (AKQA.DeviceManager.isIE()) ? ' is-ie' : '';
        className += (AKQA.DeviceManager.isWebkit()) ? ' is-webkit' : '';
        className += (AKQA.DeviceManager.isMozilla()) ? ' is-mozilla' : '';
        className += (AKQA.DeviceManager.isOpera()) ? ' is-opera' : '';
        className += (AKQA.DeviceManager.isSafari()) ? ' is-safari' : '';
        className += (AKQA.DeviceManager.isiOS()) ? ' is-ios' : '';
        className += (AKQA.DeviceManager.isiPad()) ? ' is-ipad' : '';
        className += (AKQA.DeviceManager.isiPhone()) ? ' is-iphone' : '';
        className += (AKQA.DeviceManager.isiPod()) ? ' is-ipod' : '';
        className += (AKQA.DeviceManager.isMac()) ? ' is-mac' : '';
        className += (AKQA.DeviceManager.useFontFace()) ? ' font-face' : '';
        className += (AKQA.DeviceManager.isAndroid()) ? ' is-android' : '';
        className += (AKQA.DeviceManager.isHandset()) ? ' is-handset' : '';
        docElement.className = className;

        //EVENT FOR FULL PAGE WITH BACKGROUND
        var newContentAnimationHandler = function (fadeInContentOnComplete) {
            var eventTally = AKQA.Events.ANIMATE_CONTENT.split(' ').join('');
            contentAnimationHandler = function (event) {
                eventTally = eventTally.split(event.type + '.' + event.namespace).join('');
                if (eventTally == '') {
                    $(this).unbind(event);
                    Background.show();
                    if (fadeInContentOnComplete || typeof fadeInContentOnComplete == 'undefined') {
                        Cover.fadeOut(fadeInContent);
                    } else {
                        Cover.fadeOut();
                    }
                }
            };
            return contentAnimationHandler;
        }

        function fadeInContent() {
            var delay = (Background.hasImage && Fade.hasImage) ? animationDelay : 0;
            var pageOptions;
            Fade.fadeIn(null, delay);
            Content.fadeIn(null, delay + 200 + animationSpeed);
            if (pageOptions = AKQA.SettingsForTypeOnLoad[AKQA.DeeplinkingManager.getCurrentPageType()]) {
                Footer.fadeIn(null, delay + 200 + animationSpeed);
                Navigation.fadeIn(null, delay + 200 + animationSpeed);
            }
        }

        //EVENT FOR CAROUSEL READY WITH IMAGES
        var newCarouselAnimationHandler = function () {
            var eventTally = AKQA.Events.ANIMATE_CAROUSEL.split(' ').join('');
            carouselAnimationHandler = function (event) {
                eventTally = eventTally.split(event.type + '.' + event.namespace).join('');
                if (eventTally == '') {
                    $(this).unbind(event);
                    $('body style').remove();
                    AKQA.Utility.replaceFromData(Carousel.get$Obj());
                    AKQA.Utility.replaceFromData('#footer-content');
                    AKQA.DeeplinkingManager.updatePageType();
                    AKQA.MManager.refreshPage();
                    AKQA.FontManager.refreshPage();
                    Carousel.fadeIn();
                    // This is a temporary fix: the carousel should be managed like a content update
                    Content.empty();
                }
            };
            return carouselAnimationHandler;
        }

        //Fixes IE resize issue (overlapping content)
        var resizeHandler = function () {
            var el = $('body'),
                threshold = 550,
                fixClass = 'em-fix';
            return (document.body.clientHeight < threshold) ? $(el).addClass(fixClass) : $(el).removeClass(fixClass);
        }

        //EVENT FOR CONTENT DATA LOADED AND COVER FADE IN
        var newContentReplaceHandler = function () {
            var eventTally = AKQA.Events.CONTENT_REPLACE.split(' ').join('');
            contentReplaceHandler = function (event) {
                eventTally = eventTally.split(event.type + '.' + event.namespace).join('');
                if (eventTally == '') {
                    $(this).unbind(event);
                    AKQA.Utility.replaceFromData(Content.get$Obj());
                    AKQA.Utility.replaceFromData('#footer-content');
                    AKQA.DeeplinkingManager.updatePageType();
                    AKQA.MManager.refreshPage();
                    AKQA.FontManager.refreshPage();
                    AKQA.ScrollManager.refreshPage();
                    Background.update();
                    Fade.update();

                    //two fonts hover fix
                    AKQA.Utility.cufonHoverFix('.type-home-page #main a');

                    //handle swipes
                    if (AKQA.DeviceManager.isiOS()) {
                        $('#page-in-wrap:not(.swipe-enabled)').addClass('swipe-enabled').swipe({
                            swipeLeft: function () {
                                $('#pager-next a').click();
                            },
                            swipeRight: function () {
                                $('#pager-prev a').click();
                            }
                        });
                    }

                    //Forces IE 8 not to overlap content after resizing the window 
                    if (AKQA.DeviceManager.IEVersion() === '8.0') {
                        resizeHandler();
                    }
                }
            };
            return contentReplaceHandler;
        }

        AKQA.EventManager.subscribe(AKQA.Events.PAGER_DATA_READY, function () {
            AKQA.Utility.replaceFromData('#pager-prev');
            AKQA.Utility.replaceFromData('#pager-next');
        });

        AKQA.EventManager.subscribe(AKQA.Events.CAROUSEL_DATA_READY, function () {
            var $images = Carousel.get$Obj().data('data').find('img'),
            imgSrcs = $images.map(function () {
                return $(this).attr("src");
            }).get();
            AKQA.LoadManager.loadImages(imgSrcs, function () {
                AKQA.EventManager.publish(AKQA.Events.CAROUSEL_IMAGE_READY);
            });
        });

        var initialised = false;
        return {
            init: function () {

                if (initialised) {
                    return;
                } else {
                    initialised = true;
                }

                Navigation.init();
                AKQA.MManager.init();
                AKQA.FontManager.init();
                AKQA.ScrollManager.init();
                Content.init();
                Footer.init();
                Cover.init();
                Background.init();
                Fade.init();
                Carousel.init();
                Pager.init();

                //Manage links
                AKQA.ClickManager.init();

                AKQA.Utility.cufonHoverFix('.type-search-results #copy a');

                //footer bar adjustment
                if (AKQA.DeviceManager.isMobileWebkit()) {
                    AKQA.Utility.adjustFooter();

                    $(window).scroll(AKQA.Utility.adjustFooter);
                }

                //Forces IE 8 not to overlap content after resizing the window 
                if (AKQA.DeviceManager.IEVersion() === '8.0') {
                    window.onresize = resizeHandler;
                }

                // make map address clickable
                $('p.address').live('click', function () {
                    $('a.nav-map').click();
                });
            },
            Carousel: Carousel,
            Content: Content,
            Navigation: Navigation,
            Footer: Footer,
            Cover: Cover,
            fadeInNav: function () {
                Navigation.fadeIn(null, 400);
                Footer.fadeIn(null, 400);
            },
            fadeInContent: function () {
                fadeInContent();
            }
        };
    } ());

} (jQuery.noConflict()));
