/**
 * SWFAddress 2.0: Deep linking for Flash and Ajax - http://www.asual.com/swfaddress/
 *
 * SWFAddress is (c) 2006-2007 Rostislav Hristov and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */

if(typeof asual == "undefined") var asual = {};
if(typeof asual.util == "undefined") asual.util = {};
   
/**
 * @class Utility class that provides detailed browser information
 * @constructor
 */
asual.util.Browser = new function() {

    var supported = false;
    var version = -1;
    
    var agent = navigator.userAgent;
    var ie = false;
    var camino = false;
    var safari = false;
    var opera = false;
    var mozilla = false;
    
    if (/MSIE/.test(agent)) {
        ie = true;
        version = parseFloat(agent.substring(agent.indexOf('MSIE') + 4));
        supported = version >= 6;
    } else if (/AppleWebKit/.test(agent)) {
        safari = true;
        version = parseFloat(agent.substring(agent.indexOf('Safari') + 7));
        supported = version >= 312;
    } else if (/Opera/.test(agent)) {
        opera = true;
        version = parseFloat(navigator.appVersion);
        supported = version >= 9.02;
    } else if (/Camino/.test(agent)) {
        camino = true;
        version = parseFloat(agent.substring(agent.indexOf('Camino') + 7));
        supported = version >= 1;
    } else if (/Firefox/.test(agent)) {
        mozilla = true;
        version = parseFloat(agent.substring(agent.indexOf('Firefox') + 8));
        supported = version >= 1;
    } else if (/Netscape/.test(agent)) {
        mozilla = true;
        version = parseFloat(agent.substring(agent.indexOf('Netscape') + 9));
        supported = version >= 8;
    } else if (/Mozilla/.test(agent) && /rv:/.test(agent)) {
        mozilla = true;
        version = parseFloat(agent.substring(agent.indexOf('rv:') + 3));
        supported = version >= 1.8;
    }
    
    /**
     * Detects if the browser is supported
     * @type Boolean
     */
    this.isSupported = function() {
        return supported;
    }

    /**
     * Detects the version of the browser
     * @type Number
     */
    this.getVersion = function() {
        return version;
    }

    /**
     * Detects if the browser is Internet Explorer
     * @type Boolean
     */
    this.isIE = function() {
        return ie;
    }

    /**
     * Detects if the browser is Safari
     * @type Boolean
     */
    this.isSafari = function() {
        return safari;
    }

    /**
     * Detects if the browser is Opera
     * @type Boolean
     */
    this.isOpera = function() {
        return opera;
    }

    /**
     * Detects if the browser is Camino
     * @type Boolean
     */
    this.isCamino = function() {
        return camino;
    }

    /**
     * Detects if the browser is Mozilla
     * @type Boolean
     */
    this.isMozilla = function() {
        return mozilla;
    }
}

/**
 * @class Utility class that provides event helpers
 * @constructor 
 */
asual.util.Events = new function() {

    var cache = [];
    var browser = asual.util.Browser;
    var dcl = 'DOMContentLoaded';

    if (browser.isIE()) {
        document.write('<script id=swfaddress-domload defer=true src=//:></script>');
        document.getElementById('swfaddress-domload').onreadystatechange = function() {
            if (this.readyState == 'complete') { 
                this.parentNode.removeChild(this);
                for (var i = 0, e; e = cache[i]; i++) {
                    if (e.t == dcl) e.l.call(null);
                }
            }
        };
    } else if (browser.isSafari()) {
        var timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) { 
                clearInterval(timer); 
                for (var i = 0, e; e = cache[i]; i++) {
                    if (e.t == dcl) e.l.call(null);
                }
            }
        }, 10);
    }    
    
    /**
     * Adds a cross-browser event listener to an object
     * @param {Object} obj
     * @param {String} type
     * @param {Function} listener
     */
    this.addListener = function(obj, type, listener) {
        cache.push({o: obj, t: type, l: listener});
        if (type == dcl && (browser.isIE() || browser.isSafari())) 
            return;
        if (obj.addEventListener){
            obj.addEventListener(type, listener, false);
        } else if (obj.attachEvent){
            obj.attachEvent('on' + type, listener);
        }
    }
    
    /**
     * Removes a cross-browser event listener from an object
     * @param {Object} obj
     * @param {String} type
     * @param {Function} listener
     */    
    this.removeListener = function(obj, type, listener) {
        for (var i = 0, e; e = cache[i]; i++) {
            if (e.o == obj && e.t == type && e.l == listener) {
                cache.splice(i, 1);
                break;
            }
        }
        if (type == dcl && (browser.isIE() || browser.isSafari())) 
            return;
        if (obj.removeEventListener){
            obj.removeEventListener(type, listener, false);
        } else if (obj.detachEvent){
            obj.detachEvent('on' + type, listener);
        }
    }
    
    var unload = function() {
        for (var i = 0, evt; evt = cache[i]; i++) {
            if (evt.t != dcl)
                asual.util.Events.removeListener(evt.o, evt.t, evt.l);
        }
    }
    
    if (browser.isIE() || browser.isSafari()) {    
        this.addListener(window, 'unload', unload);    
    }
}

