function blqAddLoadEvent(func){
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {window.onload = func;}
    else {window.onload = function() {
        if (oldonload) {oldonload();}
        func();}}
}

var blqOnDomReady;
(function() {
    var toRun = function() {},
    isReady = false,
    d = document,
    ua = navigator.userAgent.toLowerCase();
    
    blqOnDomReady = function(f) {
        //just run function if already ready
        if (isReady) {
            f();
        } else {
            var oldLoadFunc = toRun;
            toRun = function () {
                oldLoadFunc();
                f();
            };
        }
    };
    
    if (/*@cc_on !@*/false) {
        // polling for no errors
        (function () {
            try {
                // throws errors until after ondocumentready
                d.documentElement.doScroll('left');
            } catch (e) {
                setTimeout(arguments.callee, 50);
                return;
            }
            // no errors, fire
            toRun();
        })();
    } else if (typeof d.readyState != 'undefined' && ! (Number((/applewebkit\/(\d+(?:\.\d+)?)/.exec(ua) || [0,NaN])[1]) < 312)) {
        var f = function(){ /loaded|complete/.test(d.readyState) ? toRun() : setTimeout(f, 10); };
        f();
    } else {
        var callback = function () {
            if (arguments.callee.fired) { return; }
            arguments.callee.fired = true;
            toRun();
        };
        d.addEventListener("DOMContentLoaded", callback, false);
        var oldOnload = window.onload;
        window.onload = function () {
        if (oldOnload) { oldOnload(); }
            callback();
        };
    }
    blqOnDomReady(function() { isReady = true; });
})();

