/**
 * (c) 2011 Markus Bigler (markus.bigler#nullnulleins.ch). All rights reserved.
 * 
 * This file is part of glorya.
 *
 * glorya is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glorya is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with glorya. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
// prototype extensions
// trim string
String.prototype.trim = function () {
    return this.replace (/^\s*/, '').replace (/\s*$/, '');
};
// Get the ISO week date week number
Date.prototype.getWeekNr = function () {
    // find JulianDay
	var a = Math.floor ((14 - (this.getMonth () + 1)) / 12);
	var y = this.getFullYear () + 4800 - a;
	var m = (this.getMonth () + 1) + (12 * a) - 3;
	var jd = this.getDate () + Math.floor (((153 * m) + 2) / 5) + (365 * y) + Math.floor (y / 4) - Math.floor (y / 100) + Math.floor (y / 400) - 32045;
	// (gregorian calendar)
	// now calc weeknumber according to JD
	var d4 = (jd + 31741 - (jd % 7)) % 146097 % 36524 % 1461;
	var l = Math.floor (d4 / 1460);
	var d1 = ((d4 - l) % 365) + l;
	return Math.floor (d1 / 7) + 1;
};
// Get the unix-timestamp from date
Date.prototype.getUnix = function () {
	return Math.round (this.getTime () / 1000.0);
};

