/* Source: topspin_purchase.js, as of Fri Jun 05 16:34:41 -0700 2009 */

TSConfig = {
    CDN_URL: "http://cdn.topspin.net/",
    APP_URL: "http://app.topspin.net/",
    SSL_APP_URL: "https://app.topspin.net/",
    BEACON_URL: "http://px.topspin.net/px/"
};


/* Source: /var/www/apps/topspin/releases/20090604203139/public/javascripts/TSPurchase.js, last modified at Fri Jun 05 16:31:25 -0700 2009 */

/* BEGIN TSPURCHASE */

function initFunc() {
    if (document.getElementById('topspin_style_addition') == null) {
        var styleTag = document.createElement('link');
        styleTag.media = 'screen';
        styleTag.rel = 'stylesheet';
        styleTag.type = 'text/css';
        styleTag.id = 'topspin_style_addition';
        //styleTag.href = TSUrlWriter.flashUrl('../stylesheets/widget.css'); // TODO: TSUrlWriter should get a "stylesheetURL" method
        styleTag.href = TSConfig.CDN_URL + "stylesheets/widget.css";
        var headNode = document.getElementsByTagName('head')[0];
        var headChild = headNode.firstChild;
        headNode.insertBefore(styleTag, headChild);
        var allAnchors = document.getElementsByTagName('a');

        var genericImageTag = document.createElement('img');
        genericImageTag.className = "invisible_image";
        var bodyNode = document.getElementsByTagName('body')[0];

        var anchorLength = allAnchors.length;

        for (var i=0;i<anchorLength;i++) {
            if (allAnchors[i].href.indexOf('https://app.topspin.net/purchase/') >= 0) {
                var urlArr = allAnchors[i].href.split('/');
                var artistID = urlArr[5];
                var campaignID = urlArr[6];
                allAnchors[i].href="javascript:void(0);"
                var clickStr = "TSPurchase.load({aId:"+artistID+",bId:22737,cId:"+campaignID+",persist:true});";
                allAnchors[i].onclick = clickStr;
            }
        }

        for(i=0;i<anchorLength;i++) {
            var clickStr = new String(allAnchors[i].onclick);
            if (clickStr.indexOf('TSPurchase.load') >= 0 ) {
                var data = eval(clickStr.substring(clickStr.indexOf('TSPurchase.load') + 'TSPurchase.load'.length, clickStr.length-1));
                var beaconImageTag = genericImageTag.cloneNode(true);
                //beaconImageTag.src = TSUrlWriter.beaconUrl('',{overrideSecurity:'insecure', ec:18, es:2, ref_url: window.location.href.toString(), campaign_id:data['cId']});
                beaconImageTag.src = TSConfig.BEACON_URL +
                                     "?ec=18&es=2&ref_url=" + encodeURIComponent(window.location.href.toString()) +
                                     "&campaign_id=" + data['cId'] + "&timestamp=" + new Date().getTime();
                bodyNode.appendChild(beaconImageTag);
            }
        }
    }
}

function is_linux() {
    var exp = /Linux/;
    if(exp.exec(navigator.platform)) {
        return true;
    }else{
        return false;
    }
}

if (window.addEventListener) {
    window.addEventListener('load', initFunc, false);
} else if (window.attachEvent) {
    window.attachEvent('onload', initFunc);
} else {}
/* END INIT */

