window.console||(window.console=window.console||{});
console.log||(console.log=((window.opera||{}).postError||function(){}));

(function() {


/* =-=====================================================================-= */
/* =-=====================================================================-= */
/* =-=======================        LIBRAR       =========================-= */
/* =-=====================================================================-= */
/* =-=====================================================================-= */

/**
 * NOW
 * ===
 * var timestamp = now();
 */
var now = function() {
    return+new Date

/**
 * WINFO
 * =====
 * var window_info = winfot();
 * log(window_info.height);
 */
},  winfo = function() {
    return { height    : window.innerHeight ||
                         document.documentElement.clientHeight ||
                         document.body.clientHeight,
             scrollTop : document.documentElement.scrollTop ||
                         document.body.scrollTop
           }

/**
 * OFFSET
 * =======
 * offset( search('div')[0], 'Width' );
 * offset( search('div')[0], 'Height' );
 * offset( search('div')[0], 'Top' );
 * offset( search('div')[0], 'Left' );
 */
},  offset = function( node, what ) {
    var pos  = 0
    ,   what = what || 'Top';

    while (node) {
        pos += node['offset'+what];
        node = node.offsetParent;
    }

    return pos

/**
 * $
 * =
 * var div = $('divid');
 */
},  $ = function(id) {
    return document.getElementById(id);


/**
 * SEARCH
 * ======
 * var elements = search('a div span');
 */
},  search = function(elements) {
    var list = [];
    each( elements.split(/\s+/), function(el) {
        each( document.getElementsByTagName(el), function(node) {
            list.push(node);
        } );
    } );
    return list

/**
 * EACH
 * ====
 * each( [1,2,3], function(item) { console.log(item) } )
 */
},  each = function( o, f ) {
    if ( !o || !f ) return;

    if ( o[0] )
        for ( var i = 0, l = o.length; i < l; )
            f.call( o[i], o[i], i++ );
    else 
        for ( var i in o )
            o.hasOwnProperty          &&
            o.hasOwnProperty(i)       &&
            typeof o[i] != 'function' &&
            f.call( o[i], i, o[i] );

/**
 * WALK
 * ====
 * walk( search('body')[0], function(node) { node.doSomething; } )
 */
},  walk = function( n, f ) {
    f.call( n, n );
    n = n.firstChild;
    while (n) {
        walk( n, f );
        n = n.nextSibling;
    }

/**
 * MAP
 * ===
 * var list = map( [1,2,3], function(item) { return item + 1 } )
 */
},  map = function( list, fun ) {
    var fin = [];
    each( list || [], function(l) { fin.push(fun(l)) } );
    return fin

/**
 * GREP
 * ====
 * var list = grep( [1,2,3], function(item) { return item % 2 } )
 */
},  grep = function( list, fun ) {
    var fin = [];
    each( list || [], function(l) { fun(l) && fin.push(l) } );
    return fin

/**
 * BIND
 * ====
 * bind( 'keydown', search('a')[0], function(element) {
 *     console.log( element, '1st anchor' )
 * } );
 */
},  bind = function( type, el, fun ) {
    var rapfun = function(e) {
        if (!fun(e)) {
            e.cancelBubble = true;
            e.returnValue  = false;
            if (e.stopPropagation) {
                e.stopPropagation();
                e.preventDefault();
            }
        }
    };

    if ( el.addEventListener ) el.addEventListener( type, rapfun, false );
    else if ( el.attachEvent ) el.attachEvent( 'on' + type, rapfun );
    else  el[ 'on' + type ] = rapfun;

/**
 * UNBIND
 * ======
 * unbind( 'keydown', search('a')[0] );
 */
},  unbind = function( type, el, fun ) {
    if ( el.removeEventListener ) el.removeEventListener( type, false );
    else if ( el.detachEvent ) el.detachEvent( 'on' + type, false );
    else  el[ 'on' + type ] = null;


/**
 * HEAD
 * ====
 * head().appendChild(elm);
 */
},  head = function() { return document.getElementsByTagName('head')[0] }


/**
 * URLIZE
 * ======
 * var query_string = urlize({key:'dat'});
 */
,   urlize = function( data, url ) {
    if (!data) return '';
    var params = [], key = '';
    for ( key in data ) params.push( escape(key) + '=' + escape(data[key]) );
    return (url.indexOf('?') === -1 ? '?' : '&') + params.join('&')

/**
 * ATTR
 * ====
 * var attribute = attr( node, 'attribute' );
 */
},  attr = function( node, attribute, value ) {
    if (value) node.setAttribute( attribute, value );
    else return node.getAttribute && node.getAttribute(attribute);


/**
 * CSS
 * ===
 * var obj = create('div');
 */
},  css = function( element, styles ) {
    for (var style in styles) if (styles.hasOwnProperty(style))
        element.style[style] = styles[style] + (
            '|width|height|top|left|'.indexOf(style) > 0 ? 'px' : ''
        );

/**
 * CREATE
 * ======
 * var obj = create('div');
 */
},  create = function(element) {
    return document.createElement(element);


/**
 * BEGET
 * =====
 * var obj = beget(oldObject);
 */
},  beget = function(o) {
    function F() {}
    F.prototype = o;
    return new F();

/**
 * PARSE
 * =====
 * var obj = parse("{obj:'dat'}");
 */
},  parse = function(string) {
    return typeof JSON !== 'undefined' &&
        JSON.parse(string) || eval('('+string+')')

/**
 * XDR Cross Domain Request
 * ========================
 *  xdr({
 *     url  : 'url',  // required
 *     type : 'text', // [script, json, text]
 *     data : {
 *         'key' : 'value',
 *         'key' : 'value'
 *     },
 *     success : function(response) {
 *         // your code here
 *     },
 *     fail : function() {
 *         // your code here
 *     }
 * });
 */
},  xdr = function( setup ) {
    var script  = document.createElement('script')
    ,   unique  = 'xdr3-' + now()
    ,   json_r  = /([\\"])/g
    ,   timeout = setTimeout(function(){done('timeout')},setup.timeout||30000)
    ,   data    = setup.data    || {}
    ,   fail    = setup.fail    || function(){}
    ,   success = setup.success || function(){}

    ,   append  = function() { setTimeout( function() { 
            try { head().appendChild(script); }
            catch(err) { append(); }
         }, 100 ) }

    ,   done = function(failed) {
            clearTimeout(timeout);
            if (!script) return;
            failed && fail.call( failed, script, unescape(script.src) );
            script.onload = script.onreadystatechange = script.onerror = null;
            try {head().removeChild(script);} catch(error) {}
        };

    script.onload = script.onreadystatechange = function(e) {
        // nothing untill it's loaded.
        var state = this.readyState;
        if ( !(!state ||
                state == "loaded" ||
                state == "complete")) return;

        var response = unescape( window[unique] || '' );

        if ( !response ) return done('no data');

        // setup type supplied
        switch(setup.type) {
            case 'json' :
                response = parse(response);
                break;
            case 'script' :
                response = eval(response);
        }

        // invoke user defined function
        success.call( script, response );

        // destroy
        window[unique] = '';
        done(0);
    };

    bind( 'error', script, function() { done('error') } );

    data['unique'] = unique;
    script.src  = setup.url + urlize( data, setup.url );

    // try to call xdr as soon as possible.
    append();

/**
 * AJAX
 * ====
 *  ajax({
 *     url  : 'url',  // required
 *     type : 'text', // [script, json, text]
 *     data : [
 *         'key' : 'value',
 *         'key' : 'value'
 *     ],
 *     success : function(response) {
 *         // your code here
 *     },
 *     fail : function() {
 *         // your code here
 *     }
 * });
 */
},  ajax = function( setup ) {
    var xhr = window.ActiveXObject ?
              new ActiveXObject("Microsoft.XMLHTTP") :
              new XMLHttpRequest()
    ,   rsc = function() {
            if (  // complete?
                xhr &&
                xhr.readyState == 4 &&
                !done
            ) {
                done = 1;

                if (ival) {
                    clearInterval(ival);
                    ival = null;
                }

                // Invoke Success Or Failure
                if (
                    (xhr.status >= 200 && xhr.status < 300) ||
                    xhr.status == 304 || xhr.status == 1223
                ) setup.success && setup.success(xhr.responseText);
                else setup.error && setup.error(xhr.responseText);

                // Done with XHR
                xhr = null;
            }
        }
    ,   done = 0
    ,   data = setup.data
    ,   url  = setup.url
    ,   ival = setInterval( rsc, 14 ); // polling method

    xhr.open( setup.type || 'get', data ? urlize( data, url ) : url );
    /*
    xhr.setRequestHeader(
        "Content-Type",
        "application/x-www-form-urlencoded"
    );
    */

    // Send
    xhr.send(null /*urlize( data, setup.url )*/);




/**
 * DOM READY
 */
}, DomReady = {},

// Everything that has to do with properly supporting our document ready event. Brought over from the most awesome jQuery. 
userAgent = navigator.userAgent.toLowerCase(),

// Figure out what browser is being used
browser = {
    version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
    safari: /webkit/.test(userAgent),
    opera: /opera/.test(userAgent),
    msie: (/msie/.test(userAgent)) && (!/opera/.test( userAgent )),
    mozilla: (/mozilla/.test(userAgent)) && (!/(compatible|webkit)/.test(userAgent))
},
readyBound = false,
isReady = false,
readyList = [];

// Handle when the DOM is ready
function domReady() {
    // Make sure that the DOM is not already loaded
    if(!isReady) {
        // Remember that the DOM is ready
        isReady = true;
    
        if(readyList) {
            for(var fn = 0; fn < readyList.length; fn++) {
                readyList[fn].call(window, []);
            }
        
            readyList = [];
        }
    }
};

// From Simon Willison. A safe way to fire onload w/o screwing up everyone else.
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
};

// does the heavy work of working through the browsers idiosyncracies (let's call them that) to hook onload.
function bindReady() {
    if(readyBound) {
        return;
    }

    readyBound = true;

    // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
    if (document.addEventListener && !browser.opera) {
        // Use the handy event callback
        document.addEventListener("DOMContentLoaded", domReady, false);
    }

    // If IE is used and is not in a frame
    // Continually check to see if the document is ready
    if (browser.msie && window == top) (function(){
        if (isReady) return;
        try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll("left");
        } catch(error) {
            setTimeout(arguments.callee, 0);
            return;
        }
        // and execute any waiting functions
        domReady();
    })();

    if(browser.opera) {
        document.addEventListener( "DOMContentLoaded", function () {
            if (isReady) return;
            for (var i = 0; i < document.styleSheets.length; i++)
                if (document.styleSheets[i].disabled) {
                    setTimeout( arguments.callee, 0 );
                    return;
                }
            // and execute any waiting functions
            domReady();
        }, false);
    }

    if(browser.safari) {
        var numStyles;
        (function(){
            if (isReady) return;
            if (document.readyState != "loaded" && document.readyState != "complete") {
                setTimeout( arguments.callee, 0 );
                return;
            }
            if (numStyles === undefined) {
                var links = document.getElementsByTagName("link");
                for (var i=0; i < links.length; i++) {
                    if(links[i].getAttribute('rel') == 'stylesheet') {
                        numStyles++;
                    }
                }
                var styles = document.getElementsByTagName("style");
                numStyles += styles.length;
            }
            if (document.styleSheets.length != numStyles) {
                setTimeout( arguments.callee, 0 );
                return;
            }
        
            // and execute any waiting functions
            domReady();
        })();
    }

    // A fallback to window.onload, that will always work
    addLoadEvent(domReady);
};

// This is the public function that people can use to hook up ready.
DomReady.ready = function(fn, args) {
    // Attach the listeners
    bindReady();

    // If the DOM is already ready
    if (isReady) {
        // Execute the function immediately
        fn.call(window, []);
    } else {
        // Add the function to the wait list
        readyList.push( function() { return fn.call(window, []); } );
    }
};
bindReady();

/* =-=====================================================================-= */
/* =-=====================================================================-= */
/* =-=======================      END LIBRAR     =========================-= */
/* =-=====================================================================-= */
/* =-=====================================================================-= */


    // already running?
var running        = false
,   HTTP           = location.href.split('/')[0]
,   CDN            = "http://dfixj4nw6vyl5.cloudfront.net/"
,   CDN_SSL        = "https://cdnj.s3.amazonaws.com/"
,   DOMAIN_KEY     = "beta5/"
,   APP            = "//cdnjoy3.appspot.com"
,   LOCAL          = "//localhost"
,   SERVER_URL     = HTTP + (location.href.indexOf(LOCAL) > 0 ? LOCAL : APP)
,   fail_timeout   = setTimeout( function() {updateCDN( {}, true )}, 2200 )
,   cookies        = document.cookie
    // http://www.domain.com:8010/current/working/path/index.htm
    // http://www.domain.com:8010/current/working/path/
,   page           = location.href.split('?')[0]
    // http://www.domain.com:8010/current/working/path
,   page_key       = page.replace( /\/+$/, '' )
    // http://www.domain.com:8010/current/working
,   url_path       = page.split('/').slice(0,-1).join('/')
    // ["http:", "", "localhost", "example"]
,   url_components = page.split('/')
    // http://www.domain.com:8010/current/working
,   url_path       = page.split('/').slice(0,-1).join('/')
,   domain_parts   = url_components.slice( 0, 3 )
    // http://www.domain.com:8010
,   domain         = domain_parts.join('/')
    // httpswwwdomainkeycom8010
,   domain_key     = domain_parts.join('').replace( /[:.]/g, '' )
    // Recognized Tags that we Support
,   taglist = 'link img param embed script a'
,   tags = {
    'link' : 'href',
    'img' : 'src',
    'param' : 'value',
    'embed' : 'src',
    'script' : 'src',
    'a' : 'href'
};

// Call XDR for Page Profile
xdr({
    url     : SERVER_URL + '/cdnjoy-get-profile',
    type    : 'json',
    data    : { page : page },
    success : function(profile){updateCDN( profile, profile['status'] !== 200 )},
    fail    : function(profile){updateCDN( {}, true )}
});

// Update all CDN keys with CDN URL NOW (don't wait for profile)
DomReady.ready(function(){
    each( search(taglist), function(node) { 
        var local_url = attr( node, 'cdn' );

        // Leave if not a <tag cdn="">
        if (!local_url) return;

        var tag     = node.nodeName.toLowerCase()
        ,   tagattr = tags[tag] || 0;

        // Leave if not a Supported Tag
        if (!tagattr) return;

        // Create URL Key
        var url_key = fix_url_path_dots(make_url_key(local_url));

        // Fix Key to Fit CDN
        var cdn_url_key = '/' + url_key.split('/').slice(3).join('/');
        console.log('QUICK CDN: ' + CDN + DOMAIN_KEY + cdn_url_key);
        set_node_url( CDN + DOMAIN_KEY + cdn_url_key, node, tagattr );
    } );
});

console.log('SERVER_URL',SERVER_URL);
console.log('page',page);
console.log('page_key',page_key);
console.log('url_path',url_path);
console.log('url_components',url_components);
console.log('domain_key',domain_key);

// Function used to set URL
function set_node_url( dest, node, tagattr, nocorrect ) {
    console.log('URL: ' + dest);
    console.log('ORIGINAL URL: ' + attr( node, tagattr ));

    var check_dest = dest;

    if (dest.indexOf('?') !== -1 && !nocorrect) {
        var url_bit = dest.split('?');

        check_dest  = url_bit[0] +
                      escape('?' + url_bit[1]).replace( /%/g ,'' );
    }

    if (attr( node, tagattr ) !== check_dest)
        attr( node, tagattr, check_dest );
}


// Make a URL KEY
// '/this/is/a/url/key.jpg?alksjdfaa=alksjdf'
function make_url_key(url) {
    // Cleanup URL
    url = url.replace( /^\s*/, '' ).replace( /\s*$/, '' );

    console.log('MAKING URL:',url);

    // Absolute URL
    // /absolute/url/image.jpg
    if (!url.indexOf('/')) return domain + url;

    // Full URL
    // http://asfd.com/absolute/with/url.jpg
    if (!url.indexOf('http')) return url;

    // Relative URL
    // relative/path.jpg
    return url_path + '/' + url;
}

function fix_url_path_dots(url) {
    return url.replace( /\/[^\/]+\/\.\.\//g, '/' );
}

function updateCDN( profile, fail ) { DomReady.ready(function(){
    // Clear Failure Timeout
    clearTimeout(fail_timeout);

    // Leave if Already Running
    if (running) return;
        running = true;

    // Check if Admin Panel Is Requested
    if (location.href.indexOf('CDNJOY_STATUS') != -1) {
        // Admin JS
        var admin_js = create('script');
        admin_js.src = SERVER_URL + '/js/panel.js';
        head().appendChild(admin_js);

        // Admin CSS
        var admin_css = create('link');
        admin_css.href = SERVER_URL + '/css/panel.css';
        admin_css.setAttribute( 'rel',  'stylesheet' );
        admin_css.setAttribute( 'type', 'text/css' );
        head().appendChild(admin_css);
    }

    console.log('Running CDN UPDATE (DOM READY)');

    // Unpushed Assets (basically not in profile)
    var unpushed = []
    ,   pushed   = {};


    // Walk the DOM to find nodes which need updating.
    each( search(taglist), function(node) { 
        var local_url = attr( node, 'cdn' );

        // Leave if not a <tag cdn="">
        if (!local_url) return;

        var tag     = node.nodeName.toLowerCase()
        ,   tagattr = tags[tag] || 0;

        // Leave if not a Supported Tag
        if (!tagattr) return;

        // Update with local url if fail
        if (fail) return set_node_url( local_url, node, tagattr );

        // Find if it's on the CDN
        var url_key = fix_url_path_dots(make_url_key(local_url))
        ,   expire  = attr( node, 'expire' )
        ,   cdn_url = profile['assets'][url_key];

        console.log('URL_KEY: ' + url_key);
        console.log('CDN_URL: ' + profile['cdn'] + cdn_url);

        // If not on the CDN, then update unpushed array and set local_url.
        if (!cdn_url) {
            console.log('ADDING NEW IMAGE TO SEND: ' + local_url);
            console.log('PUSHING: ' + url_key);
            unpushed.push(url_key);
            return set_node_url( local_url, node, tagattr, true );
        }

        // It is on CDN!  
        set_node_url( profile['cdn'] + cdn_url, node, tagattr );

    } );

    // Send List of Unpushed Assets
    each( unpushed, function( new_url, index ) {
        // Prevent Pushing The Same Image
        if (pushed[new_url]) return;
            pushed[new_url] = 1;

        console.log('SENDING NEW URL: ' + new_url);

        setTimeout( function(){
            xdr({
                url     : SERVER_URL + '/cdnjoy-send',
                type    : 'json',
                data    : { url : new_url, cookie : cookies },
                success : function(response) {
                    console.log('FINISHED SENDING NEW URL: ' + new_url);
                    console.log(response);
                }
            });
        }, index * 100 );

    } );

/*
    load cdnjoy2.min.js static file
    xdr call for page profile while page is still rendering. 
    wait for domready and xdr page profile call then:
        update all known cdn assets
        update new asstes to local url.
        gather all new assets and make a post with cookie and urls

        Fall Back On
            cdn uptime != 200
            timeout (2 seconds)
            new asset
*/





});}

})();

