ps$ = window.ps$ = jQuery.noConflict(true);

//Patch the remove function to avois leaks in IE
ps$.fn.remove = function() {
	ps$(this).each(function(i,e){
		if( e.parentNode )
		    e.parentNode.removeChild(e);
	});
};

// Use a closure to map $ to the PS namespace for the entire implementation
(function( $ ){  

// misc. utility plugins
$.fn.blockToggle = function (cn)
{
	if (!cn) cn = 'open';
	var div = this.parent();
	if (!div.hasClass(cn)) div.addClass(cn);
	else div.removeClass(cn);
};

//unanchored link
$.fn.blockLink = function () {
	$(this).hover(function() {
		$(this).css("cursor","pointer");
	}, function() {
		$(this).css("cursor","default");
	}).click(function() {
		location = $(this).data("blockLink");
	});
	
};

// PS plugin namespace
$.fn.PS = {}

var app = {
	pv: [],

	init: function(pv) 
	{
		app.pv = pv;
	},

	pvGet: function(k)
	{
		return (app.pv[k] !== undefined) ? app.pv[k] : null;
	},

	/* Gets the session.	 Returns a Deferred Object */
	ssGet: function ()
	{
		var idleURL = '/mem/ajax/idle';
		var dfr = $.Deferred();
		//inject data filter so only session is returned
		bsapi.post(idleURL).then(function (d) {return dfr.resolve(d.session);}, dfr.reject);
		return dfr.promise();
	},

	realmPath: function()
	{
		var area = app.pvGet('area');

		switch (area) {
		case 'adm':
		case 'cli':
		case 'mem':
		case 'mu':
			return '/' + area;
		default:
			return '';
		}
	},

	imgGet: function(id, t, host, qry, f_auth)
	{
		if (host && (host = this.pvGet('server.' + host)));
		else host = '';

		t = (t) ? ('/' + t) : '/s';
		qry = (qry) ? '?' + qry: '';

		var iget = '/img-get';
		if (f_auth) {
				var area = this.pvGet('area');
				if (area == 'mu' || area == 'mem') 
						iget = '/' + area + iget;
		}
		iget += '/';

		return host + iget + id + t + qry;
	},

	imgSzCalc: function(dim, sz, f_upscale)
	{
		if (!is_array(sz)) sz = [sz, sz];

		if (!f_upscale && (dim[0] <= sz[0] && dim[1] <= sz[1]))
			return dim;
		
		var szAR = sz[0]/sz[1];
		var dimAR = dim[0]/dim[1];

		if (szAR > dimAR) return [Math.floor(sz[1]*dimAR), sz[1]];
		else return [sz[0], Math.floor(sz[0]/dimAR)];
	}
};

//USAGE: $().PS.app("function name", args)
$.fn.PS.app = function(method) {
	if (app[method]) {
		return app[method].apply(this, Array.prototype.slice.call(arguments, 1));
	}
	else if (typeof method === 'object' || ! method) {
		return app.init.apply(this, arguments);
	}
	else {
		$.error('PS.app: undefined method [' + method + ']');
	}
}

var busy = {
	obj: null,
	
	set: function (mode) {
		if (!busy.obj) {
			/*
			busy.obj = $('<div class="psBusy"><img src="/img/BS.com/spinner-big.gif"></div>')
				.css('zIndex', '9999')
				.css('position', 'absolute')
				.appendTo('body')
				.hide();
			*/
			
			busy.obj = $('<h1>please wait...</h1>');
			busy.obj.dialog({
				autoOpen: false,
				modal: true,
				zIndex: 99999,
				stack: true,
				resizable: false,
				dialogClass: 'psBusy'
			});
		}
		
		busy.obj.dialog(mode ? 'open' : 'close');

		/*
		busy.obj.toggle(mode);
		if (mode) {
			busy.obj.position({
				my: "center",
				at: "center",
				of: "body"
			});
		}
		*/
	}

}

$.fn.PS.busy = function(method) {
	if (busy[method]) {
		return busy[method].apply(this, Array.prototype.slice.call(arguments, 1));
	}
	else if (typeof method === 'object' || ! method) {
		return busy.init.apply(this, arguments);
	}
	else {
		$.error('PS.busy: undefined method [' + method + ']');
	}
}

$.fn.PS.dialogResize = function (dialog, minH, scalingO) {
	var winH = $(window).height();
	var widg = dialog.dialog("widget");
	var scH = ( scalingO.children().length == 1 ? scalingO.children().height() : scalingO.prop("scrollHeight"));
	var chro = widg.height() - scalingO.height();
	var mt = (parseInt(widg.css("marginTop")) || 0);
	var mb = (parseInt(widg.css("marginBottom")) || 0);
	var maxH = winH - chro - (mt + mb);

	scalingO.height(Math.max(Math.min(maxH, scH), minH));
};

// ################ relInputLabel ################
// toggle form labels in input fields 
// ##############################################
var relInputLabel = {
	_opt : {
		'blur' : false	
	},

	init : function (fId, bindSubmit, blur)
	{
		if (blur)
			relInputLabel._opt.blur = true;

		var fObj = $("FORM#"+fId);
		fObj.find("INPUT[rel]").each(relInputLabel._wireI);
		if (bindSubmit) {
			fObj.submit(function() {
				relInputLabel.submit(fId);
			});
		}
	},

	submit : function (fId)
	{
		var fObj = $("FORM#"+fId);
		fObj.find("INPUT[rel]").each(relInputLabel._submit);
	},

	_wireI : function ()
	{
		if ($(this).val() != '') return;

		$(this).val($(this).attr('rel'))
			.focus(relInputLabel._hide)
			.addClass('relInp');

		if (relInputLabel._opt.blur) 
			$(this).blur(relInputLabel._show);
			
	},

	_wireS : function ()
	{
		$(this).prepend("<option value=\"\">" + $(this).attr('rel') + "</option>");

	},

        _submit : function ()
	{
		if ($(this).hasClass("relInp"))
			$(this).val('');
	},

	_show : function ()
	{
		if ($(this).val() == '') {
			$(this).val($(this).attr('rel'));
			$(this).addClass('relInp');
		}
	},

	_hide : function ()
	{
		if ($(this).val() == $(this).attr('rel'))
			$(this).val('');

		$(this).removeClass('relInp');
	}
};

$.fn.PS.relInputLabel = function(method) {
	if (relInputLabel[method]) {
		return relInputLabel[method].apply(this, Array.prototype.slice.call(arguments, 1));
	}
	else if (typeof method === 'object' || !method) {
		return relInputLabel.init.apply(this, arguments);
	}
	else {
		$.error('PS.relInputLabel: undefined method [' + method + ']');
	}
};
// ########################################################
// widgets
// ########################################################

$.widget('ps.bsapi', {
	post: function (url, data)
	{
		var dfr = $.Deferred();
		var settings = {
			type: 'POST',
			dataType: 'json',
			cache: false,
			data: data ? data : null
		};

		$.ajax(url, settings).then(function (data, textStatus, jsXHR) {
			if (data.response && data.response.error) {
				var errstr = '', d = data.response.error;
				for (var i=0, l=d.length; i < l; i++) 
					errstr += d[i]['message']+"\n";
				/* waiting for windowing libs
					for (var i=0, l=d.length; i < l; i++) 
					errstr = '<div>'+d[i]['message']+'</div>';
					$(document).after('<div id="_bsjqErr">'+errstr+'</div>');
					$('#_bsjqErr').dialog();
				*/
				// FIXME: better way to silently error?
				//console.log(errstr);
				dfr.reject(data.response.error);
			}
			else dfr.resolve(data, textStatus, jsXHR);
		}, dfr.reject);

		return dfr;
	}

	/*
	responseParse: function (args)
	{
		var data = args[0];
		var textStatus = args[1];
		var jsXHR = args[2];
		
		if (data.response && data.response.error) {
			var errstr = '', d = data.response.error;
			for (var i=0, l=d.length; i < l; i++) 
				errstr += d[i]['message']+"\n";
			// waiting for windowing libs
			//for (var i=0, l=d.length; i < l; i++) 
			// errstr = '<div>'+d[i]['message']+'</div>';
			//$(document).after('<div id="_bsjqErr">'+errstr+'</div>');
			//$('#_bsjqErr').dialog();

			// FIXME: silently error?
			//console.log(errstr);
			throw data.response.error;
		}		
	}
	*/
});

// ########################################################
// plugins
// ########################################################


// ########################################################
// ready functions
// ########################################################

$().ready(function() {
	// Global AJAX transfer error handler
	$('body').ajaxError(function(evt, xhr, settings, excpt) {
		try {
			// FIXME: silently error
			//console.log('jquery.PS.ajaxError', excpt); 

			//make sure to prevent method-specific AJAX callback from firing (passed in settings['complete'])
			evt.stopImmediatePropagation();
			$(".psWaitingMd").trigger('bsapi_error');

			// do something with a transfer error here....
			// like throw a prompt with some messaging
			// or do the local onErr
			if (setting.onErr != undefined)
				settings.onTransportErr(evt, xhr, settings);

			throw new Error('Transfer Error');
		} catch(err) {} // force a silent error
	});

	//Global AJAX API error / exception handler (responseParse)
	$('body').ajaxSuccess(function(evt, xhr, settings) {
		var d;

		// FIXME: need real content type detection?
		switch (settings.dataType) {
		case 'json':
			// can responseText be non-string???
			if (typeof xhr.responseText == 'string')
				d = eval( "(" + xhr.responseText + ")" );
			else if (xhr.responseText)
				d = xhr.responseText;

			if (!d) return;

			if (typeof d.response == 'undefined') {
				//console.log('getJson has no data.response');
			}
			else if ((typeof d.response.success) != 'undefined') {
				if ($.isFunction(settings.bsapiCB))
					settings.bsapiCB(d['return'], settings);
				else return;
			}
			else if ((typeof d.response.error) != 'undefined') {
				var errA = d.response.error;

				// stop method-specific callbacks from firing
				evt.stopImmediatePropagation();

				if ($.isFunction(settings.bsapiErr)) {
					settings.bsapiErr(errA, settings);
				}
				else {
					// FIXME: default handling
					//console.log('generic bsapi error', errA);
				}
			}
			else throw new Error('invalid response');
			break;

		case 'html':
			if (xhr.responseText == '') {
				$("psWaitingMd").trigger('bsapi_error');
				break;
			}
		default:
			if (typeof xhr.responseXML == 'object') {
				xml = xhr.responseXML;
				err = xml.getElementsByTagName('error');
				if (err.length) {
					if ($.isFunction(settings.bsapiErr)) {
						settings.bsapiErr(err, settings);
						break;
					} 
					else {
						break; //FIX ME: same as above - we need some global handling
					}
				}
			}
			if ($.isFunction(settings.bsapiCB))
				settings.bsapiCB(xhr.responseText, settings);

			break;
		}
	});
});



})(ps$);

