/*
 * SongHi Common javascript routines
 * @uses jQuery
 * @uses jQuery.fancybox
 * */

var _gaq = _gaq || [];

// debug
var debug = debug || false;
var debugLog = debugLog || [];
function log() {
	if ( !debug ) return;
	argsArray = [];
	for ( var i=0; i<arguments.length;i++ ) {
		argsArray.push(arguments[i]);
	}
	debugLog.push(argsArray);
	if ( window.console && console.log ) {
		if ( debugLog.length > 0 ) {
			for ( i=0; i<debugLog.length; i++ ) {
				if ( console.log.apply ) {
					console.log.apply(console, debugLog[i].slice(0));
				} else {
					console.log(debugLog[i].slice(0));
				}
			}
			debugLog=[];
		}
	}
}

// Enable or disable the warning when user is trying to leave with unsaved changes
function setBrowserLeaveWarning(isEnabled) {
	if ( isEnabled ) {
		window.onbeforeunload = function (evt) {
			var message = 'You will lose all unsaved changes!';
			if (typeof evt == 'undefined') {
				evt = window.event;
			}
			if (evt) {
				evt.returnValue = message;
			}
			return message;
		};
	} else {
		window.onbeforeunload = null;
	}
}

// Do a raw call to ga.js
function gaPush() {
	log('_gaq.push:', arguments);
	_gaq.push.apply(_gaq, arguments);
}

// Open a payment window over the flash
function openPaymentWindow(playerId, sessionId) {
	log('openPaymentWindow:', playerId, sessionId);
	$.fancybox.showActivity();
	$.ajax({
		type: "POST",
		url: "/core/resources/secured/payment/source/" + playerId,
		async: true,
		data: "",
		dataType: "xml",
		contentType: "text/plain",
		beforeSend: function(xhr){
			xhr.setRequestHeader("Authorization", sessionId);
		},
		success: function(msg,status,xhr){
			var url = $(msg).find("metadata").text();
			if ( url ) { 
				$.fancybox({
					type: "iframe",
					href: url,
					autoDimensions: false,
					autoScale: false,
					hideOnOverlayClick: false,
					hideOnContentClick: false,
					enableEscapeButton: false,
					showNavArrows: false,
					width: 768,
					height: 640
				});
			} else {
				log('Successful query, but did not get the url from response:', msg);
			}
		},
		error: function(xhr,status,error){
			log('Query failed:', xhr, status, error);
		},
		complete: function(xhr,status){
			$.fancybox.hideActivity();
		}
	});
}

// convert object to xml for webservice requests
function convertToXML(obj,isNotRoot){
	var str = isNotRoot == undefined ? "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" : "";
	$.each(obj, function(k,v){
		if ( $.isArray(v) ) {
			var arrv = "";
			$.each(v, function(vk,vv){
				arrv += convertToXML({k:vv},true);
			});
			v = arrv;
		} else if ( $.isPlainObject(v) ) {
			v = convertToXML(v, true);
		}
		str += "<"+k+">"+v+"</"+k+">";
	});
	return str;
}

function HashWatcher() {
	var obj = {
		intervalId: 0,
		lastHash: '',
		onHashChange: function() {
			if ( window.location.hash.substr(1,1) == '!' ) {
				var path = window.location.hash.substr(2).split('?');
				/*
				var search = {};
				if ( window.location.search.length > 1 ) {
					$.each(window.location.search.substr(1).split('&'),function(k,v){
						var s=v.split("=");
						if ( s[0] ) {
							search[s[0]] = s[1] != undefined ? s[1] : '';					
						}
					});
				}*/
				// remove duplicates
				var searchStr = $.param($.unParam(path[1]));
				var uri = $.buildUri({
					pathname: path[0],
					search: searchStr.length > 0 ? '?'+searchStr : '',
					hash: ''
				});
				window.location.href = uri;
			}
		},
		construct: function() {
		},
		setHash: function(str) {
			var t = window.title;
			window.location.hash = str;
			this.lastHash = window.location.hash;
			window.title = t;
		},
		enable: function() {
			this.intervalId = setInterval((function(self){
				return function(){
					if ( window.location.hash != self.lastHash ) {
						self.onHashChange();
					}
					self.lastHash = window.location.hash;
				};
			})(this),1000);
			this.onHashChange();
		},
		disable: function() {
			clearInterval(this.intervalId);
		}
	};
	obj.construct();
	return obj;
}