// Global nav
var blq = new function (){
    var computedStyles
        , navClicked = false
        , browserCSS = false
        , browserImages = false
        , browserJS = (document.getElementById && document.getElementsByTagName) ? true : false
        , externalGoMetadata = false
        , labels = {
            searchSuggestion: "Search the BBC"
        },
        _flagpoles = {};
    
    //Public var because location path includes release number and platform, so is set by page
    this.assetPath = false;
    
    this.init = function(){
        //console.log("init()");
        if(browserJS){
            if (typeof document.documentElement.className == "string") {
                document.documentElement.className += " blq-js";
            } else {
                document.documentElement.className = "blq-js";
            }
            //some cps's use quirks doctype and need to tweak css (see: CPSSTATIC-13)
            if (document.compatMode == "BackCompat") { 
                document.documentElement.className += " blq-quirks";
            }
        }
    }
    
    this.domReady = function(){
        //console.log("domReady()");
        var searchButton = el('blq-search-btn');
        var moreButton = el('blq-nav-m').getElementsByTagName('a')[0];
        
        computedStyles = (document.defaultView && document.defaultView.getComputedStyle(searchButton, null)) || searchButton.currentStyle;
        
        //Check CSS is on
        //Using color as Opera doesn't report width this early
        //Allowing blank as PC and mac Safari 2 reports blank before window.onload
        if(computedStyles.color == "rgb(0, 0, 0)" || computedStyles.color == "#000000" || computedStyles.color == "#000" || computedStyles.color == ""){
            browserCSS = true;
        }
        //console.log(computedStyles.color);
        //console.log(browserCSS);
        
        //browser ability tests
        if(browserJS && browserCSS && moreButton){
            
            //Add open function
            moreButton.onclick = function(e){
                blq.toggleNav(e);
                return false;
            };

            //Add close function to body
            if (typeof document.body.onclick == "function") {
                var oldOnClick = document.body.onclick;
                document.body.onclick = function(){
                    animateNav('hide');
                    oldOnClick();
                };
            } else {
                document.body.onclick = function(){
                    animateNav('hide');
                };
            }
            
            el('blq-nav').onclick = function(e){
                stopBubble(e);
            };
        }
        
        blq.setARIAValues();
        
        //Go tracking (note some calls with SSI dependency made from head)
        if(!this.addGoTrack.isStub) { //add go tracking only if not using a stub. FWGEL-192
	        blq.addGoTrack('blq-acc',{go:'{id}2/{dir}'});
	        blq.addGoTrack('blq-mast',{go:'{id}2/{dir}'});
	        blq.addGoTrack('blq-nav',{go:'{id}2/{dir}'});
	        blq.addGoTrack('blq-disclaim',{go:'{id}2/{dir}'});
	        blq.addGoTrack('blq-sitelinks',{go:'{id}2/{count}/{dir}'});
	        blq.addGoTrack('blq-bbclinks',{go:'{id}2/{dir}'});
        }
        
        // set up the Search The BBC text hint before Glow is loaded on focus
        var searchBox = el('blq-search');
        if (searchBox.value == ""
                && searchBox != document.activeElement) {
            searchBox.value = labels.searchSuggestion;
        }
    }
    
    this.onLoad = function() {
        //Preload nav background, or set it to white when images are off
        if (imagesOn()){
            //Preload nav panel image
            var navPanelBG = new Image(1,1);
            navPanelBG.src = blq.assetPath + 'img/panel.png';
            
            //Preload autosuggest image
            var autosuggestPanelBG = new Image(1,1);
            autosuggestPanelBG.src = blq.assetPath + 'img/suggest_sprite.png';

            //Note IE7 triggers onload before ondomready
            el('blq-mast-home').className = "";
        } else {
            var navLinks = el('blq-nav-links');
            navLinks.className += ' blq-no-images';
        }
    }
    
    this.toggleNav = function(e) {
        if(document.getElementById('blq-nav-links').style.display == "block"){
            animateNav('hide');
        } else {
            animateNav('show');
        }
        stopBubble(e);
    }
   
    this.addGoTrack = function (el, opts) {
        var el = document.getElementById( el ) || el,
            opts = opts || {},
            links = el.nodeName == 'A' ? [el] : el.length ? el : el.getElementsByTagName('a'),
            extOnly = opts.external || false,
            filePath = opts.path || window.location.toString().split('bbc.co.uk/')[1],
            elId = el.id ? el.id.replace(/-/g,'/') : '_auto',
            goCode = opts.go || '{path}/int/{id}/{dir}',
            currentServer = opts.currentServer || window.location.href.split("//")[1].split("/")[0];
    
        for( var i=0; i<links.length; i++ ) {
            var externalURL = false
              , oldHref     = false;
        
            if ( ( typeof links[i] != "object" )
                || (! links[i].href) 
                || links[i].className.indexOf('blq-nogo') != -1
                || links[i].href.indexOf('/go/') != -1
                || links[i].href.charAt(0) == '#'
                //split() here to ensure it works if the present URL already has an anchor
                || links[i].href.charAt(window.location.toString().split('#')[0].length) == '#'
                || links[i].href.indexOf('mailto:') == 0
                || links[i].href.indexOf('javascript:') == 0
                || links[i].href.indexOf('itpc:') == 0
                || links[i].href.indexOf('zune:') == 0
                || links[i].href.indexOf('zcast:') == 0) {
                    continue; 
                }
        
            //Anchors on webservice & when <base> is used
            if(links[i].href.indexOf('bbc.co.uk') != -1 && links[i].href.indexOf('#') != -1){
                if (links[i].href.indexOf(filePath + '#') != -1){
                    //console.log("Match! Don't track");
                    continue;
                }
            }
    
            var reCurrentServer = currentServer.replace(/\./g, '\\.'),
                path = links[i].href.split('?')[0],
                re = new RegExp("^[A-Za-z]+:\\/\\/(?:[^.]+\\.)*(?:bbc\\.co\\.uk|doubleclick\\.net|"+reCurrentServer+")");
    
            // Put the go track codes together 
            if( ! re.test(path)) {
                //External URL
                // Completely override the specified go code
                var page = location.pathname
                    , externalURL = true
                    , goCopy = page + (page.charAt(page.length-1) == '/' ? '' : '/') + 'ext/_auto';
            } else if( extOnly ) { 
                continue; 
            } else {
                //Internal URL
                var splitPath = path.split('/')
                    , goCopy = goCode
                    , goDir = splitPath.length < 5 ? 
                        splitPath[splitPath.length-1] || splitPath[splitPath.length-2] : 
                        splitPath[splitPath.length-2] || splitPath[splitPath.length-1];
            
                goCopy = goCopy.replace('{dir}', goDir);
                goCopy = goCopy.replace('{count}', i+1);
                goCopy = goCopy.replace('{path}', filePath);
                goCopy = goCopy.replace('{id}', elId);
                goCopy = goCopy.replace('#', '_');
                goCopy = '/' + goCopy;
            }
            
            // Put together the full go track url, with exceptions for use off-bbc.co.uk
            var clickCopy = links[i].onclick
                , hrefCopy
                , baseCopy = false;
            if (path.indexOf('www.bbc.co.uk') != -1){
                // Link specifically points at live (e.g. webservice)
                hrefCopy = 'http://www.bbc.co.uk/go' + goCopy +'/-/' + links[i].href.substring(links[i].href.indexOf("bbc.co.uk/") + 10, links[i].href.length);
            } else if (links[i].href.indexOf('www.bbc.com') != -1) {
                // Link specifically points at bbc.com
                hrefCopy = 'http://www.bbc.com/go' + goCopy +'/-/' + links[i].href.substring(links[i].href.indexOf("http://www.bbc.com/"), links[i].href.length);
            } else if (externalURL || links[i].href.indexOf(currentServer) == -1){
                // Not current domain or external link
                hrefCopy = '/go' + goCopy +'/-/' + links[i].href;
            } else {
                // Live internal link
                hrefCopy = '/go' + goCopy +'/-/' + links[i].href.substring(links[i].href.indexOf(currentServer) + (currentServer.length + 1), links[i].href.length);
            }
            // All copies ready, now apply tracking 
            links[i].onclick = (function() {
                var thisClick = clickCopy
                    , thisHref = hrefCopy;
                return function() {
                    this.href = thisHref;
                    if( typeof thisClick == 'function') { 
                        thisClick() 
                    };
                    //Uncomment while testing
                    //console.log( this.href );
                    //return false;
                }
            })();
        }
    }
    
    this.setExternalGoMetadata = function(metadata){
        externalGoMetadata = metadata;
    }
    
    /**
     * @public
     * @description Returns the value of the flagpole.
     */
    this.flagpole = function(name) {
        return _flagpoles[name];
    }
    
    /**
     * @public
     * @description Sets the value of a flagpole.
     * @param {string} name The name of the flagpole.
     * @param {string} value The value of the flagpole.
     */
    this.setFlagpole = function(name, value) {
        _flagpoles[name] = value;
    }
       
    this.tagEnglishLinks = function(label, tooltipTargets){
        if(browserJS && browserCSS && imagesOn()){//Have to retest as have to call from main doc to allow ssi var to be passed in, rather than calling this from domReady()
            this.addTooltips(el('blq-acc').getElementsByTagName('a'), label, "hreflang", "en-GB");
            this.addTooltips(el('blq-foot').getElementsByTagName('a'), label, "hreflang", "en-GB");
            this.addTooltips(el('blq-nav-main').getElementsByTagName('a'), label, "hreflang", "en-GB");
            //Get all from the divs passed in above too
            if(tooltipTargets != "false"){
                tooltipTargets = tooltipTargets.split(',');
                for(var i = tooltipTargets.length-1; i >= 0; i--){
                    if(el(tooltipTargets[i])){
                        this.addTooltips(el(tooltipTargets[i]).getElementsByTagName('a'), label, "hreflang", "en-GB");
                    }
                }
            }
            //console.log("tooltips added");
        }
    }
    
    this.addTooltips = function(collection, label, attribute, value){
        for(var i = collection.length-1; i>=0; i--){
            if(collection[i].getAttribute(attribute) == value){                
                if(collection[i].className){
                    collection[i].className += ' blq-tooltipped';
                } else {
                    collection[i].className = 'blq-tooltipped';
                }
                
                //Make the tooltip and add it to the link
                var tooltip = document.createElement('span');
                
                //if element is near top or right of page apply an additional class
                var tooltipClassString = "blq-tooltip blq-tipunder";
                
                tooltip.setAttribute('class', tooltipClassString);
                tooltip.setAttribute('className', tooltipClassString);//Needed for IE
                                
                tooltip.innerHTML = '<span class="blq-tooltip-l">' + label + '</span><span class="blq-tooltip-r">&nbsp;</span>';//That &nbsp; is for IE
                collection[i].appendChild(tooltip);
            }
        }
    }
    
    this.suggest = function( data ) {
        if( this.suggestion._pendingRequest ) {
            clearTimeout(this.suggestion._pendingRequest._timeout);
            this.suggestion._pendingRequest = null;
        }
        this.suggestion.setData( data[1] || [] );
        this.suggestion.find();
    }
    
    this.addAutoSuggest = function(isRTL){
        var searchBox = document.getElementById('blq-search'),
            autosuggestClasses,
            self = this,
            removeSearchTheBBCHint = function () {
            };
            
            searchBox.parentNode.parentNode.onsubmit = function () {
                if (searchBox.value == labels.searchSuggestion) {
                    searchBox.value = '';
                }
            };
            
            if( !searchBox ) { return false; }
            searchBox.setAttribute('autocomplete','off');
            searchBox.onfocus = function() {
                
                if (searchBox.value == labels.searchSuggestion) {
                    searchBox.value = "";
                }
                
                if( document.getElementById('blq-autosuggest') ) { return false; } // ensure only one Autosuggest per page
                gloader.load( ["glow", "1", "glow.dom", "glow.net", "glow.widgets.AutoSuggest"], {
                    async  : true,
                    onLoad : function (glow) {
                        glow.ready(function () {
                            var $ = glow.dom.get;
                            $('#blq-mast form').addClass('active');
                            var scope = $("#blq-mast input").filter(function (i) {
                                return $(this).attr('name') == "scope";
                              });
                            scope = (scope.length) ? scope.attr('value') : 'all';
                            self.noData = false;
                            self.suggestion = new glow.widgets.AutoSuggest( '#blq-search', [], {
                                    formatItem: function(item) { 
                                      var name = item.title;
                                      if( name.length > 28 ) { 
                                            name = item.title.substring(0,25) + '...';
                                            name += '<span class="blq-hide">' + item.title.substring(25,item.title.length) + '</span>';
                                      }
                                      return name;
                                    }
                                  , isMatch: function() {
                                        return this.data.length ? true : false;
                                    }
                                  , index : 'title'
                                  , maxListLength : blq.suggest_short ? 3 : 6
                                  , width : 226
                                  , activeOnShow : false
                                  , useCache : true
                                  , onInputChange : function(event) {
                                        event.preventDefault();
                                        if( this.noData ) {
                                            return false;
                                        }
                                        glow.dom.get('#suggid').remove();
                                        if( this._pendingRequest ) {
                                            this._pendingRequest.abort();
                                        }
                                        var self = this;
    
                                        var qs = glow.data.encodeUrl( { 
                                            'q' : event.value, 
                                            'scope' : scope, 
                                            'format' : 'blq-1', 
                                            'callback' : 'blq.suggest' 
                                        } );
                                        this._pendingRequest = glow.net.loadScript(
                                            this.searchHost+'/suggest?'+qs,
                                          { useCache: true, charset:'utf-8', 
                                                onError: function() {
                                                    self.inputElement.attr('autocomplete','on');
                                                    self.noData = true;
                                                }, timeout: 5
                                            });
                                    }
                                  , onDataError : function(event) {
                                      this.inputElement.attr('autocomplete','on');
                                    }
                                  , onItemSelect: function(event) {
                                        this.setValue(event.selectedItem.title);

                                        var input = glow.dom.get('#suggid');
                                        if( ! input.length ) {
                                            input = glow.dom.create('<input type="hidden" name="suggid" id="suggid" />');
                                            glow.dom.get('#blq-mast form').get('p').prepend(input);
                                        }
                                        input.val(event.selectedItem.id);

                                        var form = glow.dom.get('#blq-mast form');
                                        form[0].submit();
                                    }
                              }
                        );
                            // searchHost used to allow overriding default behaviour with a bookmarklet
                            self.suggestion.searchHost = self.searchHost || 'http://search.bbc.co.uk';
                            self.suggestion.overlay.container.attr('id', 'blq-autosuggest');
                            
                            // RTL
                            if (isRTL) {
                                autosuggestClasses = self.suggestion.overlay.container.attr('class');
                                self.suggestion.overlay.container.attr('class', autosuggestClasses + ' blq-rtl');
                            }
                            
                            self.suggestion.overlay.opts.hideWindowedFlash = false;
                            
                            glow.events.addListener(
                                  '#blq-search'
                                , 'click'
                                , function(e) {
                                    e.stopPropagation();
                                    glow.dom.get('#blq-mast form').addClass('active');
                                    return false;
                                }
                            );
                            
                            glow.events.addListener(
                                  document
                                , 'click'
                                , function(e) {
                                    glow.dom.get('#blq-mast form').removeClass('active');
                                }
                            );
                            
                            searchTheBBCSearchHint(glow);
                        });
                    }
                });
                searchBox.onfocus = function() {};
            };
    }
    
    this.setARIAValues = function(){
        if(document.body.setAttribute){
            addAttribute('blq-acc', 'role', 'navigation');
            addAttribute('blq-search', 'role', 'search');
            addAttribute('blq-local-nav', 'role', 'navigation');
            addAttribute('blq-content', 'role', 'main');
            addAttribute('blq-nav-main', 'role', 'navigation');
            addAttribute('blq-nav', 'role', 'navigation');
            addAttribute('blq-foot', 'role', 'contentinfo');
        }
    }
    
    /**
        @public
        @name setLabel
        @function
        @description Allows setting of default labels (such as 'Search The BBC' search box hint).
        @param {key} Label key
        @param {value} The new value
    */
    this.setLabel = function (key, value) {
        labels[key] = value;
    }
    
    this.disableFeature = function (feature) {
    	if(this[feature]) {
    		delete this[feature];
    	}
    	
        /*Barlesque exposes a public API method for go tracking. We must leave a stub
        to minimise risk of JS errors when method called directly */
        if(feature == 'addGoTrack') {
        	this['addGoTrack'] = function() {};
        	this.addGoTrack.isStub = true; //check this property's value
        } 	
    }
    
    //Privates
    function addAttribute (id, attribute, value){
        if (el(id)){
            el(id).setAttribute(attribute, value);
        }
    }
    
    function imagesOn(){
        var x = el('blq-search-btn');
        if (x.currentStyle){
            var y = x.currentStyle['backgroundImage'];
        } else if (window.getComputedStyle) {
            var y = document.defaultView.getComputedStyle(x,null).getPropertyValue('background-image');
        }
        
        if (y.indexOf("search_icon.png") == -1){
            //console.log("Images off: " + y);
            return false;
        } else {
            //console.log("Images on: " + y);
            return true;
        }
    }
    
    //Tooltip function factories
    function letShowTooltip(n,i){
        return function() {
            el('blq-tooltip-' + n + i).style.display = 'block';
        };
    }
    function letHideTooltip(n,i){
        return function() {
            el('blq-tooltip-' + n + i).style.display = 'none';
        };
    }
    
    function getPosition(theElement){
        //console.log(theElement.href);
        var positionY = 0;
        var positionX = 0;
        
        while (theElement != null){
            positionX += theElement.offsetLeft;
            positionY += theElement.offsetTop;
            theElement = theElement.offsetParent;
        }
        return [positionX, positionY];
    }
    
    //browser ability api. No point exposing as use of Glow will negate their need
    /*
    this.cssOn = function (){
        return browserCSS;
    }
    
    this.imagesOn = function (){
        return browserImages;
    }
    */
    
    function animateNav(action){
        var agent=navigator.userAgent.toLowerCase(),
            navMainEl = el('blq-nav-main');
        
        if (el('blq-nav-links').style.opacity != undefined && agent.indexOf("chrome") == -1) {
            //Set initial opacity of nav panel
            var currentOpacity = el('blq-nav-links').style.opacity || 0;
            
            
            
            function showMorePanel() {
                el('blq-nav-links').style.display = "block";
            }
            
            function hideMorePanel() {
                el('blq-nav-links').style.display = "none";
            }
            
            if (action == 'show'){
                
                showMorePanel();
                
                if (currentOpacity < 1) {
                    el('blq-nav-links').style.opacity = (parseFloat(currentOpacity) + 0.15); 
                    setTimeout(function(){
                        animateNav('show');
                    },10);
                }
                else {
                    navMainEl.className += " blq-morepanel-shown"
                    el('blq-nav-links').style.opacity = 1;
                    if(el('blq-az') && el('blq-az').focus){
                        el('blq-az').focus();
                    }
                }
            } else {
                if (currentOpacity > 0){
                    el('blq-nav-links').style.opacity = (parseFloat(currentOpacity) - 0.15); 
                    setTimeout(function(){
                        animateNav('hide');
                    },10);
                } else {
                    el('blq-nav-links').style.opacity = 0;
                    
                    navMainEl.className = navMainEl.className.replace("blq-morepanel-shown", "");
                    hideMorePanel()
                }
            }
        } else {
            if (action == 'show'){
                showMorePanel();
                navMainEl.className += " blq-morepanel-shown";
            } else {
                hideMorePanel();
                navMainEl.className = navMainEl.className.replace("blq-morepanel-shown", "");
            }
        }
    }
    
    function stopBubble(e){
        if (!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();
    }
    
    function el(id){
        return document.getElementById(id);
    }
    
    /**
        @private
        @name searchTheBBCSearchHint
        @function
        @description Adds the 'Search The BBC' text to the search box
        @param {glow} A reference to Glow
    */
    function searchTheBBCSearchHint (glow) {
        var $         = glow.dom.get,
            bind      = glow.events.addListener,
            searchbox = $("#blq-search");
        
        bind(searchbox, 'focus', function () {
            if (searchbox.val() == labels.searchSuggestion) {
                searchbox.val("");
            }
        });
        
        bind(searchbox, 'blur', function () {
            if (! searchbox.val()) {
                searchbox.val(labels.searchSuggestion);
            }
        });
        
        bind(searchbox.parent().parent(), 'submit', function(e) {
            if ( searchbox.val() == labels.searchSuggestion) {
                searchbox.val('');
            }
        })
    }
    
    var _environment = '';
    
    /**
     * @public
     * @description Returns the environment Barlesque was rendered from.
     */
    this.environment = function () {
        return _environment;
    }
    
    /**
     * @public
     * @description Sets the environment Barlesque should consider itself rendered from.
     * @param {string} env The environment, normally one of 'live', 'stage', 'test', 'int', 'ci' or 'sandbox'.
     */
    this.setEnvironment = function (env) {
        _environment = env;
    }
}

blq.init();
blqOnDomReady(function(){
    blq.domReady();
});
blqAddLoadEvent(blq.onLoad);


/**
 * Demi
 * 
 * Stubbed API that loads the full Demi javascript object.
 * 
 * @author Paul Clifford <paul.clifford@bbc.co.uk>
 * @author Richard Hodgson <richard.hodgson@bbc.co.uk>
 */
var demi = (function () {
    var loading = false,
        callbacks = [],
        demiUrl = null;

    return {
        /**
            @private
            @description Used in the unit tests to restore the initial state.
         */
        _reset: function () {
            loading = false;
            callbacks = [];
            demiUrl = null;
        },

        /**
            @private
            @description Called by the demi.js library when it has finished loading, and re-registers all the callbacks provided to getDevice with the real implementation.
         */
        _loaded: function () {
            while (callbacks.length > 0) {
                demi.getDevice(callbacks.shift(), blq.environment());
            }
        },

        /**
            @private
            @description Insert a script tag at the top of the head element. Replaced in the unit tests to avoid side effects.
            @param {string} src The value for the script src attribute.
         */
        _addScriptTag: function (src) {
            var headTag = document.getElementsByTagName('head')[0];
            var scriptTag = document.createElement('script');
            scriptTag.type = 'text/javascript';
            scriptTag.src = src;
            headTag.insertBefore(scriptTag, headTag.firstChild);
        },

        /**
            @private
            @description Set the location of the demi.js library. Called by inline JavaScript emitted by the DeMI shared module via an inlineHead method.
            @param {string} url The URL for the demi.js library
         */
        _setSource: function (url) {
            demiUrl = url;
        },

        /**
            @public
            @description Request a DeMI device object. Behind the scenes this pulls in the demi.js library, and the callback is re-registered with the real getDevice function (see the _loaded function).
            @param {function} callback
         */
        getDevice: function (callback) {
            callbacks.push(callback);
            if (! loading) {
                loading = true;
                demi._addScriptTag(demiUrl);
            }
        }
    };
})();