/**
 * Creates a new SWFAddress event
 * @class An event class for SWFAddress
 * @constructor
 * @param {String} type Type of the event 
 */
SWFAddressEvent = function(type) {

    /**
     * The type of this event
     * @type String
     */
    this.type = type;

    /**
     * The target of this event
     * @type Function
     */
    this.target = [SWFAddress][0];

    /**
     * The value of this event
     * @type String
     */
    this.value = SWFAddress.getValue();

    /**
     * The path of this event
     * @type String
     */
    this.path = SWFAddress.getPath();

    /**
     * The parameters of this event
     * @type Array
     */
    this.parameters = [];

    var names = SWFAddress.getParameterNames();
    for (var i = 0, n; n = names[i]; i++) {
        this.parameters[n] = SWFAddress.getParameter(n);
    }
}

/**
 * Init event
 * @type String
 */
SWFAddressEvent.INIT = 'init';

/**
 * Change event
 * @type String
 */
SWFAddressEvent.CHANGE = 'change';

/**
 * @class Deep linking class
 */ 
SWFAddress = new function() {

    var browser = asual.util.Browser;
    var iframe, form, supported = browser.isSupported();
    var swfaddr, swfobj, swfupdate = false;
    var swftitle = document.title;
    var swflength = history.length;
    var swfhistory = [];   
    var swfids = [];
    var listeners = {};    
    var swftrackingEnabled = true;
    var swfhistoryEnabled = true;
    var js = 'swfaddress.js';
    var swf = 'swfaddress.swf';
    var html = 'swfaddress.html';
    var d = top.document;
    var h = top.history;
    var l = top.location;
    
    if ((!supported && l.href.indexOf('#') != -1) || 
        (browser.isSafari() && browser.getVersion() < 412 && l.href.indexOf('#') != -1 && l.search != '')){
        d.open();
        d.write('<html><head><meta http-equiv="refresh" content="0;url=' + l.href.substr(0, l.href.indexOf('#')) + '" /></head></html>');
        d.close();
    }

    var getURL = function(url) {
        var scripts = document.getElementsByTagName('script');
        for (var i = 0, s; s = scripts[i]; i++) {
            if (s.src.indexOf(js) > -1) {
                return (new String(s.src)).replace(js, url);
            }
        }
    }

    var getHash = function() {
        var index = l.href.indexOf('#');
        if (index != -1) {
            return l.href.substring(index).replace(/^#/g, '');
        }
        return '';
    }

    var hash = getHash();

    var titleListener = function() {
        if (browser.isIE() && d.title != swftitle) {
            SWFAddress.setTitle(swftitle);
        }
    }

    var listen = function() {
        if (!swfupdate) {
            if (browser.isIE()) {
                if (hash != getHash()) {
                    if (browser.getVersion() < 7) {
                        l.reload();
                    } else {
                        SWFAddress.setValue(getHash());
                    }
                }
            } else if (browser.isSafari()) {
                if (swflength != h.length) {
                    swflength = h.length;
                    if (typeof swfhistory[swflength - 1] != 'undefined') {
                        hash = swfhistory[swflength - 1];
                    }
                    update();
                }
            } else if (hash != getHash()) {
                hash = getHash();
                /*
                if (browser.isMozilla() && browser.getVersion() >= 2) {
                    var hcheck = false;
                    for (var i = 0; i < swfhistory.length; i++) {
                        if (swfhistory[i] == hash) {
                            hcheck = true; break;
                        }
                    }
                    if (!hcheck) {
                        l.reload(); return;
                    }
                }*/
                update();
            }
            titleListener();
        }
    }

    var jsDispatch = function(type) {
        if (SWFAddress.hasEventListener(type)) {
            SWFAddress.dispatchEvent(new SWFAddressEvent(type));
        }
        type = type.substr(0, 1).toUpperCase() + type.substring(1);
        if(typeof SWFAddress['on' + type] == 'function') {
            SWFAddress['on' + type]();
        }        
    }
    
    var jsInit = function() {
        jsDispatch('init');
    }
    
    var jsChange = function() {
        jsDispatch('change');
    }
    
    var swfChange = function() {
        for (var i = 0, swfid; swfid = swfids[i]; i++) {
            var obj = document.getElementById(swfid);
            if (obj) {
                if (obj.parentNode && typeof obj.parentNode.so != 'undefined') {
                    obj.parentNode.so.call('setSWFAddressValue', swfaddr);
                } else {
                    obj = (typeof obj != 'undefined' && typeof obj.setSWFAddressValue != 'undefined') ? 
                        obj : ((typeof obj.getElementsByTagName('object')[0] != 'undefined' && 
                        typeof obj.getElementsByTagName('object')[0].setSWFAddressValue != 'undefined') ? 
                        obj.getElementsByTagName('object')[0] : ((typeof obj.getElementsByTagName('embed')[0] != 'undefined' && 
                        typeof obj.getElementsByTagName('embed')[0].setSWFAddressValue != 'undefined') ? 
                        obj.getElementsByTagName('embed')[0] : null));
                    if (obj) {
                        obj.setSWFAddressValue(swfaddr);
                    }
                }
            }
        }
    }

    var update = function() {
        if (swfaddr != hash) {
            swfaddr = hash;
            swfChange();
            jsChange();
        }
    }

    var track = function() {
        if (swftrackingEnabled && typeof urchinTracker != 'undefined'){
            var path = l.pathname + SWFAddress.getValue();
            path = path.replace(/\/\//, '/');
            path = path.replace(/^\/$/, '');
            urchinTracker(path);
        }
    }

    var loadSuccess = function() {
        if (iframe.contentWindow && iframe.contentWindow.location) {
            var win = iframe.contentWindow;
            win.document.title = d.title = swftitle;
            var src = win.location.href;
            if (src.indexOf('?') > -1) {
                hash = src.substring(src.indexOf('?') + 1);
            } else {
                hash = '';
            }
            if (hash != getHash()) {
                update();
                l.hash = '#' + hash;
            }
        }
    }
    
    var load = function() {
        var content = document.createElement('div');
        document.body.appendChild(content);
        content.id = 'swfaddress';
        content.style.position = 'absolute';
        content.style.left = content.style.top = '-9999px';
        if (browser.isIE() || browser.isSafari()) {
            content.innerHTML = '<iframe src="' + getURL(html) + '?' + getHash() + '" width="0" height="0"></iframe>';
            iframe = content.getElementsByTagName('iframe')[0];
        }
        if (browser.isIE()) {
            asual.util.Events.addListener(iframe, 'load', loadSuccess);  
        }
        if (browser.isSafari()) {
            form = document.createElement('form');
            form.id = 'swfaddress-form';        
            form.method = 'get';
            content.appendChild(form);        
            if (typeof l.swfaddress == 'undefined') {
                l.swfaddress = {};
            }
            if (typeof l.swfaddress.history != 'undefined') {
                swfhistory = l.swfaddress.history.split(',');
            }
        }
        if (browser.isOpera() && typeof swfids.length > 0) {
            content.innerHTML = '<embed src="' + getURL(swf) + '" type="application/x-shockwave-flash" width="1" height="1" />';
        }
        setTimeout(jsInit, 1);
        setTimeout(jsChange, 2);
        setInterval(listen, 50);
        track();
    }

    /**
     * Change event.
     * @type Function
     */
    this.onInit = null;
    
    /**
     * Init event.
     * @type Function
     */
    this.onChange = null;

    /**
     * String representation of this class.
     */
    this.toString = function() {
        return '[class SWFAddress]';
    }

    /**
     * Loads the previous URL in the history list.
     */
    this.back = function() {
        h.back();
    }

    /**
     * Loads the next URL in the history list.
     */    
    this.forward = function() {
        h.forward();
    }

    /**
     * Loads a URL from the history list.
     * @param {Number} delta An integer representing a relative position in the history list
     */
    this.go = function(delta) {
        h.go(delta);
    }

    /**
     * Registers an event listener.
     * @param {String} type Event type
     * @param {Function} listener Event listener
     */ 
    this.addEventListener = function (type, listener) {
        if (typeof listeners[type] == 'undefined') {
            listeners[type] = [];
        }
        listeners[type].push(listener);
    }

    /**
     * Removes an event listener. 
     * @param {String} type Event type
     * @param {Function} listener Event listener
     */     
    this.removeEventListener = function (type, listener) {
        if (typeof listeners[type] != 'undefined') {
            for (var i = 0, l; l = listeners[type][i]; i++) {
                if (l == listener) break;
            }
            listeners[type].splice(i, 1);
        }
    }

    /**
     * Dispatches an event to all the available listeners. 
     * @param {Object} event Event object
     */       
    this.dispatchEvent = function (event) {
        if (typeof listeners[event.type] != 'undefined') {
            event.target = this;
            for (var i = 0, l; l = listeners[event.type][i]; i++) {
                l(event);
            }
        }
    }

    /**
     * Checks the existance of any listeners registered for a specific type of event. 
     * @param {String} event Event type
     * @type Array
     */     
    this.hasEventListener = function (type) {
        return (typeof listeners[type] != 'undefined' && listeners[type].length > 0);
    }

    this.getHistoryEnabled = function() {
        return swfhistoryEnabled;
    }

    this.setHistoryEnabled = function(enabled) {
        swfhistoryEnabled = enabled;
    }

    this.getTrackingEnabled = function() {
        return swftrackingEnabled;
    }

    this.setTrackingEnabled = function(enabled) {
        swftrackingEnabled = enabled;
    }

    /**
     * Opens a new URL in the browser. 
     * @param {String} url The resource to be opened
     * @param {String} target Target window
     */
    this.href = function(url, target) {
        target = typeof target != 'undefined' ? target : '_self';     
        switch(target) {
            case '_self': 
                self.location.href = url; 
                break;
            case '_top': 
                top.location.href = url; 
                break;                
            case '_blank':
                window.open(url); 
                break; 
            default:
                document.frames[target].location.href = url; 
                break; 
        }
    }

    /**
     * Opens a browser popup window. 
     * @param {String} url The resource to be opened
     * @param {String} name The name of the popup window
     * @param {String} options Popup options which get evaluted and passed to the window.open() method
     * @param {String} handler Optional JavsScript handler code for popup handling     
     */
    this.popup = function(url, name, options, handler) {
        var popup = window.open(url, name, eval(options));
        eval(handler);
    }

    this.getIds = function() {
        return swfids;
    }

    this.getId = function(index) {
        return swfids[0];
    }

    this.setId = function(id) {
        swfids[0] = id;
    }

    this.addId = function(id) {
        swfids.push(id);
    }

    this.getTitle = function() {
        return d.title;
    }

    this.setTitle = function(title) {
        if (!supported) return null;
        if (title == 'null') {
            title = '';
        }        
        if (typeof title != 'undefined') {
            swftitle = title;
            d.title = swftitle;
        }
    }

    this.getStatus = function() {
        return top.status;
    }

    this.setStatus = function(status) {
        if (!supported) return null;
        if (!browser.isSafari()) {
            if (status == 'null' || typeof status == 'undefined') {
                status = '';
            }        
            if (/http(s)?:\/\//.test(status) == false) {
                var index = l.href.indexOf('#');
                status = (index == -1 ? l.href : l.href.substr(0, index)) + '#' + status;
            }
            top.status = status;
        }
    }

    this.resetStatus = function() {
        top.status = '';
    }

    this.getValue = function() {
        if (!supported) return null;
        return hash;
    }

    this.setValue = function(value) {
        if (!supported) return null;
        if (value == 'null') {
            value = '';
        }
        if (swfaddr == value) {
            return;
        }
        swfupdate = true;
        hash = value;
        update();
        if (swfaddr != value) {
            return;
        }
        swfhistory[history.length] = hash;
        if (browser.isSafari()) {
            if (swfhistoryEnabled) {
                l.swfaddress.history = swfhistory.toString();
                swflength = history.length + 1;
                if (browser.getVersion() < 412) {
                    if (l.search == '') {
                        form.action = '#' + hash;
                        form.submit();
                    }
                } else {
                    var evt = document.createEvent('MouseEvents');
                    evt.initEvent('click', true, true);
                    var anchor = document.createElement('a');
                    anchor.href = '#' + hash;
                    anchor.dispatchEvent(evt);
                }
            } else {
                l.hash = '#' + hash;
            }
        } else if (hash != getHash()) {
            if (swfhistoryEnabled) {
                l.hash = '#' + hash;
            } else {
                l.replace('#' + hash);
            }
        }
        if (browser.isIE() && swfhistoryEnabled) {
            var win = iframe.contentWindow;
            var query = '?' + getHash();
            win.location.assign(win.location.pathname + query);
        }
        track();
        swfupdate = false;
    }

    this.getPath = function() {
        var value = this.getValue();
        if (value.indexOf('?') != -1) {
            return value.split('?')[0];
        } else {
            return value;   
        }
    }

    this.getQueryString = function() {
        var value = this.getValue();
        var index = value.indexOf('?');
        if (index != -1 && index < value.length) {
            return value.substr(index + 1);
        }
        return '';
    }

    this.getParameter = function(param) {
        var value = this.getValue();
        var index = value.indexOf('?');
        if (index != -1) {
            value = value.substr(index + 1);
            var params = value.split('&');
            var p, i = params.length;
            while(i--) {
                p = params[i].split('=');
                if (p[0] == param) {
                    return p[1];
                }
            }
        }
        return '';
    }

    this.getParameterNames = function() {
        var value = this.getValue();
        var index = value.indexOf('?');
        var names = [];
        if (index != -1) {
            value = value.substr(index + 1);
            if (value != '' && value.indexOf('=') != -1) {            
                var params = value.split('&');
                var i = 0;
                while(i < params.length) {
                    names.push(params[i].split('=')[0]);
                    i++;
                }
            }
        }
        return names;
    }

    if (!supported) return;
    
    for (var i = 1; i < swflength; i++) {
        swfhistory.push('');
    }
    swfhistory.push(l.hash.replace(/^#/g, ''));

    if (browser.isIE() && l.hash != getHash()) {
        l.hash = '#' + getHash();
    }

    swfaddr = this.getValue();
    titleListener();
    asual.util.Events.addListener(document, 'DOMContentLoaded', load);
}

if (typeof SWFObject != 'undefined') {
    asual.SWFObjectWrite = SWFObject.prototype.write;
    SWFObject.prototype.write = function(elementId) {
        if (this.getAttribute('version').major < 8) {
            this.addVariable('$swfaddress', SWFAddress.getValue());
            ((typeof elementId == 'string') ? document.getElementById(elementId) : elementId).so = this;
        }
        asual.SWFObjectWrite.apply(this, arguments);
        SWFAddress.addId(this.getAttribute('id'));
    }
}
if (typeof SWFFix != 'undefined') {
    asual.SWFFixRegisterObject = SWFFix.registerObject;
    SWFFix.registerObject = function(objectIdStr, swfVersionStr, xiSwfUrlStr) {
        asual.SWFFixRegisterObject.apply(this, arguments);
        SWFAddress.addId(objectIdStr);
    }
    asual.SWFFixCreateSWF = SWFFix.createSWF;
    SWFFix.createSWF = function(attObj, parObj, el) {
        asual.SWFFixCreateSWF.apply(this, arguments);
        SWFAddress.addId(attObj.id);
    }
    asual.SWFFixEmbedSWF = SWFFix.embedSWF;
    SWFFix.embedSWF = function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, 
        swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {
        asual.SWFFixEmbedSWF.apply(this, arguments);
        SWFAddress.addId(attObj.id);
    }
}
if (typeof UFO != 'undefined') {
    asual.UFOCreate = UFO.create;
    UFO.create = function(FO, id) {
        asual.UFOCreate.apply(this, arguments);
        SWFAddress.addId(id);
    }
}
if (typeof AC_FL_RunContent != 'undefined') {
    asual.AC_FL_RunContent = AC_FL_RunContent;
    AC_FL_RunContent = function() {
        asual.AC_FL_RunContent.apply(this, arguments);
        for (var i = 0, a; a = arguments[i]; i++) {
            if (a == 'id') {
                SWFAddress.addId(arguments[i+1]);
                break;
            }
        }
    }
}
