

this.Shapeshifter = this.Shapeshifter || {};

//time in milliseconds for the pagein/pageout transition
Shapeshifter.FADE_TIME = 1000; 

//how many milliseconds must elapse before the next quote is added to the list
Shapeshifter.QUOTE_INTERVAL = 3000;

//number of quotes to show at any one time 
Shapeshifter.QUOTES_VISIBLE = 2;

//what effect do you want to use to change pages
//NOTE: IE will always use slide, as IE is unable to fade text (ugly edges around anti-aliased fonts)
var m = document.URL.match(/[&\?]t=([^&#]+)/);
Shapeshifter.pageTransitionEffect = m ? m[1] : 'slidefade'; // "slide" | "fade" | "slidefade"

//fix for incorrect version number in some IE instances

if (jQuery.browser.msie){
    var largestVersion = 0;
    var ua = navigator.userAgent.toLowerCase();
    var m = ua.match(/msie (\d(\.\d+)?)/g);
    for (var i=0; i<m.length; i++){
        var version = parseFloat(m[i].substr("msie ".length));
        if (version > largestVersion){
            largestVersion = version;
        }
    }
    if (largestVersion){
        jQuery.browser.version = largestVersion;
    }
}


//disable javascripty stuff for IE < 7

if (!jQuery.browser.msie || jQuery.browser.version >= 7){

    Shapeshifter.setPageId = function(pageId){
        //IE fails to cause a navigation event to occur when the anchor off the document is altered
        //we need the navigation event to occur so the back and forwards buttons work
        //but we still need to set the ancho on the window so bookmarking works in IE
        window.location.hash = "#"+ pageId;
        if (jQuery.browser.msie){
            document.getElementById("ie-navigationfix-iframe").setAttribute("src", "index.php?iehack=1&page="+ pageId);
        }
    }
    
    Shapeshifter.getPageId = function(){
        //IE fails to cause a navigation event to occur when the anchor off the document is altered
        //we need the navigation event to occur so the back and forwards buttons work
        //but we still need to set the ancho on the window so bookmarking works in IE
        
        if (jQuery.browser.msie){
        
            try {
                var url = ""+ document.getElementById("ie-navigationfix-iframe").contentWindow.location;
                return (m = url.match(/[\?&]page=([^&]+)/)) ? m[1] : window.location.hash.substr(1);
            }
            catch(e){
                return '';    
            }            
        }
        else {
            return window.location.hash.substr(1);
        }
    }
    
    /**
    * capture internal link clicks and request content from json pages 
    * instead of following the links.
    */
    $(document).click(function(evt){

        //FIXME: when server side generation is complete, let the user middle click links
        if (evt.which != 3){

            var ele = evt.target;
            
            //get parent link
            var link = null;
            
            while (ele.parentNode){
                if (ele.tagName && ele.tagName.toLowerCase() == "a"){
                    link = ele;
                    break;
                }
                else {
                    ele = ele.parentNode;
                }
            }
            
            //Language links require that the entire page is reloaded
            if (link && link.id && link.id.indexOf('language-link') > -1){
                return true;
            }
            
            var path = document.URL.replace(/(.*?[\\\/])([^\/\\]*)(\?.*)?(#.*)?$/, '$1');
            
            if (link && link.href && link.href.indexOf(path) == 0){
                //fetch content via AJAX request instead of following the link
                
                //all we need to do is set the hash with specific instruction to fetch content.
                //the hash checker will load the new content
                var overlayURL = link.href.substr(path.length).replace(/\.(html|php)/, '');
                
                //adjust the locationbar (so forwards/back buttons work)
                Shapeshifter.setPageId(overlayURL);
                return false;
            }       
        }
    })

    //setup error handling if AJAX requests fails
    $().ajaxError(function(event, request, settings){
        //and tell the user what happened
        var msg = "Sorry, we were unable to retrieve the page.<br />";
        if (request.status == 200 || request.status == 0){
            msg += "Error: Invalid XML";
        }
        else {
            msg += "Error: "+ request.status +": "+ request.statusText;
        }
        Shapeshifter.error(msg);
    });

    //initalise the overlay dialog
    $(document).ready(function(){
        $('#overlay').click(function(){
            $(this).fadeOut("fast");
            Shapeshifter.showContent();
        })
    })

    /**
    * error handler
    */
    Shapeshifter.error = function(msg){
        $('#msg-box').addClass('error')
        $('#msg').html(msg);
        $('#overlay').fadeIn("fast"); //("display", "block");
    }

    /**
    * 
    */
    Shapeshifter.loadPageFromHash = function(){
    
        var pageId = Shapeshifter.getPageId();
        
        if (pageId){
            //we'll start the fade out here
            Shapeshifter.hideContent();
            //and then request the new page.
            //once the new page has been retrieved, we'll fade in with the new xml
            Shapeshifter.xml = null;
            jQuery.get(pageId +".xml", '', Shapeshifter.contentRecieved, 'xml');    
            return true;
        }
        else {
            return false;
        }
    }

    /**
    * apply the given action to the document
    */
    Shapeshifter.applyChanges = function(xml){

        var NODE_TYPE_ELEMENT = 1;
        
        try {
            var overlay = xml.documentElement;
            
            for (var i=0; i<overlay.childNodes.length; i++){
                var node = overlay.childNodes[i];
                if (node.nodeType == NODE_TYPE_ELEMENT){
                    switch (node.nodeName.toLowerCase()){
                        //set the title of the document
                        case "title":
                            document.title = node.firstChild.data;
                            break;
                            
                        //set inner html of element
                        case "html":
                            $(node.getAttribute("selector")).html(Shapeshifter.getInnerXML(node));                            
                            break;
                        
                        //set an attribute
                        case "attr":
                            $(node.getAttribute("selector")).attr(node.getAttribute("name"), node.getAttribute("value"));
                            break;
                        
                        default:
                            throw Error("Unknown action '"+ node.nodeName +"'");    
                        
                    }
                }
            }
        }catch(e){
            Shapeshifter.error(e);
        }
        //we may need to attach some event handlers to the new content
        Shapeshifter.showQuotes();
        
        //hide all the testimonials except the first one
        $('div.testimonial').not("#testimonial-1").css("display", "none");
        
        $('#testimonials-list a').click(function(evt){
            var link = evt.target;
            var id = link.href.replace(/^[^#]*/, '');
            evt.stopPropagation();
            //frakking IE
            $('div.testimonial').css("backgroundColor", "#FFFFFF");
            
            if ($(id).get(0)){
                //fade out any other testimonial
                var faded = 0;
                $('div.testimonial').not(id).fadeOut(Shapeshifter.FADE_TIME, function(){
                    //and fadeIn this testimonial   
                    if (faded++ == $(this).length){                 
                        $(id).fadeIn(Shapeshifter.FADE_TIME);
                    }
                });
            }
            else {
                Shapeshifter.error("Unable to find element '"+ id +"'");    
            }
            return false;
        })
    }

    Shapeshifter.showQuotes = function(){
        if (Shapeshifter.showQuotes.timer){
            clearTimeout(Shapeshifter.showQuotes.timer);
        }

        //get an array of jQuery object representing the quotes
        var quotes = $('#quotes .quote').get();
        
        if (quotes.length > 2){
        
            Shapeshifter.showQuotes.index = -1;
            
            function showNextQuote(){
                //fadeOut the first quote
                if (Shapeshifter.showQuotes.timer){
                    clearTimeout(Shapeshifter.showQuotes.timer);
                }
                
                //fetch next quote
                Shapeshifter.showQuotes.index++;
                if (Shapeshifter.showQuotes.index >= quotes.length){
                    Shapeshifter.showQuotes.index = 0;
                }
                var html = $(quotes[Shapeshifter.showQuotes.index]).html();
                
                //build a quote 
                var quote = $('<div class="quote">'+ html +'</div>').hide();
                $("#dynamic-quotes").append(quote);
                
                quote.fadeIn(Shapeshifter.FADE_TIME);
                
                var visibleQuotes = $("#dynamic-quotes").children().get();
                if (visibleQuotes.length > Shapeshifter.QUOTES_VISIBLE){
                    for (var i=0; i<Shapeshifter.QUOTES_VISIBLE; i++){
                        visibleQuotes.pop();    
                    }
                    //now hide all the rest
                    $(visibleQuotes).animate({opacity: 0}, Shapeshifter.FADE_TIME, null, function(){
                        //and then move up
                        $(visibleQuotes).slideUp(Shapeshifter.FADE_TIME, function(){
                            //and delete
                            $(visibleQuotes).remove();
                        });
                    });   
                }
                Shapeshifter.showQuotes.timer = setTimeout(showNextQuote, Shapeshifter.QUOTE_INTERVAL);
            }
            
            //add initial quotes
            var currQuotes = $("#dynamic-quotes").children().get();
            for (var i=currQuotes.length; i<Shapeshifter.QUOTES_VISIBLE; i++){
                showNextQuote();
            }
            
            Shapeshifter.showQuotes.timer = setTimeout(showNextQuote, Shapeshifter.QUOTE_INTERVAL);
        }
    }


    $(document).ready(Shapeshifter.showQuotes);

    Shapeshifter.getInnerXML = function(node){
        var xml = '';
        for (var i=0; i<node.childNodes.length; i++){
            var child  = node.childNodes[i];
            //element
            if (child.nodeType == 1){
                xml += Shapeshifter.getOuterXML(child);
            }
            //text
            else if (child.nodeType == 3 || child.nodeType == 4){
                xml += child.data;
            }
            else {
                //ignore others
            }
        }
        return xml;
    }
    /**
    * return a string of the xml found within an element 
    */
    Shapeshifter.getOuterXML = function(node){
        
        var html = '<'+ node.nodeName;
        
        for (var i=0; i<node.attributes.length; i++){
            var attr = node.attributes[i];
            html += ' '+ Shapeshifter.encodeHTML(attr.name) +'="'+ Shapeshifter.encodeHTML(attr.value) +'"'
        }
        
        if (node.childNodes.length > 0){
            html += ">";
            for (var i=0; i<node.childNodes.length; i++){
                var child = node.childNodes[i];
                if (child.nodeType == 1){
                    html += Shapeshifter.getOuterXML(child);
                }
                else if (child.nodeType == 3 || child.nodeType == 4){
                    //html += Shapeshifter.encodeHTML(child.data);
                    html += child.data;
                }
                else {
                    //ignore all other node types
                }
            }
            html += "</"+ node.nodeName +">";
        }
        else {
            html += " />";
        }
        return html;
    }

    Shapeshifter.encodeHTML = function(str){
        str = str.replace(/&/g, "&amp;");
        str = str.replace(/</g, "&lt;");
        str = str.replace(/>/g, "&gt;");
        str = str.replace(/"/g, "&quot;");
        return str;
    }

    //flag to indicate if we are currently fading the page
    Shapeshifter.fadingOut = false;

    /**
    * fade the page out
    */
    Shapeshifter.hideContent = function(){
        Shapeshifter.fadingOut = true;
        
        if (document.getElementById('swf-loading')){
            $('#swf-loading').hide();
        }
        
        if (Shapeshifter.pageTransitionEffect == "slidefade"){
            $("#content, #sidebar-content").animate({height: 0, opacity: 0}, Shapeshifter.FADE_TIME);
        }
        else if (Shapeshifter.pageTransitionEffect == "slide"){
            $("#content, #sidebar-content").slideUp(Shapeshifter.FADE_TIME);
        }
        //use a real browser
        else {            
            $("#content, #sidebar-content").animate({opacity: 0}, Shapeshifter.FADE_TIME);
        }
        
        $('#page-loading-foreground').animate({
            top: "0px",
            right: "0px"
        }, Shapeshifter.FADE_TIME, function(){
            Shapeshifter.fadingOut = false;    
            // after it's faded check for new content
            // if new content, replace content and fade in.
            if (Shapeshifter.xml){
                Shapeshifter.applyChanges(Shapeshifter.xml); 
                Shapeshifter.xml = null;
                Shapeshifter.showContent();
            }        
        });
    }

    /**
    * fades in the page
    */
    Shapeshifter.showContent = function(){

        //start marquee if it exists on this page
        if (Shapeshifter.pageTransitionEffect == "slidefade"){
            $("#content, #sidebar-content").animate({height: "100%", opacity: 1}, Shapeshifter.FADE_TIME);
        }
        else if (Shapeshifter.pageTransitionEffect == "slide"){
            $("#content, #sidebar-content").slideDown(Shapeshifter.FADE_TIME);
        }
        else {            
            $("#content, #sidebar-content").animate({opacity: 1}, Shapeshifter.FADE_TIME);
        }
        
        $('#page-loading-foreground').animate({
            top: "50px",
            right: "50px"
        }, Shapeshifter.FADE_TIME);
    }

    /**
    * handle content recieved via an ajax request
    */
    Shapeshifter.contentRecieved = function(xml){
        //wait until the fade has completed, it's callback will apply the xml
        if (Shapeshifter.fadingOut){
            Shapeshifter.xml = xml;
        }
        //or fade in immediately
        else {
            Shapeshifter.applyChanges(xml); 
            Shapeshifter.showContent();
        }
    }

    /**/
    if (jQuery.browser.msie){
        $(document).ready(function(){
            //fading in IE is broken unless the faded element has a set background
            $('#sidebar-content, #content').css('backgroundColor', '#FFFFFF');
        });
    }

    /* make the page "faded out" to start with, then fadein once the images have loaded */
    document.write('<style type="text/css">\
    #page-loading-foreground {\
        top: 0px;\
        right: 0px;\
    }\
    #sidebar-content {\
        display: none;\
    }\
    #content {\
        display: none;\
        height: 0px;\
        opacity: 0;\
    }\
    #quotes .quote {\
        display: none;\
    }\
    </style>');


    $(document).ready(function(){ 
        if (window.location.hash){
            //first load, if hash is the same as document, done reload the content
            var page = window.location.hash.replace(/^#(.*)\.\w+$/, '$1');
            page = page || 'index';
            var thisPage = document.URL.replace(/.*\/([^\/\?#]*)(\.\w+)?([\?#].*)?$/, '$1');
            thisPage = thisPage || 'index';
            if (page != thisPage){
                Shapeshifter.loadPageFromHash();
            }
            else {
                Shapeshifter.showContent();
            }
        }
        else {
            Shapeshifter.showContent();
        }
    });

    //check for back/forward events
    $(document).ready(function(){
    
        var lastPage = window.location.hash.substr(1) || 'index';
        
        //IE is soooo screwed up
        if (jQuery.browser.msie){
            if (lastPage != 'index'){
                Shapeshifter.setPageId(lastPage);
                Shapeshifter.loadPageFromHash();
            }
        }
        
        var checkPage = function(){
            var page = Shapeshifter.getPageId();
            
            if (page && (lastPage != page)){
                lastPage = page;
                Shapeshifter.loadPageFromHash();
                if (jQuery.browser.msie){
                    Shapeshifter.setPageId(page);
                }
            }
            setTimeout(checkPage, 50);
        }
        checkPage();
    });

    //fix for scrollbars cause the centered page to jump to the left bug.
    $(document).ready(function(){
        $("#container").css("marginLeft", $("#container").offset().left);
    });
    $(window).resize(function(){
        $("#container").css("marginLeft", "auto");
        setTimeout(function(){
            $("#container").css("marginLeft", $("#container").offset().left);
        },1);
    })
}


function debug(obj){
    var str = '';
    for (var prop in obj){
        try {
            str += prop +"="+ obj[prop] +"\n";
        }catch(e){
            str += prop +"= ?\n";
        }
    }
    alert(str);
}