/*	SWFObject v2.0 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var Z="undefined",P="object",B="Shockwave Flash",h="ShockwaveFlash.ShockwaveFlash",W="application/x-shockwave-flash",K="SWFObjectExprInst",G=window,g=document,N=navigator,f=[],H=[],Q=null,L=null,T=null,S=false,C=false;var a=function(){var l=typeof g.getElementById!=Z&&typeof g.getElementsByTagName!=Z&&typeof g.createElement!=Z&&typeof g.appendChild!=Z&&typeof g.replaceChild!=Z&&typeof g.removeChild!=Z&&typeof g.cloneNode!=Z,t=[0,0,0],n=null;if(typeof N.plugins!=Z&&typeof N.plugins[B]==P){n=N.plugins[B].description;if(n){n=n.replace(/^.*\s+(\S+\s+\S+$)/,"$1");t[0]=parseInt(n.replace(/^(.*)\..*$/,"$1"),10);t[1]=parseInt(n.replace(/^.*\.(.*)\s.*$/,"$1"),10);t[2]=/r/.test(n)?parseInt(n.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof G.ActiveXObject!=Z){var o=null,s=false;try{o=new ActiveXObject(h+".7")}catch(k){try{o=new ActiveXObject(h+".6");t=[6,0,21];o.AllowScriptAccess="always"}catch(k){if(t[0]==6){s=true}}if(!s){try{o=new ActiveXObject(h)}catch(k){}}}if(!s&&o){try{n=o.GetVariable("$version");if(n){n=n.split(" ")[1].split(",");t=[parseInt(n[0],10),parseInt(n[1],10),parseInt(n[2],10)]}}catch(k){}}}}var v=N.userAgent.toLowerCase(),j=N.platform.toLowerCase(),r=/webkit/.test(v)?parseFloat(v.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,i=false,q=j?/win/.test(j):/win/.test(v),m=j?/mac/.test(j):/mac/.test(v);/*@cc_on i=true;@if(@_win32)q=true;@elif(@_mac)m=true;@end@*/return{w3cdom:l,pv:t,webkit:r,ie:i,win:q,mac:m}}();var e=function(){if(!a.w3cdom){return }J(I);if(a.ie&&a.win){try{g.write("<script id=__ie_ondomload defer=true src=//:><\/script>");var i=c("__ie_ondomload");if(i){i.onreadystatechange=function(){if(this.readyState=="complete"){this.parentNode.removeChild(this);V()}}}}catch(j){}}if(a.webkit&&typeof g.readyState!=Z){Q=setInterval(function(){if(/loaded|complete/.test(g.readyState)){V()}},10)}if(typeof g.addEventListener!=Z){g.addEventListener("DOMContentLoaded",V,null)}M(V)}();function V(){if(S){return }if(a.ie&&a.win){var m=Y("span");try{var l=g.getElementsByTagName("body")[0].appendChild(m);l.parentNode.removeChild(l)}catch(n){return }}S=true;if(Q){clearInterval(Q);Q=null}var j=f.length;for(var k=0;k<j;k++){f[k]()}}function J(i){if(S){i()}else{f[f.length]=i}}function M(j){if(typeof G.addEventListener!=Z){G.addEventListener("load",j,false)}else{if(typeof g.addEventListener!=Z){g.addEventListener("load",j,false)}else{if(typeof G.attachEvent!=Z){G.attachEvent("onload",j)}else{if(typeof G.onload=="function"){var i=G.onload;G.onload=function(){i();j()}}else{G.onload=j}}}}}function I(){var l=H.length;for(var j=0;j<l;j++){var m=H[j].id;if(a.pv[0]>0){var k=c(m);if(k){H[j].width=k.getAttribute("width")?k.getAttribute("width"):"0";H[j].height=k.getAttribute("height")?k.getAttribute("height"):"0";if(O(H[j].swfVersion)){if(a.webkit&&a.webkit<312){U(k)}X(m,true)}else{if(H[j].expressInstall&&!C&&O("6.0.65")&&(a.win||a.mac)){D(H[j])}else{d(k)}}}}else{X(m,true)}}}function U(m){var k=m.getElementsByTagName(P)[0];if(k){var p=Y("embed"),r=k.attributes;if(r){var o=r.length;for(var n=0;n<o;n++){if(r[n].nodeName.toLowerCase()=="data"){p.setAttribute("src",r[n].nodeValue)}else{p.setAttribute(r[n].nodeName,r[n].nodeValue)}}}var q=k.childNodes;if(q){var s=q.length;for(var l=0;l<s;l++){if(q[l].nodeType==1&&q[l].nodeName.toLowerCase()=="param"){p.setAttribute(q[l].getAttribute("name"),q[l].getAttribute("value"))}}}m.parentNode.replaceChild(p,m)}}function F(i){if(a.ie&&a.win&&O("8.0.0")){G.attachEvent("onunload",function(){var k=c(i);if(k){for(var j in k){if(typeof k[j]=="function"){k[j]=function(){}}}k.parentNode.removeChild(k)}})}}function D(j){C=true;var o=c(j.id);if(o){if(j.altContentId){var l=c(j.altContentId);if(l){L=l;T=j.altContentId}}else{L=b(o)}if(!(/%$/.test(j.width))&&parseInt(j.width,10)<310){j.width="310"}if(!(/%$/.test(j.height))&&parseInt(j.height,10)<137){j.height="137"}g.title=g.title.slice(0,47)+" - Flash Player Installation";var n=a.ie&&a.win?"ActiveX":"PlugIn",k=g.title,m="MMredirectURL="+G.location+"&MMplayerType="+n+"&MMdoctitle="+k,p=j.id;if(a.ie&&a.win&&o.readyState!=4){var i=Y("div");p+="SWFObjectNew";i.setAttribute("id",p);o.parentNode.insertBefore(i,o);o.style.display="none";G.attachEvent("onload",function(){o.parentNode.removeChild(o)})}R({data:j.expressInstall,id:K,width:j.width,height:j.height},{flashvars:m},p)}}function d(j){if(a.ie&&a.win&&j.readyState!=4){var i=Y("div");j.parentNode.insertBefore(i,j);i.parentNode.replaceChild(b(j),i);j.style.display="none";G.attachEvent("onload",function(){j.parentNode.removeChild(j)})}else{j.parentNode.replaceChild(b(j),j)}}function b(n){var m=Y("div");if(a.win&&a.ie){m.innerHTML=n.innerHTML}else{var k=n.getElementsByTagName(P)[0];if(k){var o=k.childNodes;if(o){var j=o.length;for(var l=0;l<j;l++){if(!(o[l].nodeType==1&&o[l].nodeName.toLowerCase()=="param")&&!(o[l].nodeType==8)){m.appendChild(o[l].cloneNode(true))}}}}}return m}function R(AE,AC,q){var p,t=c(q);if(typeof AE.id==Z){AE.id=q}if(a.ie&&a.win){var AD="";for(var z in AE){if(AE[z]!=Object.prototype[z]){if(z=="data"){AC.movie=AE[z]}else{if(z.toLowerCase()=="styleclass"){AD+=' class="'+AE[z]+'"'}else{if(z!="classid"){AD+=" "+z+'="'+AE[z]+'"'}}}}}var AB="";for(var y in AC){if(AC[y]!=Object.prototype[y]){AB+='<param name="'+y+'" value="'+AC[y]+'" />'}}t.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AD+">"+AB+"</object>";F(AE.id);p=c(AE.id)}else{if(a.webkit&&a.webkit<312){var AA=Y("embed");AA.setAttribute("type",W);for(var x in AE){if(AE[x]!=Object.prototype[x]){if(x=="data"){AA.setAttribute("src",AE[x])}else{if(x.toLowerCase()=="styleclass"){AA.setAttribute("class",AE[x])}else{if(x!="classid"){AA.setAttribute(x,AE[x])}}}}}for(var w in AC){if(AC[w]!=Object.prototype[w]){if(w!="movie"){AA.setAttribute(w,AC[w])}}}t.parentNode.replaceChild(AA,t);p=AA}else{var s=Y(P);s.setAttribute("type",W);for(var v in AE){if(AE[v]!=Object.prototype[v]){if(v.toLowerCase()=="styleclass"){s.setAttribute("class",AE[v])}else{if(v!="classid"){s.setAttribute(v,AE[v])}}}}for(var u in AC){if(AC[u]!=Object.prototype[u]&&u!="movie"){E(s,u,AC[u])}}t.parentNode.replaceChild(s,t);p=s}}return p}function E(k,i,j){var l=Y("param");l.setAttribute("name",i);l.setAttribute("value",j);k.appendChild(l)}function c(i){return g.getElementById(i)}function Y(i){return g.createElement(i)}function O(k){var j=a.pv,i=k.split(".");i[0]=parseInt(i[0],10);i[1]=parseInt(i[1],10);i[2]=parseInt(i[2],10);return(j[0]>i[0]||(j[0]==i[0]&&j[1]>i[1])||(j[0]==i[0]&&j[1]==i[1]&&j[2]>=i[2]))?true:false}function A(m,j){if(a.ie&&a.mac){return }var l=g.getElementsByTagName("head")[0],k=Y("style");k.setAttribute("type","text/css");k.setAttribute("media","screen");if(!(a.ie&&a.win)&&typeof g.createTextNode!=Z){k.appendChild(g.createTextNode(m+" {"+j+"}"))}l.appendChild(k);if(a.ie&&a.win&&typeof g.styleSheets!=Z&&g.styleSheets.length>0){var i=g.styleSheets[g.styleSheets.length-1];if(typeof i.addRule==P){i.addRule(m,j)}}}function X(k,i){var j=i?"visible":"hidden";if(S){c(k).style.visibility=j}else{A("#"+k,"visibility:"+j)}}return{registerObject:function(l,i,k){if(!a.w3cdom||!l||!i){return }var j={};j.id=l;j.swfVersion=i;j.expressInstall=k?k:false;H[H.length]=j;X(l,false)},getObjectById:function(l){var i=null;if(a.w3cdom&&S){var j=c(l);if(j){var k=j.getElementsByTagName(P)[0];if(!k||(k&&typeof j.SetVariable!=Z)){i=j}else{if(typeof k.SetVariable!=Z){i=k}}}}return i},embedSWF:function(n,u,r,t,j,m,k,p,s){if(!a.w3cdom||!n||!u||!r||!t||!j){return }r+="";t+="";if(O(j)){X(u,false);var q=(typeof s==P)?s:{};q.data=n;q.width=r;q.height=t;var o=(typeof p==P)?p:{};if(typeof k==P){for(var l in k){if(k[l]!=Object.prototype[l]){if(typeof o.flashvars!=Z){o.flashvars+="&"+l+"="+k[l]}else{o.flashvars=l+"="+k[l]}}}}J(function(){R(q,o,u);if(q.id==u){X(u,true)}})}else{if(m&&!C&&O("6.0.65")&&(a.win||a.mac)){X(u,false);J(function(){var i={};i.id=i.altContentId=u;i.width=r;i.height=t;i.expressInstall=m;D(i)})}}},getFlashPlayerVersion:function(){return{major:a.pv[0],minor:a.pv[1],release:a.pv[2]}},hasFlashPlayerVersion:O,createSWF:function(k,j,i){if(a.w3cdom&&S){return R(k,j,i)}else{return undefined}},createCSS:function(j,i){if(a.w3cdom){A(j,i)}},addDomLoadEvent:J,addLoadEvent:M,getQueryParamValue:function(m){var l=g.location.search||g.location.hash;if(m==null){return l}if(l){var k=l.substring(1).split("&");for(var j=0;j<k.length;j++){if(k[j].substring(0,k[j].indexOf("="))==m){return k[j].substring((k[j].indexOf("=")+1))}}}return""},expressInstallCallback:function(){if(C&&L){var i=c(K);if(i){i.parentNode.replaceChild(L,i);if(T){X(T,true);if(a.ie&&a.win){L.style.display="block"}}L=null;T=null;C=false}}}}}();
/* END SWFOBJECT */