// this object holds all framework data and functions
window.glorya = {
	urlPrefix: '/',
	domLoaded: false,
	// contains code to be executed on document load
	onLoadRegistry: new Array (),
	reloadPage: function () {
		glorya.wait ('global_page_reload');
		var uri = location.href;
		if (uri.indexOf ('?login') >= 0) {
			// if there is a ?login then remove it
			uri = uri.replace ('?login', '');
		}
		if (uri.indexOf ('#') >= 0) {
			// if there is a hash, we need to remove it
			uri = uri.substring (0, uri.indexOf ('#'));
		}
		if (uri == location.href) {
			// just reload
			location.reload (true);
		}
		else {
			location.replace (uri);
		}
	},
	// reloads the toplevel window, if it's not a wwwEditor
	reloadTopPage: function () {
		if (window.opener && !window.closed) {
			// go on to parent
			window.opener.glorya.reloadTopPage ();
		}
		else {
			if (!glorya.isWWWEditor) {
				glorya.reloadPage ();
			}
		}
	},
	// onload stuff:
	// pass the code to be executed on $.ready as string
	executeOnLoad: function (code) {
		var existing = false;
		for (var i = 0; !existing && i < glorya.onLoadRegistry.length; i++) {
			existing = (code == glorya.onLoadRegistry[i]);
		}
		if (!existing) {
			glorya.onLoadRegistry[glorya.onLoadRegistry.length] = code;
		}
	},
	// Executes the code in onLoadRegistry
	onLoad: function () {
		glorya.domLoaded = true;
		// execute all the code in the onloadregistry
		for (var i = 0; i < glorya.onLoadRegistry.length; i++) {
			try {
				eval (glorya.onLoadRegistry[i]);
			} catch (ex) {
				alert ('Exception in onLoadRegistry: ' + glorya.onLoadRegistry[i] + "\n" + ex.name + ": " + ex.message);
			}
		}
		//
		// clear the registry, it might get called after a json-request again
		glorya.onLoadRegistry = [];
	},
	// Preload an image
	preloadImage: function () {
		var img = new Image ();
		for (var i = 0; i < arguments.length; i++) {
			img.src = arguments[i];
		}
	},
	// sets the cursor in the field with the given id returns true if it works
	focusInput: function (id) {
		var input = $(':input#' + id);
		// do not focus color input, it would open the color-picker too
		if (input && input.length == 1 && !input.hasClass ('readonly') && !input.hasClass ('disabled') && !input.hasClass ('color')) {
			try {
				if (input.hasClass ('__ckeditor')) {
					// check if this is visible
					CKEDITOR.instances[id].focus ();
				}
				else {
					input.focus ().select ();
				}
				return true;
			} catch (ex) {
				return false;
			}
		}
		/*else {
			glorya.debug ('not found: ' + id);
		}*/
		return false;
	},
	// sets the cursor in the first visible field in the html-element (a form or a tab) with the given id
	focusForm: function (id) {
		// @todo if focusInput returns false try next input
		// @todo check documentation for .not() it does not seam to work correctly
		glorya.focusInput ($(':input:visible:not(.readonly):not(.disabled), :input.__ckeditor', $('#' + id)).filter (':eq(0)').attr ('id'), false);
		return false;
	},
	// resource functions
	getResource: function (resourceKey, params) {
		if (resourceKey) {
			var r = glorya.json.call ('admin/' + glorya.adminLanguage + '/__user_1/gateway/', { module: 'getresource', key: resourceKey, params: params });
			return r.resource;
		}
		return 'No resourceKey in input.';
	},
	// create an email-link
	linkMT: function (linkNr, address) {
		var l = $('#mt-' + linkNr);
		if (l.length == 1) {
			var label = l.html ();
			l.html ('<a/>');
			$('a', l).attr ('href', 'javascript:void(0);').html (label).bind ('click', function () {
				var e = '';
				for (var i = 0; i < address.length; i++) {
					e += String.fromCharCode (address[i]);
				}
				document.location.href = 'mailto:' + e;
			});
		}
	},
	// adds ' target="_blank"' to all a- and form-tags having rel=external
	external2blank: function () {
		$('a:[rel="external"],form:[rel="external"]').attr ('target', '_blank').removeAttr ('rel');
		// clean up email-links
		$('a:[href*="mailto:"]:[target="_blank"]').removeAttr ('target');
	},
	// alerts a message or a resource
	// if there is no callback, it just closes the dialog on "OK"
	alert: function (message, isResource, params, callback) {
		glorya.dialog (message, [{label: 'global_dialog_ok', isResource: true, action: (callback ? callback : function () { glorya.hideDialog (); }) }], isResource, params);
	},
	// glorya.dialog ('sitemap_save_error', [{label: 'global_dialog_ok', action: function () { glorya.reloadPage (); }}]);
	dialog: function (message, buttons, isResource, params) {
		var d = window.glorya.getDialog ();
		var content = '<div class="message">' + (isResource ? glorya.getDialogResource (message, params) : message) + '</div>';
		content += '<div class="buttons">';
		for (var i = 0; i < buttons.length; i++) {
			content += '<input type="button" value="' + (buttons[i].isResource ? glorya.getDialogResource (buttons[i].label) : buttons[i].label) + '" id="glorya_dialogbutton_' + i + '"/>';
		}
		content += '</div>';
		d.html (content);
		for (var i = 0; i < buttons.length; i++) {
			$('#glorya_dialogbutton_' + i).bind ('click', buttons[i].action);
		}
		d.parent ().show ();
		// focus first button
		$(':input:eq(0)', d).focus ().select ();
	},
	wait: function (message, isResource) {
		var d = window.glorya.getDialog ();
		d.width ('200px');
		d.html ('<div class="wait">' + (message ? (isResource ? glorya.getDialogResource (resourceName) : '') : '') + '</div>');
		d.parent ().show ();
	},
	dialogWindow: undefined,
	dialogResources: [],
	getDialogResource: function (resourceName, params) {
		if (!glorya.dialogResources[resourceName]) {
			if (params) {
				// do not cache resources with params
				return glorya.getResource (resourceName, params);
			}
			else {
				glorya.dialogResources[resourceName] = glorya.getResource (resourceName);
			}
		}
		return glorya.dialogResources[resourceName];
	},
	hideDialog: function () {
		if (glorya.dialogWindow) {
			glorya.dialogWindow.hide ();
			glorya.dialogWindow = undefined;
		}
	},
	getDialog: function () {
		var d = $('#glorya-dialog');
		if (d.length != 1) {
			// load css
			glorya.loadCSSFile ('system/gui/css/dialog.css');
			// create div
			d = $('<div id="glorya-dialog"/>');
			$('body').prepend (d);
			d.hide ();
		}
		d.html ('<div class="dialog"/>');
		glorya.dialogWindow = d;
		return d.children ('div:eq(0)');
	},
	debugWindow: undefined,
	debug: function (msg) {
		if (glorya.debugWindow == undefined) {
			// load css
			glorya.loadCSSFile ('system/gui/css/debug.css');
			// create div
			$('body').prepend ('<div id="gloryadebugger" style="position: absolute;"><div class="handle">Debug Log<span>X</span></div><div class="scrollpane"><ul/></div></div>');
			glorya.debugWindow = $('#gloryadebugger .scrollpane');
			$('#gloryadebugger span').bind ('click', function () { $(this).parent ().parent ().css ('display', 'none'); });
			glorya.debugWindow.parent ().draggable ({
				handle: 'div.handle',
				stop: function () {
					glorya.cookie.set ('gloryadebugtop', $(this).css ('top'));
					glorya.cookie.set ('gloryadebugleft', $(this).css ('left'));
				}
			});
			var t = glorya.cookie.get ('gloryadebugtop'),
			l = glorya.cookie.get ('gloryadebugleft');
			if (t && l) {
				$('#gloryadebugger').css ('left', l).css ('top', t);
			}
		}
		glorya.debugWindow.parent ().css ('display', '');
		var d = new Date ();
		var ms = d.getMilliseconds ();
		$('>ul', glorya.debugWindow).prepend ('<li>' + d.toLocaleTimeString () + '.' + (ms < 10 ? '00' + ms : (ms < 100 ? '0' + ms : ms)) + ' &ndash; ' + msg + '</li>');
	},
	// called when visitor reaches a protected page
	loadWWWLogin: function () {
		glorya.loadCSSFile ('system/gui/css/wwwadmin.css');
		glorya.loadJSFile ('system/gui/js/glorya.intranet.js', function () {
			glorya.wwwEditor.showLogin (function () {
				// alter the cancel-button-action
				$('#gloryawwwlogin input:button:[name=form_cancel]').bind ('mousedown', function () {
					$('#gloryawwwlogin').animate ({ top: '-200px' }, 1000);
				});
			});
		});
	},
	loadCSSFile: function (url) {
		$('head').append ('<link>');
	    css = $('head').children ('link:last');
	    css.attr ({ rel: 'stylesheet', type: 'text/css', href: glorya.urlPrefix + url });
	},
	loadJSFile: function (url, callback) {
		$.getScript (glorya.urlPrefix + url, callback);
	},
	getCommonParent: function (selector) {
		var $items = $(selector);
		var total = $items.length;
	    var parent;
	    $items.first ().parents ().each (function () {
	    	if ($(this).find (selector).length == total) {
	    		parent = this;
	    		return false;
	    	}
	    });
	    return $(parent);
	}
};
// register onload via jquery's ready
$(document).ready (function () { glorya.onLoad (); });