(function($){
	$.ajaxSetup({
		type: "GET",
		dataType: "json"
	});

	$.fn.ajaxWait = function(loaderElement){
		if ( loaderElement == undefined ) {
			loaderElement = this;
		}
		if ( loaderElement !== false ) {
			this.data("replaceContent", true);
			this.data("loaderElement", loaderElement);
			this.data("loaderContent", $(loaderElement).html());
			var tag = '<div class="loader ajaxWaitLoader" style="position:absolute; display:none;"></div>';
			$(loaderElement).append(innerShiv(tag,false));
			var $el = $(loaderElement).find(".loader");
			$el.css({
				top:$(loaderElement).position().top + Number($(loaderElement).css("padding-top").replace(/[^0-9]/g,'')) + Math.round(($(loaderElement).height()-$el.height())/2),
				left:$(loaderElement).position().left + Number($(loaderElement).css("padding-left").replace(/[^0-9]/g,'')) + Math.round(($(loaderElement).width()-$el.width())/2)
			});
			$el.fadeIn(100);
		}
		this.data("waiting", true);
		return this;
	};

	$.fn.ajaxIsWaiting = function(){
		return this.data("waiting") ? true : false;
	};

	$.fn.ajaxUnWait = function(){
		if ( this.data("replaceContent") ) {
			var loaderElement = this.data("loaderElement");
			//$(loaderElement).html(innerShiv(this.data("loaderContent"),false));
			$(".ajaxWaitLoader").fadeOut(100);
			this.data("replaceContent", null);
			this.data("loaderContent", null);
			this.data("loaderElement", null);
		}
		this.data("waiting", false);
		return this;
	};
})(jQuery);