/* TSFLASH */
/**
 * Functions for embedding Flash elements on the page.
 * Flash movies currently in use must be recompiled to use the Flash methods.
 * Uses swfobject 2.0.
 */
TSFlash = {
    /**
     * Embeds a flash movie on the page. Requires a full path to the SWF, a container element, and an options object. At a minimum, you need to pass
     * option.width, option.height, option.instance (a unique ID for the movie). If option.facing is not supplied, this defaults to 'fan' facing,
     * using fan redirects & min version standards. The other valid option is currently 'artist'. Other optional params include option.redirectURL -- a
     * custom URL to redirect to that doesn't correspond to the stock fan- or artist- facing URL; option.redirectParams -- appended to the end of
     * the redirect URL.
     * If params are not supplied we will supply a high quality
     * @param    swfName   the full path to the swf file to be embedded.
     * @param    container the element that the Flash movie will be embedded in.
     * @param    option    an object with options. Minimum requirement is width, height, instanceName and loadParams.
     * @requires swfbject  swfobject 2.0 is required for embeds.
     * @namespace
     */
    embed: function(swfName, container, option) {
        (typeof(option.facing) == "undefined") ? option.facing = "fan" : option.facing = option.facing;
        if (typeof(option.params) == "undefined") {
		    option.params = {
		        quality:"high",
		        wmode: is_linux() ? "" : "transparent",
		        allowscriptaccess:"always",
		        menu:false
		    };
        }
        // redirect, etc have been pulled as swfobject 2.0 does not currently support it. Variables should still be passed in but it's pulled
        // for lightness of code.
        swfobject.embedSWF(swfName, container, option.width, option.height, TSFlash.minVersion[option.facing], null, option.variables, option.params);

    },
    /**
     * Allows flash to call out to resize its parent container.
     * @param    target        the id of element to be redimensioned
     * @param    height        the new desired height
     * @param    jsIdentifier  JS Identifier for widget making call
     * @namespace
     */
    redimensionMovie: function(target, height, jsIdentifier){
        // TODO: convert to a JSON model of CSS atribs & values & change that way
        var elem = document.getElementById(target);
        height = parseInt(height) + 23;
        elem.style.height = height + "px";
        elem.parentNode.style.height = height + "px";
    },
    /**
     * Checks to see if minimum version of flash player is present for the supplied facing. Assumes "fan" if no facing is supplied.
     * @param    facing        the facing that needs to be checked for min flash version.
     * @return   boolean       true if sufficient flash player version exists, false if not.
     * @namespace
     */
    checkMinVersion: function(facing) {
        if (typeof(facing) == 'undefined') {
            facing = 'fan';
        }
        var version = swfobject.getFlashPlayerVersion();
        var versionString = version.major+"."+version.minor+"."+version.release;
        var reqVersions = TSFlash.minVersion[facing].split('.');
        var compatibleVersion = false;
        if (parseInt(version.major) > parseInt(reqVersions[0])) {
            // MAJ > MAJ -- compat
            compatibleVersion = true;
        } else {
            // check the minor version
            if (parseInt(version.minor) > parseInt(reqVersions[1]) && parseInt(version.major) == parseInt(reqVersions[0])) {
                // MAJ == MAJ; MIN > MIN -- compat
                compatibleVersion = true;
            } else {
                // check the revision
                if (parseInt(version.release) >= parseInt(reqVersions[2]) && parseInt(version.minor) == parseInt(reqVersions[1])) {
                    // MAJ == MAJ, MIN == MIN, REV > REV -- compat
                    compatibleVersion = true;
                }
            }
        }
        return compatibleVersion;
    },
    /**
     * Minimum flash versions needed for different areas of the site.
     */
    minVersion: {
        artist:"9.0.115",
        fan:"9.0.115"
    },
    /**
     * Javascript functions used by Flash players to transact. This may be moved to Widgets eventually.
     */
    PlayerHooks: {
        /**
         * Transact is the primary player hook for flash and kicks off the purchase flow.
         * @param   JSONData JSON string containing transactionMode (share or download), event info, and APIDs to transact upon.
         */
        transact: function(JSONData) {
            var jsonObj = eval( "(" + JSONData + ")");
            (!jsonObj.jsIdentifier) ? ts_load_purch_flow(jsonObj.purchases, jsonObj.transactionMode) : ts_load_purch_flow(jsonObj.purchases, jsonObj.transactionMode, jsonObj.jsIdentifier);
        }
    }
};
/* END TSFLASH */
/* WIDGETS.JS */
/*
TODO: clean up catalog rendering code
TODO: make getElementsByClassName faster.
TODO: add throbbers to indicate loading
TODO: clean up error overlay
*/