//child windows
window.glorya.popup = {
	/**
	 * Opens a popup-window.
	 * @param string url The URL to be displayed in the window
	 * @param boolean doReturnWindow If set to true, it will return the reference to the window-object (optional)
	 * @param string name The name of the window, if not set and if there is an id=[0-9] in the url, name will be set dynamically 
	 * @param int width The width of the window in px (optional)
	 * @param int height The height of the window in px (optional)
	 */
	open: function (url, doReturnWindow, name, width, height) {
		if (!width) width = 726;
		if (!height) height = 500;
		var winX = (document.all) ? window.screenLeft : window.screenX;
		var winY = (document.all) ? window.screenTop : window.screenY;
		// position on the screen
		var left = (screen.width - width) / 2;
		var top = (screen.height - height) / 2.5;
		if ($('body').hasClass ('popup')) {
			// position slightly more left and lower than this
			left = winX - 150;
			top = winY + 100;
		}
		else {
			// position in the top right corner
			left = screen.width - width - 50;
			top = 50;
		}
		// screen.width / screen.height
		var windowName = '';
		// set the window's name
		if (name) {
			windowName = name;
		}
		// dynamically create a windowName from the url if there is an id in the parameter list
		else if (url.match (/id=[0-9]+/) && url.indexOf ('?')) {
			// windowname will be tableUID+actionName+recordID
			windowName = url.replace (glorya.urlPrefix + 'admin/' + glorya.adminLanguage + '/', '').replace (/\//g, '_');
			// remove parameters
			var params = '' + windowName.substr (windowName.indexOf ('?')).match (/id=[0-9]+/);
			windowName = windowName.substr (0, windowName.indexOf ('?')) + params.substr (3);
		}
		var win = window.open (url, windowName, 'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',location=0,status=1,menubar=0,resizable=1,toolbar=0,scrollbars=1');
		//var win = window.showModalDialog (url); /* does not work on opera */
		if (win && win.focus) { win.focus (); } // does not work in opera (by default) and safari
		// set opener
		if (win && !win.opener) {
			win.opener = self; // @todo why not window?
		}
		window.setTimeout (function () {
			// popup-blocker ?
			// opera/safari + chrome return a window, but opera/safari's window's name is undefined
			// chrome does not set a height test it after some time
			// all browsers                         // extra-sausage for google's chrome
			if ((!win || win.name == undefined) || ((win.outerHeight == 0 || win.outerHeight == undefined) && (win.left == 0 || win.left == undefined))) {
				if ($('#gloryacontent').length == 1) {
					$('#gloryacontent').prepend ('<ul class="gloryacontentnote" style="display:none;"><li>' + glorya.getResource ('popup_blocked_restore_message') + ': <a href="javascript:$(\'#gloryacontent>.gloryacontentnote\').slideUp(150,function(){$(this).remove ();});glorya.popup.open(\'' + url + '\');">' + url + '</a></li></ul>');
					$('#gloryacontent>ul.gloryacontentnote').slideDown (150);
				}
				else {
					glorya.alert ('popup_blocked: ' + url);
				}
			}
		}, 500);
		if (doReturnWindow) {
			return win;
		}
	},
	// Returns null or the opening window if it still exists
	getRoot: function () {
		var win = window.opener;
		while (win != null) {
			if (win.opener == null) {
				break;
			}
			win = win.opener;
		}
		return win;
	},
	// closes the current window if the opener disappears or if the opener is on the loginscreen
	observeParent: function () {
		if (window.opener && !window.closed) {
			// for ie
			try {
				// access to opener.document throws an exception
				var bl = window.opener.document;
				if (window.opener.glorya.currentAction.id && window.opener.glorya.currentAction.id == 1) {
					// the opener is a login screen -> close
					this.close ();
				}
				else if (!window.opener.glorya.adminLanguage || window.opener.glorya.adminLanguage == '') {
					// adminLanguage is always defined if admin is logged in
					this.close ();
				}
				else {
					setTimeout (glorya.popup.observeParent, 5000);
				}
			} catch (ex) {
				// ie: close this popup if opener does not exist anymore
				try { this.close (); } catch (ex) { }
			}
		}
		else {
			// close this popup if opener does not exist anymore
			try {
				this.close ();
			} catch (ex) {
				// if we can't close via javascript it's most probably becuase we are in the main-window
				// maybe if you login with http://joses02/glorya/admin/de/__user_1/add/
				// so, we try to open the popup and go to the welcome screen
				// @todo correct url
				/*try {
					glorya.popup.open (document.location.href, false, 'test');
				} catch (ex) {} */
				$('#gloryawrapper').hide ();
				var params = '';
				if (document.location.href.indexOf ('?') > 0) {
					params = document.location.href.substr (document.location.href.indexOf ('?') + 1);
				}
				// go to admin and pass url to be restored
				document.location.replace (glorya.urlPrefix + 'admin/?restorepopup=' + glorya.util.urlEncode (glorya.currentTable.uid + ':' + glorya.currentAction.name) + (params != '' ? '&restoreparams=' + glorya.util.urlEncode (params) : ''));
			}
		}
	}
};

// json stuff
window.glorya.json = {
	// @todo solve jsonp and remove gateway loadremote
	call: function (url, data, success, error) {
		// if it's an absolute url don't modify, otherwise add the urlPrefix
		if (url.indexOf ('://') < 0) {
			url = glorya.urlPrefix + url;
		}
		try {
			// if we have a callback we execute it async
			if (success != undefined) {
				$.ajax ({
					url: url,
					data: data,
					type: 'GET',
					dataType: 'json',
					async: true,
					success: success,
					error: (error != undefined ? error : function (request, textStatus, errorThrown) { alert (url + ': ' + request + ' (' + request.status + '): ' + textStatus + ': ' + errorThrown); }) 
				});
			}
			// if there is no callback we immediately eval the return value
			else {
				// alert (glorya.urlPrefix + url);
				var c = eval ('(' + $.ajax ({
					url: url,
					data: data,
					type: 'GET',
					dataType: 'json',
					async: false,
					error: (error != undefined ? error : function (request, textStatus, errorThrown) { alert (url + ': ' + request + ' (' + request.status + '): ' + textStatus + ': ' + errorThrown); })
				}).responseText + ')');
				// jsHeaderCode is executed automatically if there is no callback
				glorya.json.evalHeader (c);
				// handle login screen in response
				glorya.json.checkLogin (c);
				// we do not return anything if c.isvoid is set
				if (c.isvoid == undefined || c.isvoid != '1') {
					return c;
				}
			}
		} catch (ex) {
			alert (ex);
			alert (url + ': ' + data);
		}
	},
	// Evaluates c.jsHeaderCode (is executed automatically if there is no callback)
	evalHeader: function (c) {
		if (c.jsHeaderCode) { 
			try {
				eval (c.jsHeaderCode);
			} catch (ex) {
				alert ('Exception in headercode: ' + ex);
			}
		}
	},
	// Evaluates c.jsFooterCode (has to be called by script)
	evalFooter: function (c) {
		if (c.jsFooterCode) {
			try {
				eval (c.jsFooterCode);
			} catch (ex) {
				alert ('Exception in footercode: ' + ex);
			}
		}
	},
	checkLogin: function (c) {
		if (c.loginform != undefined) {
			glorya.reloadTopPage ();
		}
	}
};
// utils
window.glorya.util = {
	// escape a string for use in a regexp
	regexpEscape: function (text) {
		return text.replace (/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	},
	// sets the value of the field to the attr oldval
	onValueChanged: function (fieldName, callback) {
		var f = $('#form_' + fieldName);
		if (f.length == 1) {
			f.attr ('oldval', f.val ());
			f.bind ('keydown', function () {
				$(this).attr ('oldval', $(this).val ());
			});
			if (callback) {
				f.bind ('keyup', function (event) {
					if (!glorya.util.isSpecialKey (event)) {
						if ($(this).val () != $(this).attr ('oldval')) {
							callback ($(this));
						}
					}
				});
			}
		}
	},
	getCharCode: function (event) {
		event = event || window.event;
		if (event) {
			if (event.keyCode) {
				return event.keyCode;
			}
			else if (event.charCode) {
				return event.charCode;
			}
		}
		return null;
	},
	isSpecialKey: function (event) {
		event = event || window.event;
		return (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey);
	},
	isEnterKey: function (event) {
		var code = glorya.util.getCharCode (event);
		return (code == 13);
	},
	// @todo does not work in ie, it does not issue onkeypress with meta-keys
/*
	isCtrlV: function (event) {
		event = event || window.event;
		var code = glorya.util.getCharCode (event);
		//                        windows          apple
		return ((code == 118) && (event.ctrlKey || event.metaKey));
	},
*/
	formatFileSize: function (filesize) {
		if (filesize >= 1073741824) {
			filesize = (filesize / 1073741824).toFixed (2) + 'GB';
		}
		else { 
			if (filesize >= 1048576) {
				filesize = (filesize / 1048576).toFixed (2) + 'MB';
			}
			else {
				if (filesize >= 1024) {
					filesize = (filesize / 1024).toFixed (2) + 'KB';
				}
				else {
					filesize = (filesize) + 'B';
				}
			}
		}
		return filesize;
	},
	urlEncode: function (value) {
		// urifunction is used for utf-8
		return escape (encodeURIComponent (value));
	},
	urlDecode: function (value) {
		// urifunction is used for utf-8
		return decodeURIComponent (unescape (value));
	},
	highlight: function (obj, color) {
		if (color == undefined) {
			color = '#FFFFBB';
		}
		obj.effect ('highlight', { color: color }, 500);
		window.setTimeout (function () { obj.effect ('highlight', { color: color }, 500); }, 600);
		window.setTimeout (function () { obj.effect ('highlight', { color: color }, 500); }, 1200);
	},
	// removes the given value from the array
	deleteArrayValue: function (arr, value) {
		for (var i = 0; i < arr.length; i++) {
			if (arr[i] == value) {
				this.splice (i, 1);
				i--;
			}
		}
		return arr;
		// return arr.splice( $.inArray (value, arr), 1 );
	}
};
// cookies
window.glorya.cookie = {
	set: function (name, value, days) {
		if (days) {
			var date = new Date ();
			date.setTime (date.getTime () + (days * 24 * 60 * 60 * 1000));
			var expires = '; expires=' + date.toGMTString ();
		}
		else {
			var expires = '';
		}
		document.cookie = name + '=' + value + expires + '; path=' + glorya.urlPrefix;
	},
	get: function (name) {
		var nameEQ = name + '=';
		var ca = document.cookie.split (';');
		for (var i = 0; i < ca.length; i++) {
			var c = ca[i];
			while (c.charAt (0) == ' ') {
				c = c.substring (1, c.length);
			}
			if (c.indexOf (nameEQ) == 0) {
				return c.substring (nameEQ.length, c.length);
			}
		}
		return null;
	},
	unset: function (name) {
		createCookie (name, '', -1);
	}
}

// helpers on the image button
window.glorya.imageButton = {
	enable: function (button) {
		// only do it if button is disabled
		if (button && button.children (0).hasClass ('disabled')) {
			button.children (0).removeClass ('disabled');
			if (button.attr ('disabledhref')) {
				// restore href
				button.attr ('href', button.attr ('disabledhref'));
			}
		}
	},
	disable: function (button) {
		// only do it if button is NOT disabled yet
		if (button && !button.children (0).hasClass ('disabled')) {
			button.children (0).addClass ('disabled');
			// backup href
			if (button.attr ('href')) {
				button.attr ('disabledhref', button.attr ('href'));
				button.attr ('href', 'javascript:void(0);');
			}
		}
	},
	setDisabledHREF: function (id, href) {
		$('#' + id).attr ('disabledhref', href);
	}
};

// MP3 Player
window.glorya.mp3Player = {
	position: 0,
	instance: null,
	// flash interface
	onInit: function () {
		glorya.mp3Player.instance = document.getElementById ('__mp3player');
		// get all mp3player buttons and activate them
		$.each ($('a.imagebutton.mp3player'), function () { glorya.imageButton.enable ($(this)); });
	},
	onUpdate: function () {
		var a = $('a:[nowplaying=true]');
		if (a.length == 1) {
			if (this.isPlaying == 'true') {
				if ((1 * this.position) > 0) {
					$('img', a).attr ('src', $('img', a).attr ('src').replace ('load', 'stop').replace ('play', 'stop'));
				}
				/*
				glorya.debug ('pos: ' + this.position + ': ' + (this.position == 0));
				glorya.debug ('bl : ' + this.bytesLoaded);
				glorya.debug ('bt : ' + this.bytesTotal);
				this.duration
				this.bytesPercent
				*/
			}
			else {
				glorya.mp3Player.stop ($('a:[nowplaying=true]').attr ('id'));
			}
		}
		else {
			glorya.mp3Player.instance.SetVariable ('enabled', 'false');
		}
	},
	// javascript stuff
	initialise: function () {
		if ($('#__mp3player').length == 0) {
			// move it out, display: none would cause it not to be loaded
			$('body').prepend ('<div style="position:absolute;top:-50px;"><div id="__mp3player"/></div>');
			//$('body').append ('<!--[if IE]><script type="text/javascript" event="FSCommand(command,args)" for="__mp3player">' + '</script><![endif]-->');
		}
		if ($('#__mp3player').length == 1) {
			var player = $('#__mp3player');
			if (player.length == 1) {
				try {
					glorya.loadJSFile ('system/gui/js/lib/swfobject/swfobject.js', function () {
						swfobject.embedSWF (glorya.urlPrefix + 'system/gui/js/lib/mp3player/player_mp3_js.swf', '__mp3player', '180', '40', '9.0.0', null, {name: '__mp3player', listener: 'glorya.mp3Player'});
					});
				} catch (ex) { alert (ex); }
			}
		}
	},
	play: function (buttonID) {
		try {
			// get the anchor
			var a = $('#' + buttonID);
			this.position = 0;
			glorya.mp3Player.instance.SetVariable ('method:setUrl', a.attr ('title'));
			glorya.mp3Player.instance.SetVariable ('enabled', 'true');
			glorya.mp3Player.instance.SetVariable ('method:play', '');
			// replace icons and links of any other player playing or loading
			$.each ($('a:[nowplaying=true]'), function () {
				$(this).attr ('href', 'javascript:glorya.mp3Player.play(\'' + $(this).attr ('id') + '\')').removeAttr ('nowplaying');
				$('img', $(this)).attr ('src', $('img', $(this)).attr ('src').replace ('load', 'play').replace ('stop', 'play'));
			});
			// replace image and link of this instance
			a.attr ('href', 'javascript:glorya.mp3Player.stop(\'' + buttonID + '\')').attr ('nowplaying', 'true');
			$($('img', a)).attr ('src', $($('img', a)).attr ('src').replace ('play', 'load'));
		} catch (ex) { /* alert (ex); */ }
	},
	stop: function (buttonID) {
		glorya.mp3Player.instance.SetVariable ('method:stop', '');
		glorya.mp3Player.instance.SetVariable ('enabled', 'false');
		var a = $('#' + buttonID);
		a.attr ('href', 'javascript:glorya.mp3Player.play(\'' + buttonID + '\')').removeAttr ('nowplaying');
		$('img', a).attr ('src', $('img', a).attr ('src').replace ('stop', 'play').replace ('load', 'play'));
	}
};
// inputtypes
window.glorya.inputType = new Object ();
// urlField
window.glorya.inputType.urlField = {
	// Opens the url from the inputfield in a popup
	open: function (field) {
		if (field.val ()) { glorya.popup.open (field.val ()); }
	},
	validate: function (name, protocolChanged) {
		var field = $('#form_' + name + '_input');
		var selector = $('#form_' + name + '_protocol');
		var url = $('#form_' + name);
		var value = field.val ();
		if (!protocolChanged) {
			// see if there is a protocol
			var protocolFound = false;
			$('#form_' + name + '_protocol > option').each (function () {
				if ($(this).val ().length > 0 && $(this).val ().toLowerCase () == value.substr (0, $(this).val ().length).toLowerCase ()) {
					value = value.substr ($(this).val ().length);
					field.val (value);
					selector.val ($(this).val ());
					protocolFound = true;
				}
			});
			// if there is no matching protocol but there is a :// in the url set protocol to ''
			if (!protocolFound && /^.*\:\/\/.*/.test (value)) {
				selector.val ('');
			}
		}
		if (glorya.inputType.urlField.isValidURL (field.val (), selector.val ())) {
			// enable button
			url.val (selector.val () + value);
			glorya.imageButton.enable ($('.imagebutton', $('#form_' + name).parent ()));
		}
		else {
			// disable button
			url.val ('');
			glorya.imageButton.disable ($('.imagebutton', $('#form_' + name).parent ()));
		}
	},
	isValidURL: function (url, protocol) {
		var isValid = false;
		if (protocol != undefined) {
			// @todo find real regexp
			isValid = (url.length > 0);
		}
		else {
			// we got protocol+url together
			// @todo find real regexp
			isValid = /[a-z]{3,5}:\/\/.*\.[a-z]{2,4}.*/i.test (url);
		}
		// @todo only validate if there is protocol selected that is not javascript:
		/*	if (isValid && protocol.length > 0 && protocol != 'javascript:') {
		var regExp = /^.*[\.[a-z]{2,}\/$|\.[a-z]{2,}\/.*$|\.[a-z\-]{2,}$]/i;
		isValid = regExp.test (url);
		}*/
		return isValid;
	}
};
// email
window.glorya.inputType.emailField = {
	send: function (field) {
		if (field.val ()) {
			location.href = 'mailto:' + field.val ();
		}
	},
	validate: function (name) {
		if (this.isValidEmail ($('#form_' + name).val ())) {
			glorya.imageButton.enable ($('#form_' + name).next ()); // enable button
		}
		else {
			glorya.imageButton.disable ($('#form_' + name).next ()); // disable button
		}
	},
	isValidEmail: function (email) {
		regExp = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
		// let's see if this might be a valid email address
		return regExp.test (email);
	}
};
// date/time/calendar
window.glorya.inputType.calendar = {
	onOpenRegistry: {},
	onShowDateRegistry: {},
	toggle: function (name) {
		if ($('#form_' + name + '_calendar').css ('display') == 'block') {
			this.close (name);
		}
		else {
			this.open (name);
		}
	},
	open: function (name) {
		// find the parent "name + '_d'" and the selected value in "name"
		var textField = $('#form_' + name + '_d');
		var calendar = $('#form_' + name + '_calendar');
		if (!calendar.html ()) {
			// create the calendar
			var code  = '<table cellpadding="0" cellspacing="0" border="0">' +
						'<thead><tr><th colspan="8"></th></tr></thead>' +
						'<tfoot><tr><td colspan="8"></td></tr></tfoot>' +
						'<tbody><tr><td colspan="8"></td></tr></tbody></table>';
			textField.parent ().append ($('<div id="form_' + name + '_calendar" class="calendar" onclick="event.cancelBubble=true;">' + code + '</div>'));
			calendar = $('#form_' + name + '_calendar');
			calendar.attr ('name', name);
			// close the calendar on document click
			$(document).bind ('click', function () { glorya.inputType.calendar.close (name); });
			// @todo add clicklistener on iframes as well, event bubbling might be turned off in fck?
		}
		// set the calendars content
		// add the header
		$('tfoot > tr > td:first', calendar).html ('<span onclick="glorya.inputType.dateTimeField.setDate (\'' + name + '\', new Date (), true);">' + this.config.today + '</span>');
		var date = ($('#form_' + name).val () && $('#form_' + name).val () != window.glorya.dbnull ? new Date (1000 * $('#form_' + name).val ()) : new Date ());
		var isSelected = ($('#form_' + name).val () && $('#form_' + name).val () != window.glorya.dbnull);
		this.showDate (name, date, isSelected);
		// show it
		calendar.css ('display', 'none').slideDown (150);
		// check onOpenRegistry
		if (this.onOpenRegistry[name]) {
			for (var i = 0; i < this.onOpenRegistry[name].length; i++) {
				eval (this.onOpenRegistry[name][i]);
			}
		}
	},
	close: function (name) {
		$('#form_' + name + '_calendar').slideUp (150);
	},
	// called when the calendar is shown and when user browses months/years
	showDate: function (name, date, isSelected) {
		var cc = this.config;
		var calendar = $('#form_' + name + '_calendar');
		$('thead tr', calendar).html ('<th><a onclick="glorya.inputType.calendar.showDate(\'' + calendar.attr ('name') + '\',new Date(' + date.getFullYear () + ',' + (date.getMonth () - 1) + ',' + date.getDate () + '));">&lt;</a></th><th colspan="2">' + cc.months[date.getMonth ()] + '</th><th><a onclick="glorya.inputType.calendar.showDate(\'' + calendar.attr ('name') + '\',new Date(' + date.getFullYear () + ',' + (date.getMonth () + 1) + ',' + date.getDate () + '))">&gt;</a></th><th><a onclick="glorya.inputType.calendar.showDate(\'' + calendar.attr ('name') + '\',new Date(' + (date.getFullYear () - 1) + ',' + date.getMonth () + ',' + date.getDate () + '))">&lt;</a></th><th colspan="2">' + date.getFullYear () + '</th><th><a onclick="glorya.inputType.calendar.showDate(\'' + calendar.attr ('name') + '\',new Date(' + (date.getFullYear () + 1) + ',' + date.getMonth () + ',' + date.getDate () + '))">&gt;</a></th>');
		// create the calendar rows showing the dates
		var chart = '';
		chart = '<tr class="labels"><td class="weeknr"><span>00</span></td><td><span>' + cc.days[0] + '</span></td><td><span>' + cc.days[1] + '</span></td><td><span>' + cc.days[2] + '</span></td><td><span>' + cc.days[3] + '</span></td><td><span>' + cc.days[4] + '</span></td><td class="weekend"><span>' + cc.days[5] + '</span></td><td class="weekend"><span>' + cc.days[6] + '</span></td></tr>';
		// find monday on the first of this month, or just first monday in the previous month
		var fd = date;
		var today = new Date ();
		while (!(fd.getDay () == 1 && (date.getDate () == 1 || date.getMonth () != fd.getMonth ()))) {
			fd = new Date (fd.getFullYear (), fd.getMonth (), fd.getDate () - 1);
		}
		// print
		for (var i = 0; (i < 2 || date.getMonth () == new Date (fd.getFullYear (), fd.getMonth (), (fd.getDate () + (i * 7) - 1)).getMonth ()); i++) {
			chart += '<tr>';
			for (var j = 0; j < 8; j++) {
				var d = new Date (fd.getFullYear (), fd.getMonth (), fd.getDate () + (i * 7) + j - 1);
				var cls = (j == 0 ? 'weeknr' : (j > 5 ? 'weekend' : '') + (isSelected && d.getFullYear () + '-' + d.getMonth () + '-' + d.getDate () == date.getFullYear () + '-' + date.getMonth () + '-' + date.getDate () ? ' selected' : '') + (d.getFullYear () + '-' + d.getMonth () + '-' + d.getDate () == today.getFullYear () + '-' + today.getMonth () + '-' + today.getDate () ? ' today' : ''));
				if (j > 0 && d.getMonth () != date.getMonth ()) {
					cls += ' outofmonth';
				}
				if (j == 0) {
					// the weeknr label
					chart += '<td' + (cls ? ' class="' + cls + '"' : '') + '><span>' + (new Date (fd.getFullYear (), fd.getMonth (), fd.getDate () + (i * 7) + j + 1).getWeekNr ()) + '</span></td>';
				}
				else {
					// a selectable day
					chart += '<td id="' + name + '_' + d.getFullYear () + ((d.getMonth () < 9 ? '0' : '') + (d.getMonth () + 1)) + ((d.getDate () < 10 ? '0' : '') + d.getDate ()) + '" ' + (cls ? ' class="' + cls + '"' : '') + ' onclick="glorya.inputType.dateTimeField.setDate (\'' + calendar.attr ('name') + '\', new Date (\'' + d.toDateString () + '\'), true);"><span>' + d.getDate () + '</span></td>';
				}
			}
			chart += '</tr>';
		}
		$('tbody', calendar).html (chart);
		// check onShowDateRegistry
		if (this.onShowDateRegistry[name]) {
			for (var i = 0; i < this.onShowDateRegistry[name].length; i++) {
				eval (this.onShowDateRegistry[name][i]);
			}
		}
	},
	onOpen: function (name, code) {
		if (!this.onOpenRegistry[name]) {
			this.onOpenRegistry[name] = [];
		}
		this.onOpenRegistry[name][this.onOpenRegistry[name].length] = code;
	},
	onShowDate: function (name, code) {
		if (!this.onShowDateRegistry[name]) {
			this.onShowDateRegistry[name] = [];
		}
		this.onShowDateRegistry[name][this.onShowDateRegistry[name].length] = code;
	},
	// is called when opening a calender with config: timespan_unique=1
	getTimespans: function (tableUID, columnName, componentName, date) {
		glorya.json.call ('admin/' + glorya.adminLanguage + '/__user_1/gateway/',
				{ module: 'gettimespans', table: tableUID, column: columnName, date: date.getUnix () },
				function (c) {
					glorya.json.evalHeader (c);
					if (c.timespans && c.timespans.length > 0) {
						for (var i = 0; i < c.timespans.length; i++) {
							// ids of td are name_yyyymmdd
							for (var ts = (1 * c.timespans[i].timespan_from); ts <= 1 * (c.timespans[i].timespan_to); ts += (24 * 60 * 60)) {
								var d = new Date (ts * 1000);
								var id = componentName + '_' + d.getFullYear () + ((d.getMonth () < 9 ? '0' : '') + (d.getMonth () + 1)) + ((d.getDate () < 10 ? '0' : '') + d.getDate ());
								$('#' + id).addClass ('timespanunique' + ($('#form_id').val () == c.timespans[i].id ? 'current' : ''));
							}
						}
					}
					glorya.json.evalFooter (c);
				}
		);
	}
};