(function($){
	// ajaxLoader links replace certain content when clicked
	// other trigger events can be used as well
	$.fn.ajaxLoader = function(argOptions){
		return this.each(function(){
			var opts = {
			    cache: true,
				context: this,
				success: null,
				link: this,
				target: $(this).attr("ajax:target") ? $(this).attr("ajax:target") : $(this),
				data: {},
				url: $(this).attr("href"),
				event: "click",
				noReplace: false
			};

			$.extend(opts, argOptions);
			$.extend(opts.data, $.unParam(opts.url.split('?')[1]));
			$.extend(opts.data, $.unParam($(this).attr("ajax:data")));
			opts.url = opts.url.split('?')[0];

			$(opts.target).data("ajaxLoaderCache",{});
			var targets = $(this).data("ajaxLoaderTargets") || {};
			targets[opts.target] = opts;
			$(this).data("ajaxLoaderTargets", targets);
			$(this).bind(opts.event, function(){
				var targets = $(this).data("ajaxLoaderTargets") || [];
				$.each(targets,function(target,opts){
					if ( !$(target).ajaxIsWaiting() ) {
						$(target).ajaxWait();
						if ( $.isFunction(opts.load) ) {
							var d = opts.load.apply(opts.context, [opts.data, opts]);
							if ( d != undefined ) opts.data = d;
						}
						var ajaxOpts = {
							context: opts,
							url: opts.url,
							data: opts.data,
							success: function(msg,status,xhr){
								if ( msg.data != undefined && !this.noReplace ) {
									$(this.target).ajaxUnWait();
									//$(this.target).children().remove();
									$(this.target).html(innerShiv('<p class="ct">&nbsp;</p>'+msg.data.html,false));
									$(this.target).find("article").focus();
									if ( window.hashWatcher ) {
										hashWatcher.setHash('!'+$.urlToPath(this.url));
									}
								}
								if ( debug && msg.debug ) {
									$.each(msg.debug, function(i,v){
										log.apply(this, v);
									});
								}
								if ( $.isFunction(this.success) ) {
									this.success.apply(this.context,[msg,status,xhr]);
								}
							},
							complete: function(){
								$(this.target).ajaxUnWait();
							}
						};
						if ( opts.cache ) {
							$.ajaxWithCache(ajaxOpts);
						} else {
							$.ajax(ajaxOpts);
						}
					}
				});
				return false;
			});
		});
	};

	var ajaxCache = {};
	$.ajaxWithCache = function(opts) {
		// create an ajax options object for the scope of this function
		var ajaxOpts = $.extend(true, {}, opts);
		ajaxOpts.success = function(msg,status,xhr){
			var cacheKey = (this.url+$.param(this.data)).replace(/[^a-zA-Z0-9]*/g,'');
			ajaxCache[cacheKey] = msg; 
			if ( $.isFunction(this.success) ) {
				this.success.apply(this.context,[msg,status,xhr]);
			}
		};
		// wrap callbacks so that the context is correct
		ajaxOpts.complete = function(){ if ( $.isFunction(this.complete) ) { this.complete.apply(this.context,arguments); } };
		ajaxOpts.error = function(){ if ( $.isFunction(this.error) ) { this.error.apply(this.context,arguments); } };
		ajaxOpts.dataFilter = function(){ if ( $.isFunction(this.dataFilter) ) { return this.dataFilter.apply(this.context,arguments); } else { return arguments[0]; } };
		ajaxOpts.beforeSend = function(){ if ( $.isFunction(this.beforeSend) ) { return this.beforeSend.apply(this.context,arguments); } };
		ajaxOpts.context = opts;
		
		var cacheKey = (opts.url+$.param(opts.data)).replace(/[^a-zA-Z0-9]*/g,'');
		if ( !ajaxCache[cacheKey] ) {
			$.ajax(ajaxOpts);
		} else {
			// return before doing heavy work
			setTimeout(function(){
				log('> Fetched '+$.param(ajaxCache[cacheKey].data).length+' bytes of html from '+opts.url+'?'+$.param(opts.data)+' [ajaxLoaderCache]:');
				if ( $.isFunction(opts.success) ) { 
					opts.success.apply(opts.context,[ajaxCache[cacheKey]]);
				}
				if ( $.isFunction(opts.complete) ) {
					opts.complete.apply(opts.context, []);
				}
			},1);
		}
	};

	// the complement of $.param
	// TODO: does not handle multilevel objects yet
	$.unParam = function(str){
		if ( str == undefined ) return {};
		var obj = {};
		if ( str && str.length > 0 ) {
			if ( str.substr(0,1) == '?' ) str = str.substr(1);
			$.each(str.split('&'),function(k,v){
				var s=v.split("=");
				if ( s[0] ) {
					obj[s[0]] = s[1];					
				}
			});
		}
		return obj;
	};

	// strip protocol and host from url for ajax hashes
	$.urlToPath = function(url) {
		var href = window.location.protocol + '//' + window.location.host;
		url = url.replace(href, "");
		url = url.replace(/^http(s)*:\/\/[^\/]+/, "");
		return url;
	};

	// build uri from parts like in window.location
	$.buildUri = function(argOpts) {
		var opts = {
			protocol: window.location.protocol,
			hostname: window.location.hostname,
			port: window.location.port,
			pathname: window.location.pathname,
			search: window.location.search,
			hash: window.location.hash
		};
		$.extend(opts,argOpts);
		var uri = opts.protocol;
		uri += '//';
		uri += opts.hostname;
		if ( opts.port != '' && opts.port != 80 ) uri += ':'+opts.port;
		uri += opts.pathname;
		if ( opts.search.length > 0 ) uri += opts.search;
		if ( opts.hash.length > 0 ) uri += opts.hash;
		return uri;
	};
	
	// ajaxScroller appends pages of content when the scroll of page reaches the bottom
	$.fn.ajaxScroller = function(argOptions){
		return this.each(function(i,el){
			
			$(el).find(".pagination").hide();
			
			var opts = {
				cache: true,
				initPage: 1,
				pageSize: 16,
				pageCount: $(el).attr("ajax:pagecount") ? $(el).attr("ajax:pagecount") : Infinity,
				listElement: $(el).attr("ajax:listelement") ? $(el).attr("ajax:listelement") : $(el),
				data: $(el).attr("ajax:data") ? $.param($(el).attr("ajax:data")) : false,
				url: $(el).attr("href") ? $(el).attr("href") : $(el).attr("ajax:href"),
				boundaryPixels: 5
			};

			$.extend(opts, argOptions);
			opts.page = opts.initPage;
			if ( opts.pageCount < 2 ) {
				opts.reachedLastPage = true;
			}
			$(el).addClass("ajaxScroller");
			$(el).find(opts.listElement).addClass("ajaxScrollerList").append(innerShiv('<div class="clear"></div>',false));
			$(el).data("ajaxScrollerOptions",opts);
			$(el).scroll(function(){
				opts = $(el).data("ajaxScrollerOptions");
				var list = $(el).children(".ajaxScrollerList");
				if ( list.position().top + list.innerHeight()  < $(el).innerHeight() + opts.boundaryPixels ) {
					if ( !$(el).ajaxIsWaiting() && !opts.reachedLastPage ) {
						$(el).ajaxWait($('<div class="loader"></div>').appendTo($(el).find(opts.listElement)));
						var ajaxOpts = {
							context: this,
							url: opts.url,
							data: $.extend(opts.data, {
								_ps: opts.pageSize,
								_p: (opts.page+1)
							}),
							success: function(msg,status,xhr){
								opts = $(this).data("ajaxScrollerOptions");
								if ( msg.data != undefined ) {
									$(this).children(".ajaxScrollerList").append(innerShiv(msg.data.html,false)).append(innerShiv('<div class="clear"></div>',false));
									opts.page = (opts.page+1);
									if ( msg.data.isLastPage || opts.page >= opts.pageCount ) {
										opts.reachedLastPage = true;
									}
									if ( debug && msg.debug ) {
										$.each(msg.debug, function(i,v){
											log.apply(this, v);
										});
									}
								}
								$(this).data("ajaxScrollerOptions", opts);
							},
							complete: function(){
								$(this).ajaxUnWait();
								$(this).find(".loader").remove();
							}
						};
						if ( opts.cache ) {
							$.ajaxWithCache(ajaxOpts);
						} else {
							$.ajax(ajaxOpts);
						}
					}
				}
			});
			//$(el).scroll();
		});
	};
})(jQuery);