/**
 * @fileoverview This file encompasses three main code areas: base widget functionality, associated libraries,
 * and individual widgets' associated generation and population functions and helpers thereof.
 * @author  Timon Karnezos (tkarnezos@topspinmedia.com)
 */


/**
 * Namespace that wraps all widget code.
 */
var TSWidget = {
    /**
     * The Klass namespace is a wholesale borrowing from the Prototype library. It marks a class as instantiable
     * and provides a common interface (the initialize method) for defining constructors.
     * It contains one method (static) that creates an object which can be used as the base for an instantiable
     * class.
     * All instantiable, custom classes in the widget code use Klass's method.
     */
    Klass: {},
    /**
     * The Util namespace encompasses static utility functions that are either dependencies of other classes, or
     * are commonly used by the individual or general widget code.
     * Util encompasses DOM manipulation, logging and debugging, URL parsing, String manipulation functions, and
     * the like. In general most of this functionality has been developed elsewhere and collected here.
     * It borrows heavily from the Prototype library and Peter Michaux's Fork library.
     */
    Util: {},
    /**
     * @class The TabSwitch class creates a tabbed pane view of like-class-named <div>s and <li>s.
     * This class powers the "catalog" and "metadata" widgets.
     * This class copied wholesale from the TabSwitch class in the app. (topspin_classes.js)
     */
    Widgets: {},
    /**
     * The Config namespace is used to declare configuration variables.
     * These variables can be modified by widget users.
     * Any variables that are modified by deploy scripts should be declared here.
     */
    Config: {
        DEBUG: (window.location.hostname.indexOf(".local") != -1), // Debug enabled in development; disabled otherwise
        CROSS_SITE: true,
        RESP_FORMAT_KEY: 'resp_format',
        JS_FUNC_KEY: 'js_func',
        CACHING: true,
        TIMEOUT: 30000 // 30 seconds * 1000 milliseconds/second
    }
};
TSWidget.Config.RESP_FORMAT = TSWidget.Config.CROSS_SITE ? 'js' : 'json';

//For links to the app:
//TSWidget.Config.APP_PATH = TSUrlWriter.applicationUrl({controller:'', overrideSecurity:'insecure'}).replace(/\/$/,'');
//TSWidget.Config.SSL_APP_PATH = TSUrlWriter.applicationUrl({controller:'', overrideSecurity:'secure'}).replace(/\/$/,'');
//TSWidget.Config.SSL_APP_CALL_PATH = TSUrlWriter.applicationUrl({controller:'', overrideSecurity:'secure'}).replace(/\/$/,'');

/**
 * This function adds the fields (and corresponding values) of the source to the destination.
 * It has many uses, like merging associative arrays, extending classes with new functionality, and overwriting
 * methods.
 * It is taken wholesale from the Prototype library (Object.extend).
 * @param {Object} destination The object to be extended.
 * @param {Object} source The object whose fields are to be copied.
 * @return {Object} The destination object after extension.
 */
TSWidget.Util.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
};

/* =====      TSWidget.Klass      ===== */
TSWidget.Util.extend(TSWidget.Klass, {
    create: function() {
        return function() {
              this.initialize.apply(this, arguments);
        };
      }
});

/* =====      TSWidget.Util      ===== */
TSWidget.Util.extend(TSWidget.Util, {
    /**
     * A function that does nothing, and returns nothing.
     */
    emptyFunction: function(){},
    /** THE FOLLOWING FUNCTIONS ARE JUST FIRST PASS, UNOPTIMIZED AND FOR DISCUSSION PURPOSES ONLY */
    getOverlayDimensions: function() {
        var ua = new String(navigator.userAgent);

        var windowWidth;
        var windowHeight;
        if (ua.indexOf('MSIE') > -1) {
            // IE
            windowWidth = parseInt(document.documentElement.clientWidth);
            windowHeight = parseInt(document.documentElement.clientHeight);
        } else {
            // Not IE
            windowWidth = parseInt(window.innerWidth);
            windowHeight = parseInt(window.innerHeight);
        }

        var bodyWidth = parseInt(document.body.offsetWidth);
        var bodyHeight = parseInt(document.body.offsetHeight);

        var overlayWidth = (windowWidth > bodyWidth) ? windowWidth : bodyWidth;
        var overlayHeight = (windowHeight > bodyHeight) ? windowHeight : bodyHeight;

        function testPage () {
        	var arr = document.getElementsByTagName("*");
        	var max = 0;

        	function getDimensions(element) {
        	    var display = element.style.display;
        	    if (display != 'none' && display != null) { // Safari bug
        	        return {width: element.offsetWidth, height: element.offsetHeight};
                }
                // All *Width and *Height properties give 0 on elements with display none,
        	    // so enable the element temporarily
        	    var els = element.style;
        	    var originalVisibility = els.visibility;
        	    var originalPosition = els.position;
        	    var originalDisplay = els.display;
        	    els.visibility = 'hidden';
        	    els.position = 'absolute';
        	    els.display = 'block';
        	    var originalWidth = element.clientWidth;
        	    var originalHeight = element.clientHeight;
        	    els.display = originalDisplay;
        	    els.position = originalPosition;
        	    els.visibility = originalVisibility;
        	    return {width: originalWidth, height: originalHeight};
        	}

        	for (var i=0 ; i< arr.length ; i++) {
        		var el = arr[i];
        		var h = getDimensions(el).height;
        		if (h > max) { max = h; }
        	}
            return max;
        }

        if (bodyHeight == 0 || bodyHeight == windowHeight) {
            overlayHeight = testPage();
        }

        var overlayDimensions = {
            width:overlayWidth,
            height:overlayHeight
        };
        return overlayDimensions;
    },
    hideFlash:function() {
        var flashNodes = document.getElementsByTagName('object');
        for (var i=0;i<flashNodes.length;i++) {
            flashNodes[i].parentNode.style.textIndent = "-9999px";
            if (flashNodes[i].style.visibility == "visible") {
                flashNodes[i].style.visibility = "hidden";
            }
        }
    },
    showFlash:function() {
        var flashNodes = document.getElementsByTagName('object');
        for (var i=0;i<flashNodes.length;i++) {
            flashNodes[i].parentNode.style.textIndent = "0px";
            if (flashNodes[i].style.visibility == "hidden") {
                flashNodes[i].style.visibility = "visible";
            }
        }
    },
    genOverlay: function() {
        var testNode = document.getElementById('TSOverlayBGDiv');
        if (testNode != null) {
            testNode.parentNode.removeChild(testNode);
        }
        var overlay = document.createElement('div');
        TSWidget.Util.hideFlash();
        var overlayDims = TSWidget.Util.getOverlayDimensions();

        var dBody = document.getElementsByTagName('body')[0];
        dBody.insertBefore(overlay, dBody.firstChild);
        var ua = new String(navigator.userAgent);
        //if (ua.indexOf('MSIE') > -1) {
           overlay.style.height = overlayDims.height + "px"; // only need to set in IE
        //}
        overlay.id = "TSOverlayBGDiv";
        overlay.innerHTML = "&nbsp;";
    },
    removeOverlay:function() {
        var overlay = document.getElementById('TSOverlayBGDiv');
        var dBody = document.getElementsByTagName('body')[0];
        dBody.removeChild(overlay);
    },
    errorMessage: function(message, actionLink, jsIdentifier) {
        var pFlow = document.getElementById('ts_ol_pflow');
        if (typeof(pFlow) != 'undefined') {
            var newDiv = document.createElement('div');
            newDiv.innerHTML = "blah";
            pFlow.style.display = "none";
        }
        var ua = new String(navigator.userAgent);
        var errorPane = document.createElement('div');
        errorPane.id = "tsUsrErrMsgLbox";

        //errorPane.style.background = "url('"+TSUrlWriter.imageUrl("widgetSupport/errorPane/errorIcon.jpg", {overrideSecurity:'insecure'})+"') no-repeat 25px 30px #000000";
        errorPane.style.background = "url('"+ TSConfig.CDN_URL + "images/widgetSupport/errorPane/errorIcon.jpg') no-repeat 25px 30px #000000";

        if (ua.indexOf("MSIE") > -1) {
         errorPane.style.top = 120 + parseInt(document.documentElement.scrollTop) + "px";
         errorPane.style.left = parseInt(document.documentElement.clientWidth)/2 - 347 + "px";
        } else {
         //errorPane.style.top = parseInt(window.pageYOffset) + 120 + "px";
         errorPane.style.left = parseInt(window.innerWidth)/2 - 347 + "px";
        }

        var errorHeadline = document.createElement('h3');
        var errorMessage = document.createElement('div');
        var errorAction = document.createElement('a');
        var errorClose = document.createElement('a');

        errorPane.appendChild(errorHeadline);
        errorPane.appendChild(errorMessage);
        errorPane.appendChild(errorAction);
        errorPane.appendChild(errorClose);

        var dBody = document.getElementsByTagName('body')[0];
        dBody.insertBefore(errorPane, dBody.firstChild);
        setTimeout("TSWidget.Util.paneScroll('tsUsrErrMsgLbox', 120)",2);

        errorHeadline.innerHTML = message.headline;
        errorMessage.innerHTML = message.text;
        errorAction.innerHTML = "&raquo; " + actionLink.text;
        errorAction.href = actionLink.href;
        errorAction.onclick = actionLink.onclick;
        errorAction.setAttribute("onclick", actionLink.onclick);
        errorAction.className = "tsErrActionLink";

        errorClose.innerHTML = "Cancel and Go Back";
        errorClose.href = "javascript:void(0);";
        errorClose.onclick = "javascript:TSWidget.Util.closeError('"+errorPane.id+"')";
        errorClose.setAttribute("onclick","javascript:TSWidget.Util.closeError('"+errorPane.id+"')");

        errorPane.innerHTML = errorPane.innerHTML; // IE
        TSPurchFlowResizeHandler = function () {
            TSWidget.Util.centerPane('tsUsrErrMsgLbox', 350);
        };
        TSPurchFlowScrollHandler = function () {
            TSWidget.Util.paneScroll('tsUsrErrMsgLbox', 120);
        };
        TSWidget.Util.DOM.addEventHandler(window, "resize", TSPurchFlowResizeHandler);
        TSWidget.Util.DOM.addEventHandler(window, "scroll", TSPurchFlowScrollHandler);
        return;
    },
    redimensionOverlay: function() {
        var overlayDims = TSWidget.Util.getOverlayDimensions();
        var overlay = document.getElementById('TSOverlayBGDiv');
        overlay.style.height = overlayDims.height + "px"; // only need to set in IE
    },
    centerPane : function(idE, offset) {
        var ePane = document.getElementById(idE);
        var val = (parseInt(document.body.offsetWidth))/2 - offset;
        var val = val + "px";
        ePane.style.left = val;
        TSWidget.Util.redimensionOverlay();
    },
    closeError : function(paneId) {
       var ePane = document.getElementById(paneId);
       ePane.parentNode.removeChild(ePane);
       TSWidget.Util.removeOverlay();
       TSWidget.Util.showFlash();
      // document.onscroll = "";
       TSWidget.Util.DOM.removeEventHandler(window, "resize", TSPurchFlowResizeHandler);
       TSPurchFlowResizeHandler = null;
       TSWidget.Util.DOM.removeEventHandler(window, "scroll", TSPurchFlowScrollHandler);
       //TSWidget.Util.DOM.removeEventHandler(document.documentElement, "scroll", TSPurchFlowScrollHandler);
       TSPurchFlowScrollHandler = null;
    },
    paneScroll: function(elementId, offset) {
      var ePane = document.getElementById(elementId);
      var ua = new String(navigator.userAgent);
      if (ua.indexOf("MSIE") >= 0) {
       var rawVal = parseInt(document.documentElement.scrollTop);
      } else {
       var rawVal = parseInt(window.pageYOffset);
      }
      var val = offset + rawVal + "px";
      ePane.style.top = val;
    },
    /**
     * The DOM namespace covers basic DOM manipulation functions such as insertions and search functions.
     */
    DOM: {
        /**
         * Adds an event handler function as an event listener to a DOM element
         *
         * @param element  DOM element to which the event handler should be added
         * @param eventType  Event type excluding "on" prefix
         * @param handler  Event handler function
         */
        addEventHandler: function (element, eventType, handler) {
            if (typeof element.addEventListener != "undefined") {
                element.addEventListener(eventType, handler, false); // DOM2
            } else if (typeof element.attachEvent != "undefined") {
                element.attachEvent("on"+eventType, handler); // IE
            }
        },
        /**
         * Removes an event handler function from a DOM element
         *
         * @param element  DOM element from which the event handler should be removed
         * @param eventType  Event type excluding "on" prefix
         * @param handler  Event handler function
         */
        removeEventHandler: function (element, eventType, handler) {
            if (typeof element.removeEventListener != "undefined") {
                element.removeEventListener(eventType, handler, false); // DOM2
            } else if (typeof element.detachEvent != "undefined") {
                element.detachEvent("on"+eventType, handler); // IE
            }
        }
    }
});
var TSDOM = TSWidget.Util.DOM;
/* END WIDGETS.JS */
/* WIDGET POPULATORS */
/**
 * Widgets is the namespace encapsulating all individual-widget-specific methods. In effect, the unique portion of each widget is defined here.
 * Each widget is fundamentally a hash of four functions and a settings hash.
 * The first function, under the key 'generateSkeleton', creates the HTML skeleton of a widget, without the information.
 * It should return the DOM object that is the container created for the widget.
 * The second function, under the key 'populate', populates the skeleton with the payload from the server. There is no need to perform any AJAX calls, as they are handled by the widget infrastructure. (See generateCallArgs.)
 * The third function, under they key 'generateCallArgs', returns a hash containing the arguments needed to make an
 * AJAX call to the server: callUrl (the url to query), callParams (a hash of queryString parameters in kvp format), and callMethod (the HTTP method to be used.)
 * NOTE: currently the only HTTP method supported by the widgets is GET.
 * The final function, under they key 'log', is a function that indicates how any logging should be dealt with.
 * The settings hash is a centralized location to enumerate the default values for user-customizable properties of the widgets.
 * NOTE: the first three functions are called in the scope of the original Widget instantiation. So this = widget instance.
 */