function SonghiPlayer(argOpts) {
	var obj = {
		
		debug: false,
		element: '',
		intervalId:0,
		context: null,
		eventListeners: [],
		playing:false,

		id: '',
		src: '',
		width: 360,
		height: 111,
		flashvars: {},
		params: {allowscriptaccess:"always", wmode:"transparent"},
		attributes: {},
		
		construct: function() {
			if ( this.debug ) log("Creating new SonghiPlayer from", this.id);
			if ( this.element == '' ) this.element = $("#"+this.id).get()[0];
			if ( this.src == '' ) this.src = $(this.element).attr("js:src");
			if ( this.context == null ) this.context = this;
			this.embed();
		},
		init: function(element) { },
		_init: function() {
			this.init.apply(this.context, [this.element]);
		},
		onMethodsExposed: function(element){
		},
		_onMethodsExposed: function(){
			if ( this.debug ) log("SonghiPlayer swf methods exposed", this.id);
			this.addEventListener('soundStarted', (function(self){
				return function(){
					self.playing = true;
				};
			})(this));
			this.addEventListener('soundStopped', (function(self){
				return function(){
					self.playing = false;
				};
			})(this));
			this.onMethodsExposed.apply(this.context, [this.element]);
		},
		play: function() {
			if ( !this.playing ) {
				return this.element.startPlayback();
			}
		},
		pause: function() {
			if ( this.playing ) {
				return this.element.pausePlayback();
			}
		},
		addEventListener: function(eventName, listenerCallback) {
			// create a global function for the callback, since flash will only accept a global function name
			var fn = this.id+"JavascriptCallback"+this.eventListeners.length;
			this.eventListeners.push(listenerCallback);
			window[fn] = listenerCallback;
			return this.element.addPlayerEventListener(eventName, fn);
		},
		wait: function() {
			// periodically check if the exposed methods are available
			this.intervalId = setInterval((function(self){
				return function(){
					if ( self.element && self.element.addPlayerEventListener ) {
						if ( self.debug ) log(self.id + " ok");
						self._onMethodsExposed();
						clearInterval(self.intervalId);
					}
				};
			})(this), 500);
		},
		onEmbed: function(e) {
			if ( e.success ) {
				if ( this.debug ) log("SonghiPlayer swf embedded", this.id);
				this.element = e.ref;
				this._init();
				this.wait();
			} else {
				log("Error embedding swf", e);
			}
		},
		embed: function(){
			try {
				swfobject.embedSWF(this.src, this.id, this.width, this.height, "9.0.0", false, this.flashvars, this.params, this.attributes, (function(self){
					return function(e){
						self.onEmbed(e);
					};
				})(this));
			} catch(e) {
			}
		}
	};
	obj = $.extend(obj, argOpts);
	obj.construct();
	return obj;
}

// http://jdbartlett.github.com/innershiv | WTFPL License
window.innerShiv=(function(){var d,r;return function(h,u){if(!d){d=document.createElement('div');r=document.createDocumentFragment();/*@cc_on d.style.display = 'none'@*/}var e=d.cloneNode(true);/*@cc_on document.body.appendChild(e);@*/e.innerHTML=h.replace(/^\s\s*/, '').replace(/\s\s*$/, '');/*@cc_on document.body.removeChild(e);@*/if(u===false)return e.childNodes;var f=r.cloneNode(true),i=e.childNodes.length;while(i--)f.appendChild(e.firstChild);return f}}());