TSWidget.Util.extend(TSWidget.Widgets, {
    FlashHooks:{
		//purchaseFlowPath: "pf3/TSPurchaseFlow.swf",
		purchaseFlowPath: "flash/pf3/TSPurchaseFlow.swf",

        /**
         * @deprecated  Use TSWidget.Widgets.Helpers.closeLightBox instead -- needs to be changed in flash
         */
        downloadFormCancel: function (jsIdentifier){
            TSWidget.Widgets.Helpers.closeLightBox(jsIdentifier);
        },
        paypalPurchase: function (paypalURL, jsIdentifier){
            var WindowObjectReference = window.open(paypalURL,'targetURL');
            if (!WindowObjectReference) {
                message = {
                    headline: "Oops!",
                    text: "It appears you've got pop-up blocking enabled.<br/><br/>"
                };
                message.text += "You may want to disable it, or if you wish to complete this purchase via PayPal, click the link below:";
                actionLink = {
                    href:"javascript:void(0);",
                    text:"Go to PayPal in a New Window",
                    onclick:"javascript:window.open('"+paypalURL+"');TSWidget.Util.closeError('ts_usrErrMsg_lbox');"
                };
                TSWidget.Util.errorMessage(message, actionLink, jsIdentifier);
            }
        },
        openURLFromFlash: function(targetURL, jsIdentifier) {
            var WindowObjectReference = window.open(targetURL,'targetURL');
            if (!WindowObjectReference) {
                message = {
                    headline: "Oops!",
                    text: "It appears you've got pop-up blocking enabled.<br/><br/>"
                };
                message.text += "You may want to disable it. If you wish to continue to your original destination, click the link below:";
                actionLink = {
                    href:"javascript:void(0);",
                    text:"Open Link in a New Window",
                    onclick:"javascript:window.open('"+targetURL+"');TSWidget.Util.closeError('ts_usrErrMsg_lbox');"
                };
                TSWidget.Util.errorMessage(message, actionLink, jsIdentifier);
            }
        },
        refreshPage: function (jsIdentifier) {
            window.location = window.location;
        },
        loadPurchaseFlow: function (productList, mode, widgetId, width, campaignId, persistVal, artistIdVal) {
            var lightBox = TSWidget.Widgets.Helpers.renderLightBox(widgetId);
            var lightBoxWrapper = lightBox.parentNode;
            persistVal = (typeof(persistVal) == 'undefined' || persistVal == null) ? persistVal = true : persistVal = persistVal;
            var key = "";
            // TODO: Need to determine where to get the subject from. Global data object is not the right place.
            //var emailSubject = (typeof(data.subject) != 'undefined') ? data.subject : "";
            var emailSubject = "";

            campaignId = campaignId || "";
            mode = mode || "download";
            width = width || 435;
            var height = 529;
            //var flashURL = TSUrlWriter.flashUrl(TSWidget.Widgets.FlashHooks.purchaseFlowPath, {overrideSecurity:'insecure'});
            var flashURL = TSConfig.CDN_URL + TSWidget.Widgets.FlashHooks.purchaseFlowPath;

            if (mode == "share") {
                lightBoxWrapper.className += " share";
                width = 400;
                height = 334;
                //flashURL = TSUrlWriter.flashUrl("share/TSShareFlow.swf", {overrideSecurity:'secure'});
                flashURL = TSConfig.SSL_APP_URL + "flash/share/TSShareFlow.swf";
            }
            //var paypalReturnURLBase = TSWidget.Config.SSL_APP_PATH + "/purchase";
            var paypalReturnURLBase = TSConfig.SSL_APP_URL + "purchase";
            var option = {
                facing: 'fan',
                variables: {
                    persist: persistVal,
                    baseUrl: TSConfig.SSL_APP_URL.replace(/\/$/,''),
                    cdnUrl: TSConfig.CDN_URL.replace(/\/$/,''),
                    ppUrl: paypalReturnURLBase,
                    shareSubj: emailSubject,
                    divW: width,
                    artistId: artistIdVal,
                    pList: productList,
                    key: key,
                    campaignId: campaignId,
                    jsIdentifier: widgetId,
                    movieId: lightBox.id
                },
                params: {
                    quality: "high",
                    allowscriptaccess: "always",
                    menu: "false",
                    bgcolor: "#000000",
                    wmode: is_linux() ? "" : "transparent"
                },
                width: width,
                height: height,
                instance: lightBox.id
            };

            TSFlash.embed(flashURL, lightBox.id, option);

            function adblockCheck() {
                var abCheck = lightBoxWrapper.getElementsByTagName('a');
                var hideFlag = false;
                for (var i=0;i<abCheck.length;i++){
                    if (abCheck[i].className.indexOf('abp-obj') >= 0) {
                        hideFlag = true;
                    }
                }
                if (hideFlag == true) {
                    for (var i=0;i<abCheck.length;i++) {
                        if (hideFlag == true && abCheck[i].className.indexOf('abp-obj') == -1) {
                            abCheck[i].style.left = "0px";
                            abCheck[i].style.cssFloat = "left";
                            abCheck[i].style.textAlign = "left";
                            abCheck[i].parentNode.style.textAlign = "left";
                        }
                    }
                }
            };
            setTimeout(adblockCheck, 100);
        }
    },
    Helpers: {
        /**
         * Renders empty modal light box
         *
         * @param id  The identifier used to create the light box media container
         * @return The light box media container element
         */
        renderLightBox: function (id) {
            TSWidget.Util.genOverlay();

            var wrapper = document.getElementById('ts_ol_pflow');
            if (wrapper != null) {
                wrapper.parentNode.removeChild(wrapper);
            }
            wrapper = document.createElement('div');
            wrapper.id = "ts_ol_pflow";
            wrapper.className = "ts_download_form";

            var tBar = document.createElement('div');
            tBar.id = "ts_pflow_control";
            var tBarLink = document.createElement('a');
            tBarLink.href = "javascript:void(0);";
            //var closeURL = TSUrlWriter.imageUrl('widgetSupport/purchFlow/close.gif');
            var closeURL = TSConfig.CDN_URL + "images/widgetSupport/purchFlow/close.gif";
            tBarLink.innerHTML = "<img src='"+closeURL+"' border='0' alt='Close'/>";
            TSWidget.Util.DOM.addEventHandler(tBarLink, "click", TSWidget.Widgets.Helpers.closeLightBox);
            tBar.appendChild(tBarLink);

            var contentBox = document.createElement('span');
            contentBox.id = "pf_alt_" + id;
            contentBox.className = "TSFlash_alt";
            contentBox.style.display = "block";
            contentBox.style.position = "absolute";
            contentBox.style.fontSize = "12px";
            contentBox.style.fontFamily = "Verdana, Arial, Helvetica";
            contentBox.style.backgroundColor = "transparent";
            contentBox.style.width = "100%";
            contentBox.style.border = "none";
            contentBox.style.color = "#ffffff";
            contentBox.innerHTML = "You do not have the required minimum version of<br/>Adobe Flash&reg;.<br/><br/> <a href='http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash' target='_blank' style='color:#01cdff;font-weight:bold;'>Click here to upgrade</a>.<br/><br/><a href='#' style='color:#01cdff' onclick='javascript:TSWidget.Widgets.Helpers.closeLightBox();'>Cancel</a>";

            wrapper.appendChild(tBar);
            wrapper.appendChild(contentBox);

            var ua = new String(navigator.userAgent);
            if (ua.indexOf("MSIE") >= 0) {
                wrapper.style.top = 80 + parseInt(document.documentElement.scrollTop) + "px";
            } else {
                wrapper.style.top = 80 + parseInt(window.pageYOffset) + "px";
            }
            wrapper.style.left = (document.body.clientWidth)/2 - 212 + "px";

            var bodyNode = document.getElementsByTagName('body')[0];
            bodyNode.insertBefore(wrapper, bodyNode.firstChild.nextSibling);

            // Declare event handlers within global scope so they can be referenced when removing
            TSLightBoxResizeHandler = function () {
                TSWidget.Util.centerPane("ts_ol_pflow", 212);
            };
            TSWidget.Util.DOM.addEventHandler(window, "resize", TSLightBoxResizeHandler);

            return contentBox;
        },
        /**
         * Closes a modal light box
         *
         * @param id  The identifier used to create the light box media container
         */
        closeLightBox: function (id) {
            /// THIS TOOK JSIDENTIFIER... NEEDS TO ACTUALLY TAKE ID NOW
            var pf = document.getElementById('ts_ol_pflow');
            //pf.innerHTML = "";

            TSWidget.Util.DOM.removeEventHandler(window, "resize", TSLightBoxResizeHandler);
            TSLightBoxResizeHandler = null;

            TSWidget.Util.removeOverlay();
            TSWidget.Util.showFlash();
            TSWidget.Widgets.Helpers.getLoginStatus();
            pf.style.display = "none";
            //pf.parentNode.removeChild(pf);
        },
        /**
         * Compatibility function - does nothing. prevents error from being thrown.
         *
         */
        getLoginStatus: function(){}
    }
});

/* END WIDGET POPULATORS */
/* TSPURCHASE */
var TSPurchase = (function () {
    return {
        load: function(params) {
           // bId = bundle id; cId = campaign ID; aId = artist ID; persist = persist login
           var options = params;
           TSWidget.Widgets.FlashHooks.loadPurchaseFlow(options.bId, null, 1, 435, options.cId, options.persist, options.aId);
        }
    };
})();
/* END TSPURCHASE */

