
var Environment =
{
	shopUrl: "http://www.qoc.de",
	resourcesUrl: "http://resources.qoc.de",
	xiSwfUrl: "http://resources.qoc.de/libs/swfobject/swf/expressInstall.swf"
};
(function($){

$.fn.delay = function(time, callback){
    // Empty function:
    $.fx.step.delay = function(){};
    // Return meaningless animation, (will be added to queue)
    return this.animate({delay:1}, time, callback);
}

})(jQuery);


$.fn.selectedIndex = function(value)
{
	return this.each(
			function()
			{
				this.selectedIndex = value;
			}
		);
};



var StringUtils = (function()
{
	var htmlReplaceMap = {
		'&': '&amp;',
		'\"': '&quot;',
		'\'': '&#39;',
		'<': '&lt;',
		'>': '&gt;',
		'\r\n': '<br/>\n',
		'\r': '<br/>\n',
		'\n': '<br/>\n',
		'\t': '<span style="white-space: pre-wrap;">\t</span>'
	};
	
	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
	
	return {
		repeat: repeat,
		trim: trim,
		htmlchars: htmlchars,
		htmlcharsNl2br: htmlcharsNl2br,
		htmlify: htmlify,
		escapeForCssAttributeSelector: escapeForCssAttributeSelector,
		toDecimal: toDecimal,
		parseDecimal: parseDecimal,
		toCurrency: toCurrency,
		parseCurrency: parseCurrency,
		evalJsonString: evalJsonString,
		encode64: encode64,
		decode64: decode64,
		utf8_encode: utf8_encode,
		utf8_decode: utf8_decode,
		gup: gup
	};
	
	function gup( name )
	{
		name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
		var regexS = "[\\?&]"+name+"=([^&#]*)";
		var regex = new RegExp( regexS );
		var results = regex.exec( window.location.href );
		if( results == null )
			return "";
		else
			return results[1];
	}
	
	function repeat(str, count)
	{
		return new Array(count + 1).join(str);
	}
	
	function trim(str)
	{
		return $.trim(str);
		//return str.match(/^\s*(.*?)\s*$/)[1];
	}
	
	function htmlchars(str)
	{
		return str.replace(/&|"|'|<|>/g, _htmlReplace); // ");
	}
	
	function htmlcharsNl2br(str)
	{
		return str.replace(/&|"|'|<|>|\r\n|\r|\n/g, _htmlReplace); // ");
	}
	
	function htmlify(str)
	{
		return str.replace(/&|"|'|<|>|\r\n|\r|\n|\t/g, _htmlReplace); // ");
	}

	function _htmlReplace(str)
	{
		return htmlReplaceMap[str];
	}
	
	function escapeForCssAttributeSelector(str)
	{
		return str.replace(/(\W)/g, '\\$1');
	}

	function toCurrency(num) {
		
		var match = parseFloat(num).toFixed(2).match(/^(-?)(\d+)\.(\d+)$/);
		if (!match) return '0,00';
		var sign = match[1];
		var euro = match[2];
		var cents = match[3];
		
		var i = euro.length % 3;
		var r = sign + euro.substr(0, i);
		for (; i < euro.length; i += 3)
		{
			if (i != 0) r += '.';
			r += euro.substr(i, 3);
		}
		r += ',';
		r += cents;
		return r;
		
		
		
		
//		num = num.toString().replace(/\,/g,'.');
//		
//		if(isNaN(num) || num == 0.00){
//			return "0,00";
//		}
//	        
//		num = parseFloat(num).toFixed(2);
//		var cents = Math.abs(parseInt((num * 100)%100));
//		num = num > 0 ? Math.floor(num).toString() : Math.ceil(num).toString();
//		var prefix = num>0?'':'-';
//		num = Math.abs(num);
//		
//		if(cents<10){
//			cents = "0" + cents;
//		}
//		
//		for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++){
//			num = num.substring(0,num.length-(4*i+3))+'.'+
//			num.substring(num.length-(4*i+3));
//		}
//		return prefix + num + ',' + cents;
	}

/**
	function toCurrency(number)
	{
		var cent = Math.round(number * 100);
		var remainder = cent % 100;
		var s = '' + ((cent - remainder) / 100) + ',';
		remainder = Math.abs(remainder);
		return s + (remainder < 10 ? '0' + remainder : '' + remainder);
	}
*/
	
	function parseCurrency(string)
	{
		var match = string.match(/^([+-]?)(\d\d?\d?(?:(?:\.\d\d\d)*|(?:\d\d\d)*))(?:,(\d\d))?$/);
		if (!match) return null;
		return +(match[1] + match[2].replace(/\./, '') + (match[3] ? '.' + match[3] : ''));
	}
	
	function parseDecimal(string)
	{
		return Number(string.replace('.', '').replace(',', '.'));
	}
	
	function toDecimal(number,precision)
	{
		return number.toFixed(precision).replace('.', ',');
		
//		var re = new RegExp('/^(\d+)(\.(\d{'+precision+'}))?$/');
//		var match = number.toString().match(re);
//		var str = match[1]+','+match[3];
//		
//		return str;
		
//		
//		var cent = Math.round(number * Math.pow(10,precision));
//		var remainder = cent % Math.pow(10,precision);
//		var s = '' + ((cent - remainder) / Math.pow(10,precision)) + ',';
//		remainder = Math.abs(remainder);
//		return s + (remainder < 10 ? '0' + remainder : '' + remainder);
	}
	
//	function parseDecimal(string,precision)
//	{
//		var match = string.match(/^([+-]?)(\d\d?\d?(?:(?:\.\d\d\d)*|(?:\d\d\d)*))(?:,(\d\d))?$/);
//		if (!match) return null;
//		return +(match[1] + match[2].replace(/\./, '') + (match[3] ? '.' + match[3] : ''));
//	}
	
	function evalJsonString(string)
	{
		var json = null;
		try
		{
			json = eval('(' + string + ')');
		}
		catch (error)
		{
		}
		return json;
	}

	
	// This code was written by Tyler Akins and has been placed in the
	// public domain.  It would be nice if you left this header intact.
	// Base64 code from Tyler Akins -- http://rumkin.com
	
	function encode64(input) {
		var output = "";
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
	
		do {
			chr1 = input.charCodeAt(i++);
	      chr2 = input.charCodeAt(i++);
	      chr3 = input.charCodeAt(i++);
	
	      enc1 = chr1 >> 2;
	      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
	      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
	      enc4 = chr3 & 63;
	
	      if (isNaN(chr2)) {
	         enc3 = enc4 = 64;
	      } else if (isNaN(chr3)) {
	         enc4 = 64;
	      }
	
	      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + 
	         keyStr.charAt(enc3) + keyStr.charAt(enc4);
	   } while (i < input.length);
	   
	   return output;
	}
	
	function decode64(input) {
	   var output = "";
	   var chr1, chr2, chr3;
	   var enc1, enc2, enc3, enc4;
	   var i = 0;
	
	   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
	   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
	
	   do {
	      enc1 = keyStr.indexOf(input.charAt(i++));
	      enc2 = keyStr.indexOf(input.charAt(i++));
	      enc3 = keyStr.indexOf(input.charAt(i++));
	      enc4 = keyStr.indexOf(input.charAt(i++));
	
	      chr1 = (enc1 << 2) | (enc2 >> 4);
	      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
	      chr3 = ((enc3 & 3) << 6) | enc4;
	
	      output = output + String.fromCharCode(chr1);
	
	      if (enc3 != 64) {
	         output = output + String.fromCharCode(chr2);
	      }
	      if (enc4 != 64) {
	         output = output + String.fromCharCode(chr3);
	      }
	   } while (i < input.length);
	
		//FIXME small hack
	   return utf8_decode(output);
	}
	
	// public method for url encoding
	function utf8_encode(string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	}
 
	// public method for url decoding
	function utf8_decode(utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
	
})();



/**
 * Timer Klasse
 *
 * Erleichtert die Arbeit mit Timeouts oder Intervallen.
 *
 * Siehe kru.timer.js um den Timer als jQuery UI Komponente zu benutzen.
 *
 */


function Timer(callback, delay, numTicks)
{
	if (callback == undefined) callback = null;
	if (delay == undefined) delay = 1000;
	if (numTicks == undefined) numTicks = 1;
	
	this._callback = callback;
	this._delay = delay;
	this._numTicks = numTicks;
	this._tickCount = 0;
	this._timerHandle = null;
	this._startTime = 0;
	var self = this;
	this._onTickDelegate = function() { self._onTick(); };
}

//Stoppt den Timer
Timer.prototype.stop = function()
{
	if (this._timerHandle !== null)
	{
		if (this._numTicks != 1)
		{
			clearInterval(this._timerHandle);
		}
		else if (this._tickCount == 0)
		{
			clearTimeout(this._timerHandle);
		}
		this._timerHandle = null;
	}
};

// Startet den Timer
Timer.prototype.start = function(callback, delay, numTicks)
{
	if (callback == undefined) callback = null;
	if (delay == undefined) delay = -1;
	if (numTicks == undefined) numTicks = -1;
	
	this.stop();
	
	if (callback == null && (callback = this._callback) == null)
	{
		throw new Error('Timer callback ist not set.');
	}
	if (delay < 0 && (delay = this._delay) < 0)
	{
		throw new Error('Timer delay ist not set.');
	}
	if (numTicks < 0 && (numTicks = this._numTicks) < 0)
	{
		throw new Error('Number of ticks is not set.');
	}
	
	this._callback = callback;
	this._delay = delay;
	this._numTicks = numTicks;
	this._tickCount = 0;
	this._startTime = new Date().getTime();
	
	if (numTicks != 1)
	{
		this._timerHandle = setInterval(this._onTickDelegate, delay);
	}
	else
	{
		this._timerHandle = setTimeout(this._onTickDelegate, delay);
	}
	
};

Timer.prototype._onTick = function()
{
	this._tickCount += 1;
	if (this._numTicks != 0 && this._tickCount == this._numTicks)
	{
		this.stop();
	}
	
	this._callback.call(window, this);
};

// Gibt die Anzahl Ticks zurück
Timer.prototype.getTickCount = function()
{
	return this._tickCount;
};

Timer.prototype.getStartTime = function()
{
	return this._startTime;
};

Timer.prototype.getDelay = function()
{
	return this._delay;
};

Timer.prototype.getNumTicks = function()
{
	return this._numTicks;
};



// Ajax-Requests vorkonfigurieren
$.ajaxSetup(
	{
		cache: false, // Cache umgehen
		dataType: 'json', // wir möchten Antworten immer als JSON empfangen
		type: 'POST' // weil POST schöner als GET ist
	}
);

// Normalerweise fängt der Debugger den größten Teil von serverseitigen Fehlern.
// Für HTTP-Fehler oder fatale PHP-Fehler können wir leider nichts machen, als
// eine penetrante MessageBox anzuzeigen :P
$(document).bind(
	'ajaxError',
	function (event, xmlHttpRequest, ajaxOptions, thrownError)
	{
		//if (!ajaxOptions.error)
		//{
			alert('Es konnten keine Daten im JSON-Format vom Server angefragt werden!\n' + xmlHttpRequest.responseText);
		//}
	}
);

//die ensureSingleElement()-Funktion stellt sicher, dass ein jQuery-Objekt genau ein DOM-Element enthält.
$.fn.ensureSingleElement = function()
{
	if (this.length != 1 || this[0] == null)
	{
		var msg = 'Expected a single dom element in this jQuery object. Selector: ' + this.selector;
		alert(msg);
		throw new Error(msg);
	}
	return this;
};


$.fn.jsElProp = function(name, value)
{
	if (value == undefined)
	{
		return this[0] && this[0][name];
	}
	return this.each(function()
	{
		//alert(''+this+' '+name+' = '+value);
		this[name] = value;
	});
};


// Sicherstellen, dass der $.kru-Namespace existiert, damit wir HIER schon statische Hilfsmethoden
// hinzufügen können. Normalerweise wird dieser Namespace von der UI automatisch mit dem ersten
// $.widget("kru.meincontrol", ...) angelegt.
if ($.kru == undefined)	$.kru = {};

/*
 * Hilfsfunktion, die aus einer "Parametervariable" einen Hash liefert.
 * Eine "Parametervariable" kann ein String oder ein Objekt sein, oder ein Array aus beiden.
 * 
 * Diese Methode wird "global" definiert, damit alle Komponenten davon Gebrauch machen
 * können, um die Datenübergabe an Funktionen einheitlich und flexibel zu machen.
 * 
 *	$.kru.getHashFromMixedParameters(null) == {}
 *	$.kru.getHashFromMixedParameters(undefined) == {}
 *	$.kru.getHashFromMixedParameters('a=1&b=2') == {a:1,b:2}
 *	$.kru.getHashFromMixedParameters({m:123}) == {m:123}
 *	$.kru.getHashFromMixedParameters(['a=1&b=2', {m:123}]) == {a:1,b:2,m:123}
 */

$.kru.getHashFromMixedParameters = function(parameters)
{
	var hash = {};
	if (parameters != undefined && parameters != null) // ein Vergleich hätte genügt, da dummerweise? in JS null == undefined ist
	{
		if (!$.isArray(parameters)) parameters = [parameters];
		for (var i = 0, len = parameters.length; i < len; ++i)
		{
			var object = parameters[i];
			if (typeof object == 'string')
			{
				if (object.length != 0)
				{
					var pairs = object.split('&');
					for (var j = 0; j < pairs.length; ++j)
					{
						var pair = pairs[j].split('=');
						if (pair.length != 2) throw new Error('Could not split query string.');
						hash[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
					}
				}
			}
			else
			{
				for (var name in object)
				{
					hash[name] = String(object[name]);
				}
			}
		}
	}
	return hash;
};




/**
 * 
 * Timer-Wrapper für die jQuery UI; verwendet intern die Timer Klasse
 * 
 * Optionen des Timers:
 *	callback: Callback-Funktion, die mit jedem Tick aufgerufen werden soll.
 *		Diese Funktion wird mit dem Element (als ersten Parameter) aufgerufen,
 *		auf dem der Timer erzeugt wurde.
 *	delay: Verzögerung in ms
 *	numTicks: Anzahl Ticks, die der Timer ausführen soll; ein Wert von 0 führt
 *		den Timer endlos aus
 * 
 * 
 * Beispiel: Timer erzeugen und verwenden
 * 
 * function test()
 * {
 * 	alert('Der wievielte Aufruf des Timers? ' + $(this).timer('getTickCount'));
 * }
 * 
 * $('body')
 * 	.timer({callback: test, delay: 1000, numTicks: 4}) // erzeugt den Timer; es wird ein Options-Objekt übergeben
 * 	.timer('start'); // ruft die Methode start() auf, es wird ein String (Name der Methode) übergeben
 * 
 * 
 */

$.widget("kru.timer",
{
	// Konstruktor
	_init: function()
	{
		this._timer = new Timer();
		this._callback = null;
		var self = this;
		this._onTickDelegate = function(timer) { self._onTick(); };
	},
	
	// Wird von der UI aufgerufen, wenn das zur Komponente gehörige Element
	// aus dem DOM entfernt wird bzw die Komponente vom DOM-Element gelöst wird.
	destroy: function()
	{
		this._timer.stop();
		this._timer = null;
		$.widget.prototype.destroy.call(this);
	},
	
	// Stoppt den Timer
	stop: function()
	{
		this._timer.stop();
	},
	
	// Startet den Timer mit den aktuell gesetzten Optionen
	start: function()
	{
		var callback = this.options.callback;
		var delay = this.options.delay;
		var numTicks = this.options.numTicks;
		
		this._callback = callback;
		this._timer.start(this._onTickDelegate, delay, numTicks);
	},
	
	_onTick: function()
	{
		this._callback.call(this.element[0]);
	},
	
	// Gibt die Anzahl Ticks zurück
	getTickCount: function()
	{
		return this._timer.getTickCount();
	}
	
});

// Hier werden Methoden gelistet, die einen Wert zurückgeben
$.kru.timer.getter = ['getTickCount'];

// Standardwerte des Timers
$.kru.timer.defaults =
{
	callback: null,
	delay: 1000,
	numTicks: 0
};



var SingleFileUploader = {};

$.widget("kru.singlefileuploader", (function()
{
	var nextId = 0;
	var singleFileUploaders = [];
	
	SingleFileUploader.externalInterfaceCall = function(action, id, data)
	{
		var singleFileUploader = singleFileUploaders[id];
		if (singleFileUploader == undefined) return;
		
		singleFileUploader._externalInterfaceCall(action, data);
	};
	
	return {
		_init: function()
		{
			var o = this.options;
			if (!o.url)
			{
				throw new Error('Could not create SingleFileUploader. Please specify the url.');
			}
			
			this.id = nextId++;
			singleFileUploaders[this.id] = this;
			
			var $swf = $(document.createElement('div'))
				.attr('id', '__singleFileUploader' + this.id)
				.css(
					{
						width: o.width,
						height: o.height
					}
				)
				.appendTo(this.element);
			
			var flashVars =
			{
				id: this.id,
				browseDescription: encodeURIComponent(o.browseDescription),
				browseExtension: encodeURIComponent(o.browseExtension),
				url: encodeURIComponent(o.url),
				data: encodeURIComponent(typeof o.data == 'string' ? o.data : $.param(o.data)),
				uploadDataFieldName: encodeURIComponent(o.uploadDataFieldName),
				uploaderButtonImageUrl: encodeURIComponent(o.uploaderButtonImageUrl)
			};
			var params =
			{
				//allowScriptAccess: 'sameDomain',
				allowScriptAccess: 'always', // der Shop benutzt die Komponente mit; das swf liegt dann auf resources
				bgColor: o.bgColor,
				wmode: o.wmode
			};
			var attributes =
			{
				'class': 'lookThisIsMyFlash'
			};
		
			swfobject.embedSWF(
				o.swfUrl, $swf.attr('id'), o.width, o.height,
				"10.0.22", o.xiSwfUrl,
				flashVars, params, attributes
			);
		},
		
		destroy: function()
		{
			delete singleFileUploaders[this.id];
			this.element.find('.lookThisIsMyFlash').remove();
			$.widget.prototype.destroy.call(this);
		},
		
		_externalInterfaceCall: function(action, data)
		{
			switch (action)
			{
			case "UploaderEvent:finished":
				this._trigger('finished', null /* event */, data);
				break;
			}
		}
		
	};
	
})());



$.kru.singlefileuploader.getter = [];

$.kru.singlefileuploader.defaults = {
	browseDescription: 'Alle Dateien',
	browseExtension: '*.*',
	url: null,
	data: '',
	uploadDataFieldName: 'Filedata',
	uploaderButtonImageUrl: '/resources/images/upload-button.png',
	width: 100,
	height: 100,
	bgColor: '#000000',
	wmode: 'transparent',
	swfUrl: '/resources/swf/SingleFileUploader.swf',
	xiSwfUrl: Environment.xiSwfUrl
};


/**
Ziel des Datacontrols:

	Es wird eine verbindung zu einem PHP-seitigem Datenliefarent zur Verfügung 
	gestellt. Die Komponente auf der das Control registriert wird ist auch 
	gleich der Container für ggf. zurückgegebenes HTML.
	
	Optionen
		numPerPage
			integer[1>=x<∞]=10
			Anzahl Elemente die Pro Seite ausgegeben werden sollen 
		page
			integer[1>=x<∞]=1
			Seite die geladen wird wenn das control initialisiert wird 
		noAutoload
			boolean=false
			verhindert das automatisch die 
		url
			string[URL]
			Ressourcenlieferant bei dem die Daten angefragt werden
			string
		additional
			object
			enthält Key-Value-Paare die zusätzlich für das Datacontrol gelten sollen
		
	Zustände	
		numItems 
			Anzahl der Elemente laut dem letzten erfolgreichen Request
			Ist null falls noch kein Request durchgeführt wurde

	Events
		retrievedata
			wenn Daten abgerufen werden. Daten sollten last-chance modifiziert 
			werden können. Ladevorgang kann verhindert werden 
		retrievedatafailed
			Beim laden der Daten ist nicht das erwartete zurückgekommen oder 
			der Request ist gänzlich gescheitert
		retrievedatasucceeded
			wenn Daten abgerufen wurden wird gefeuert, bevor das DataControl 
			die Daten liest empfangene Daten können modifiziert werden Vorgang 
			kann abgebrochen werden
		retrievedataupdated
			wenn Daten abgerufen wurden wird gefeuert, nachdem das DataControl
			die empfangenen Daten verarbeitet hat	
		retrievedatacompleted
			wenn der Ajaxrequest abgeschlossen wurde unabhängig von Erfolg 
			oder Fehler
		numitemschanged
			wird ausgelöst wenn die gesamte Anzahl der Elemente sich geändert 
			hat oder zum ersten mal bekannt wird 
		pagechanged
			wenn sich die Seite geändert hat. Vorgang kann abgebrochen werden.
			wird bei einer Änderung gefeuert
		numperpagechanged
			Anzahl angezeigter Elemente pro Seite hat sich geändert Vorgang kann
			abgebrochen werden

	Methoden
		updateContents
			refreshed die aktuell angezeigte Seite
		setPage
			um eine Seite anzusteuern. Wenn die selbe Seite übergeben wird wie 
			aktuell dargestellt dann passiert nichts!  
		setNumPerPage
			Wenn die gleiche Anzahl angegeben wird wie bereit gesetzt dann 
			passiert nichts!		
		
	Funktionen
		getPage
			gibt die aktuell dargestellte Seite zurück. 
		getNumItems
			gibt die anzahl der elemente zurück. kann null sein wenn es noch 
			keine erfolgreiche anfrage gegeben hat. 
		getNumPerPage
			gibt zurück wieviele Elemente auf jeder Seite geladen werden
		getUrl
			gibt einfach die Url zum Ressourcenlieferanten zurück
			
	Listeners
		keine
*/

$.widget("kru.datacontrol",
{
	_debug: function(x){},
	_init: function()
	{
		var self = this;
		this._debug('es wird das Datacontrol auf das Element '+this.element+' initialisiert');
		// um den mehrfachlauf von requests zu verhindern
		this.runningRequest = null;
		this.queuedRequest = null;
		// startwerte
		this.destroyed = false;
		this._setData('numItems', null);
		if (this._getData('noAutoload')) return; 
		// wenn dom ready 
		$(function(){ self._loadPage(); });
	},
	destroy: function()
	{
		this._debug('es wurde das Datacontrol auf dem Element '+this.element+' zerstört')
		// falls noch ajaxrequests laufen konnen diese hiermit festellendas sie 
		// nichts mehr zu tun haben. 
		this.destroyed = true;
		
		$.widget.prototype.destroy.call(this);
	},
	_pageReceived: function(data,request)
	{
		this._debug('Datacontrol._pageReceived('+data+','+request.customData.page+')');
		// die Komponente wurde mittlerweile entladen
		if (this.destroyed) return;
		var event = $.Event();
		//event.data = data; // kann null sein
		if (
			data==null
			||
			data.numItems == undefined
			||
			(
				data.data == undefined
				&&
				data.HTML == undefined
			)	
		)
		{
			this._trigger('retrievedatafailed',event,data);
		} 
		else
		{
			this._trigger('retrievedatasucceeded', event,data);
			if (!event.isDefaultPrevented())
			{
				// die daten verarbeiten
				if (data.numItems != this._getData('numItems'))
				{
					var data2 = {oldNumItems : this._getData('numItems')};
					this._setData('numItems', data.numItems);
					this._trigger('numitemschanged', 0,	data2);
				}
				if (data.HTML!=undefined) this.element.html(data.HTML);
				this._trigger('retrievedataupdated', event,data);
			}
		}
		this._trigger('retrievedatacompleted', event,data);
		this.runningRequest = null;
		// prüfen ob nicht bereits ein neues Request ausgeführt werden soll
		if (this.queuedRequest)
		{
			var queuedRequest = this.queuedRequest;
			this.queuedRequest = null;
			this._internalLoad(queuedRequest);
		}
	},
	_internalLoad: function(request)
	{
  		this._debug('Datacontrol._internalLoad('+request.customData.page+')');
  		var event = $.Event();
  		this._trigger('retrievedata', event, request);
  		if (event.isDefaultPrevented()) return;
		this.runningRequest = request;
		$.ajax(request);
	},
	_loadPage: function(parameters)
	{
		if (parameters== undefined)parameters = {};
		this._debug('Datacontrol._loadpage()');
		var self = this;
		var submitData = $.kru.getHashFromMixedParameters([parameters,this._getData('additional')]);
		submitData.page = this.getPage();
		submitData.numPerPage = this.getNumPerPage();
		var request = 
		{
			url: this.getUrl(),
			data: submitData, 
			customData: submitData, 
			success: function(data, textStatus){ self._pageReceived(data,this); },
			error: function(XMLHttpRequest, textStatus, errorThrown){ self._pageReceived(null,this); }
		};
		if (this.runningRequest != null)this.queuedRequest = request;else this._internalLoad(request);
	},
	updateContents: function(parameters)
	{
		this._debug('Datacontrol.updateContens()');
		this._loadPage($.kru.getHashFromMixedParameters(parameters));
	},
	getPage: function() { return this._getData('page'); },
	setPage: function(newpage,parameters) 
	{
		this._debug('Datacontrol.setPage('+newpage+')');
		if (newpage == this._getData('page')) return; 
		var data = {oldpage : this._getData('page')};
		this._setData('page',newpage); 
		var event = $.Event();
		this._trigger('pagechanged', event, data);
		if (event.isDefaultPrevented()) return;
		this.updateContents(parameters);
	},
	getNumItems: function () { return this._getData('numItems'); },
	getNumPerPage: function() { return this._getData('numPerPage'); },
	setNumPerPage: function(newNumPerPage)
	{
		this._debug('Datacontrol.setNumPerPage('+newNumPerPage+')');
		newNumPerPage = Math.max(1,newNumPerPage);
		if (newNumPerPage == this.getNumPerPage())return ;
		var event = $.Event();
		var data = {oldNumPerPage : this._getData('numPerPage')};
		this._setData('numPerPage', newNumPerPage);
		this._trigger('numperpagechanged',event,data);
		if (event.isDefaultPrevented()) return;
		this.updateContents();
	},
	getUrl: function () { return this._getData('url'); }
});
$.kru.datacontrol.getter = ['getNumPerPage','getNumItems','getPage','getUrl'];
$.kru.datacontrol.defaults = 
{ 
	numPerPage	: 10, 
	page		: 1,
	noAutoload	: false,
	url			: null,
	additional	: null
};

/**
Ziel des Ajaxanimation

	Die Komponente auf der das Control registriert wird abgelauscht nach den 
	Signalen des Datacontrols retrievedata und retrievedatacompleted. Wärend
	dieser Beiden Signale wird der Bereich der Komponente mit einem Lade-Overlay
	überlegt. 
	
	Optionen
		keine
	
	Zustände
		keine
		
	Events
		keine
		
	Methoden
		keine
	
	Funktionen
		keine
*/

$.widget("kru.ajaxanimation", 
{
	_init: function()
	{
		this.$markup = null;
	
		var self = this;
		this.element.bind(
			this._appendEventNamespace(this._getData('startEvents')),
			function(evt, data) { self._displayHandler(evt, data); });
		this.element.bind(
			this._appendEventNamespace(this._getData('endEvents')),
			function(evt, data) { self._removeHandler(evt, data); });
	},
	
	_appendEventNamespace: function(eventString)
	{
		eventString = $.trim(eventString);
		if (eventString.length != 0)
		{
			var namespace = '.' + this.widgetName;
			eventString.split(/\s+/).join(namespace + ' ') + namespace;
		}
		return eventString;
	},
	
	destroy: function()
	{
		this.element.unbind('.' + this.widgetName);
		this._removeHandler();
	},
	
	_displayHandler: function()
	{
		if (this.$markup != null) return;
		var anchor = this.element.offsetParent();
		var position = this.element.position(anchor);

		var width;
		var getDimensionFrom = this.element;
		while (getDimensionFrom){
			width = getDimensionFrom.innerWidth();
			if (width > 0) break;
			getDimensionFrom = getDimensionFrom.parent();
		}

		var height;
		var getDimensionFrom = this.element;
		while (getDimensionFrom){
			height = getDimensionFrom.innerHeight();
			if (height > 0) break;	
			getDimensionFrom = getDimensionFrom.parent();
		}
		
		var html =
			'<div class="ajaxanimation" style="'+
				'position:absolute;'+
				'background-color:black;'+
				'top:'+position.top+'px;'+
				'left:'+position.left+'px;'+
				'width:'+width+'px;'+
				'height:'+height+'px;'+
				'background-image:url(\'/resources/images/ajax-loader.gif\');'+
				'background-repeat:no-repeat;'+
				'background-position: center center'+
			'"></div>';
		
		this.$markup = $(html).prependTo(anchor).css('opacity',0.8);
	},
	
	_removeHandler: function()
	{
		if (this.$markup != null)
		{
			this.$markup.remove();
			this.$markup = null;
		}
	}
});

$.kru.ajaxanimation.getter = [];

$.kru.ajaxanimation.defaults = {
	startEvents	: 'datacontrolretrievedata',
	endEvents	: 'datacontrolretrievedatacompleted'
};

/**
Ziel des Browsecontrols:
	
	Die Komponente auf der das Control registriert wird mit elementen zum 
	Blättern befüllt. Sie reagiert auf events die auf dieses Element losgelassen 
	werden.
	Wenn geblättert werden soll dann wird dies auch per Events mitgeteilt
	
	Optionen
		connectTo
			DomElement
			Das Element welches das Datacontrol enthält bzw enthalten wird
		mode 
			string['logaritmisch'|'linear'|'delphi']
			Modus wie die entfernten seiten ermittelt werden
			linear
				traditionelle liste mit inc 1 zu jedem Blatt
			logaritmisch
				incrementiert logarithmisch die Blätter
			delphi
				links und rechts den Browserange zu füllen und eine über den 
				gesamten Bereich gehende liste präsentieren
			
		browseRange
			integer[1>=x<=∞]
			Wie viele Element zum Blättern links und rechts von der aktuellen 
			Seite zu zeichen sind, vorausgesetzt es gibt diese Seiten auch
		logBase
			integer[2>=x<=∞]
			beistimmt bei mode == 'logaritmisch' die Schrittweite
		labels
			Callbackfunction welche verwendet werden kann um statt der 
			Seitenzahlen z.B. Monate zu schreiben
			
		
	Zustände
		pages
			merkt sich die aktuell dargestellten Seiten
			
	Events
		keine
		
	Methoden 
		keine
		
	Funktionen
		keine
			
	Listeners (fest verdrahtet)
		numitemschanged
			erwartet als daten ein Object das wenigstens folgende Informationen 
			enthält: {numItems:a, numPerPage:b, page:c, newNumItems:d}
		numperpagechanged
			erwartet als daten ein Object das wenigstens folgende Informationen 
			enthält: {numItems:a, numPerPage:b, page:c, newNumPerPage:d}
		pagechanged
			erwartet als daten ein Object das wenigstens folgende Informationen 
			enthält: {numItems:a, numPerPage:b, page:c, newPage:d}
*/

$.widget("kru.browsecontrol",function(){
	var $blattTemplate = $('<div class="blatt"></div>');
	
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			this.pages = [];
			this.blaetter = [];
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			connectTo.bind('datacontrolnumitemschanged', function(evt,data){ self._numItemsChangedHandler(evt, data); });
			connectTo.bind('datacontrolnumperpagechanged', function(evt,data){ self._numPerPageChangedHandler(evt, data); });
			connectTo.bind('datacontrolpagechanged', function(evt,data){ self._pageChangedHandler(evt, data); });
			
			// leeren
			this.element.empty();
			this.element.addClass('browsecontrol');
			// Elemente
			var element = $blattTemplate.clone().text('<<');
			this.element.append(element);
			element.bind('click', function(){ self._setPageFirst();});
			
			element = $blattTemplate.clone().text('<');
			this.element.append(element);
			element.bind('click', function(){ self._setPagePrevious();});
			
			// anhand des Broserange die elemente vorerzeugen
			var browseRange = this._getData('browseRange');
			for(var i=0; i<=browseRange*2+1;i++){
				element = $blattTemplate.clone().text('');//
				this.element.append(element);
				this.blaetter.push(element);
				element.bind('click', {elementIndex:i}, function(event){ self._setPageHandler(event);});
			}
			
			element = $blattTemplate.clone().text('>');
			this.element.append(element);
			element.bind('click', function(){ self._setPageNext();});
			
			element = $blattTemplate.clone().text('>>');
			this.element.append(element);
			element.bind('click', function(){ self._setPageLast();});
			
			this.element.append('<div class="clear"/>');
		},
		destroy: function()
		{
			this.element.removeClass('browsecontrol');
			this.element.empty();
			
			$.widget.prototype.destroy.call(this);
		},
		_getMaxPage : function()
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			var numItems = connectTo.datacontrol('getNumItems');
			var numPerPage = connectTo.datacontrol('getNumPerPage');
			return Math.max(1,Math.ceil(numItems/numPerPage));
		},
		
		_setPageHandler : function(evt)
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			connectTo.datacontrol('setPage',this.pages[evt.data.elementIndex]);
		},
		
		_setPageFirst : function(evt)
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			connectTo.datacontrol('setPage',1);
		},
		_setPagePrevious : function(evt)
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			connectTo.datacontrol('setPage',Math.max(1,connectTo.datacontrol('getPage')-1));
		},
		_setPageNext : function(evt)
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			var maxPage = this._getMaxPage();
			
			connectTo.datacontrol('setPage', Math.min(maxPage,connectTo.datacontrol('getPage')+1));
		},
		_setPageLast : function(evt)
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			var maxPage = this._getMaxPage();
			connectTo.datacontrol('setPage', maxPage);
		},
		_setPages : function()
		{
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			var page = connectTo.datacontrol('getPage');
			this.pages = this._pagesToHave();
			
			if (typeof(this._getData('labels'))=='function'){
				labels = this._getData('labels');
			}else{
				labels = null;
			}
			
			for(var i = 0 , laenge = this.blaetter.length; i < laenge;i++){
				if(this.pages[i]){
					var blatt = this.blaetter[i];
					// falls eine Callbackfunction gesetzt ist <-> ansonsten einfach die Zahl
					blatt.text(labels==undefined?this.pages[i]:labels(this.pages[i]));
					blatt.css({display:'block'});
					if (page == this.pages[i]){
						blatt.addClass('active');
					}else{
						blatt.removeClass('active');
					}
				}else{
					this.blaetter[i].css({display:'none'});
				}
			}
			if (page > this.pages[this.pages.length -1]){
				this._setPageLast();
			}
		},
		_numItemsChangedHandler : function(event,data)
		{
			this._debug('browsecontrol._numItemsChangedHandler');
			this._setPages();
		},
		_numPerPageChangedHandler : function(event,data)
		{
			this._debug('browsecontrol._numPerPageChangedHandler');
			this._setPages();
		},
		_pageChangedHandler : function(event,data)
		{
			this._debug('browsecontrol._pageChangedHandler');
			this._setPages();
		},
		_pagesToHave: function (currentpage)
		{
			var pages = [];
			var connectTo = $(this._getData('connectTo')).ensureSingleElement();
			var browseRange = this._getData('browseRange');
			var logBase = this._getData('logBase');
			var mode = this._getData('mode');
			
			var page = connectTo.datacontrol('getPage');
			var maxPage = this._getMaxPage();
			switch(mode)
			{
			case 'logaritmisch':
				// um aktuelle position
				for (var i = Math.min(browseRange -1 ,Math.ceil(Math.log(page)/Math.log(logBase))) ; i>=0;i--) 
				{
					pages.push(page - Math.pow(logBase,i));
				}
				
				
				
				
				pages.push(page);
				for (var i = 0; i<= Math.min(browseRange -1,Math.ceil(Math.log(maxPage-page)/Math.log(logBase))); i++)
				{
					pages.push(page + Math.pow(logBase,i));
				}
				break;
			case 'linear':
				for (var i = browseRange + Math.max(0 , browseRange - (maxPage - (page))); i>=1;i--)
				{
					pages.push(page - i);
				}
				
				
				
				
				pages.push(page);
				for (var i = 1; i <= browseRange + Math.max(0, browseRange - (page-1));i++)
				{
					pages.push(page + i);
				}
				break;
				
			case 'delphi':
				var potentielLinks = Math.max(0,page -1);
				var potentielRechts = Math.max(0,maxPage - page);
				var vorschlagLinks = this._delphiCalcCntBlaetter(potentielLinks,browseRange);
				var vorschlagRechts = this._delphiCalcCntBlaetter(potentielRechts,browseRange);
				// wenn eine Seite nicht benötigt wird wegen anfang oder ende
				// dann darf dem anderen eine Seite dazugegeben werden
				// jetzt noch den vorschlag korrigieren damit die maximal anzuzeigenden elemente nicht überschritten werden
				var vorschlagLinksEntgueltig = Math.min(vorschlagLinks, browseRange - 1       + Math.max(0,(browseRange-1)-vorschlagRechts)   +  (vorschlagRechts==0&&potentielRechts==0?1:0));
				var vorschlagRechtsEntgueltig = Math.min(vorschlagRechts, browseRange - 1     +  Math.max(0,(browseRange-1)-vorschlagLinks)   +  (vorschlagLinks==0&&potentielLinks==0?1:0));
				// es gibt nur einen Fall wo der vorschlag scheitert und das ist 
				// bei potentiel = 1. Hier würde die Basisberechnung nicht 
				// funktionieren. Deshalb hier das Trick mit dem Math.max
				for (var i = vorschlagLinksEntgueltig; i >= 0; i--)
				{
					pages.push(page - Math.ceil(Math.pow( potentielLinks, i/Math.max(1,vorschlagLinksEntgueltig) )));
				}
				pages.push(page);
				for (var i = 0; i <= vorschlagRechtsEntgueltig; i++)
				{
					pages.push(page + Math.ceil(Math.pow(potentielRechts,i/Math.max(1,vorschlagRechtsEntgueltig) )));
				}
				// um die aktuelle Seite füllen und zwar immer auf der Schwächeren Seite  
				// arr.splice(2,0,"Lene");
				break;
			}
			// entferne Elemente die ausserhalb der möglichen Seiten sind
			for (var i = 0, temp = pages, pages = [], length = temp.length; i < length; i++){
				var cmp = temp[i]; 
				if ( cmp<= maxPage && cmp >= 1){
					pages.push(cmp);
				}
			}
			return pages;
		},
		
		_delphiCalcCntBlaetter : function(platz, browseRange)
		{
			for (var b=1; b<=Math.min(platz,browseRange*2);b++)
			{
				var max = 0;
				for(var i = 1; i<=b ; i++)
				{
					var minpages = Math.pow(i,b/i); 
					max = Math.max(minpages,max);
				}
				// dieses Maximum muss kleiner oder gleich dem verfügbaren platz sein!
				if (max>=platz)
				{
					return b-1;
				}
			}
			return b-1;
		}
		
	}
}());

$.kru.browsecontrol.getter = [];

$.kru.browsecontrol.defaults = {
	connectTo		: null,
	mode			: 'linear',
	browseRange		: 5,
	logBase			: 5,
	labels			: null
};


$.widget("kru.tablebehaviour", (function()
{
	return {
		_debug: function(x){},		
		_init: function()
		{
			var self = this;
			this.element.bind('datacontrolretrievedatacompleted.'+this.widgetName,function(evt,data){self._retrievedataHandler(evt, data); });
			// falls das control erst nach dem ersten datenholen eingebunden wurde 
			self._retrievedataHandler();
		},
		
		destroy: function()
		{
			this.element.unbind('.'+this.widgetName);
			this.element.find('tr').unbind('.'+this.widgetName);
			$.widget.prototype.destroy.call(this);
		},
		
		
		_retrievedataHandler: function()
		{
			var self = this;
			$.each(this._getData('styles'),function(i, val){
				self.element.find('>'+i).css(val);
			});
			if(this._getData('alternate'))
			{
				this.element.find('>tr:even').addClass(this.widgetName+'-even');
			}	
			if(this._getData('highlight'))
			{
				this.element.find('>tr').bind('mouseenter.'+this.widgetName,function(){$(this).addClass(self.widgetName+'-hover');} )
				this.element.find('>tr').bind('mouseleave.'+this.widgetName,function(){$(this).removeClass(self.widgetName+'-hover');} )
			}
		}
	};
})());

$.kru.tablebehaviour.getter = [];
$.kru.tablebehaviour.defaults =
{
	alternate:true,
	highlight:true,
	styles:{} //  styles:{'td':{padding:'2px'},'tr:odd':{backgroundColor:'blue'}}
};



$.widget("kru.ajaxrequest", (function()
{
	return {
		_init: function()
		{
			this.xhr = null;
		},
		
		_reset: function()
		{
			if (this.xhr != null)
			{
				this.xhr.abort();
				this.xhr = null;
			}
		},
		
		destroy: function()
		{
			this._reset();
		},
		
		load: function(ajaxOptions)
		{
			if (ajaxOptions == undefined) ajaxOptions = null;
			
			var extendedAjaxOptions = $.extend({}, this.options.ajaxOptions, ajaxOptions);
			var container = this.options.container;
			if (container != null)
			{
				var success = extendedAjaxOptions.success;
				extendedAjaxOptions.success = function(data, textStatus)
				{
					if (data.htmlContent == undefined) return;
					
					$(container).html(data.htmlContent);
					
					if (success)
					{
						success(data, textStatus);
					}
				};
			}
			
			
			this._reset();
			this.xhr = $.ajax(extendedAjaxOptions);
		}
		
	};
	
})());

$.kru.ajaxrequest.getter = [];
$.kru.ajaxrequest.defaults = {
	ajaxOptions: {},
	container: null
};



/**
 * 
 * Das AjaxRequestMixin fügt einer Klasse Methoden zum Arbeiten mit Ajax hinzu.
 * Es können unterschiedliche Requestgruppen in Auftrag gegeben werden, indem
 * die Requests mit Namen versehen werden. Falls unter einem Namen ein Request
 * bereits läuft, wird der neue Request vorgemerkt und ersetzt einen evtl schon
 * vorgemerkten Request.
 * 
 * Normalerweise sollten die folgenden Methoden in der Komponente überschrieben
 * werden. Wenn eine Methode überschrieben wurde, muss denoch die überschriebene
 * Methode von AjaxRequestMixin aufgerufen werden:
 * - _ajaxHandler(data, request)
 * - _sendRequest(request, name)
 * 
 * Außerdem muss in der _init()-Methode der Komponente die
 * _initAjaxRequestMixin()-Methode aufgerufen werden. In der destroy()-Methode
 * der Komponente muss _destroyAjaxRequestMixin() aufgerufen werden.
 * 
 */


var AjaxRequestMixin = (function()
{
	var defaultRequestName = 'default';
	
	return {
		// Initialisert das AjaxRequestMixin; muss in der _init()-Methode der
		// Komponente aufgerufen werden
		_initAjaxRequestMixin: function()
		{
			this._ajaxDestroyed = false;
			this._ajaxRunningRequest = {};
			this._ajaxQueuedRequest = {};
			
			var self = this;
			this._ajaxSuccessDelegate = function(data, textStatus)
			{
				self._ajaxResponse(data, this);
			};
			this._ajaxErrorDelegate = function(xmlHttpRequest, textStatus, errorThrown)
			{
				self._ajaxResponse(null, this);
			};
		},
		// Zerstört das AjaxRequestMixin; muss in der destroy()-Methode der
		// Komponente aufgerufen werden
		_destroyAjaxRequestMixin: function()
		{
			this._ajaxDestroyed = true;
			this._runningRequest = null;
			this._queuedRequest = null;
			this._ajaxSuccessDelegate = null;
			this._ajaxErrorDelegate = null;
		},
		// Prüft, ob momentan ein Ajaxrequest läuft
		_ajaxIsLoading: function(name)
		{
			if (name == undefined || name == null)
			{
				name = defaultRequestName;
			}
			var runningRequest = this._runningRequest[name];
			return runningRequest != undefined && runningRequest != null;
		},
		// Ruft die _ajaxHandler()-Methode auf, wenn die Komponente noch aktiv
		// ist; sollte nicht überschrieben werden
		_ajaxResponse: function(data, request)
		{
			if (!this._ajaxDestroyed)
			{
				this._ajaxHandler(data, request);
			}
		},
		// Reagiert auf eine Ajax-Anfrage; wenn überschrieben, muss diese
		// Methode von der überschreibenden Komponenten-Methode aufgerufen
		// werden
		_ajaxHandler: function(data, request)
		{
			var name = request.name;
			this._ajaxRunningRequest[name] = null;
			var queuedRequest = this._ajaxQueuedRequest[name];
			if (queuedRequest != undefined && queuedRequest != null)
			{
				this._ajaxQueuedRequest[name] = null;
				this._sendRequest(queuedRequest, name);
			}
		},
		// Nimmt ein neues Request-Objekt auf; es handelt sich dabei um das
		// Options-Objekt der $.ajax()-Funktion
		_loadAjax: function(request, name)
		{
			if (name == undefined || name == null)
			{
				name = defaultRequestName;
			}
			var runningRequest = this._runningRequest[name];
			if (runningRequest == undefined || runningRequest == null)
			{
				this._sendRequest(request, name);
			}
			else
			{
				this._queuedRequest[name] = request;
			}
		},
		// Sendet einen Request ab; wenn überschrieben, muss diese Methode von
		// der überschreibenden Komponenten-Methode aufgerufen werden
		_sendRequest: function(request, name)
		{
			request.name = name;
			request.success = this._ajaxSuccessDelegate;
			request.error = this._ajaxErrorDelegate;
			this._runningRequest[name] = request;
			$.ajax(request);
		}
		
	};
})();



/**
 * Hauptgrund für die Existenz dieser Klasse ist, damit nicht mehr als nötig 
 * die $.httpData()-Funktion aufgerufen wird, denn die globalen Eventhandler
 * müssen sich ihr "data"-Objekt selbst erzeugen.
 * 
 * Ein weiterer Vorteil ist, dass auch gefakte Ajax-Request-Antworten behandelt
 * werden können, z.B. wenn der Server die JSON-Antwort an ein Flash schickt.
 */

var AjaxHook = (function()
{
	var callbacks = [];
	
	$(document).bind('ajaxSuccess', ajaxSuccessHandler);
	
	return {
		registerCallback: registerCallback,
		inject: inject
	};
	
	// Fügt eine Callback-Funktion hinzu, die bei eintreffenden Ajax-Antworten
	// benachrichtigt werden soll.
	function registerCallback(callback)
	{
		callbacks.push(callback);
	}
	
	function ajaxSuccessHandler(event, xmlHttpRequest, ajaxOptions)
	{
		var data = null;
		try
		{
			data = $.httpData(xmlHttpRequest, ajaxOptions.dataType, ajaxOptions);
		}
		catch (error)
		{
		}
		if (data == null) return;
		
		callCallbacks(data,ajaxOptions);
	}
	
	//function callCallbacks(json)
	function callCallbacks(json,ajaxOptions)
	{
		for (var i = 0, len = callbacks.length; i < len; ++i)
		{
			callbacks[i].call(ajaxOptions , json, "success");
		}
	}
	
	// Ruft alle registrierten Callbacks zur Behandlung der übergebenen Daten
	// auf.
	function inject(data)
	{
		callCallbacks(data);
	}
	
})();



/*
 * Alle Formulare sollen mit der Eingabe-Taste abgeschickt werden können.
 * Dieses Skript umgeht auch Probleme mit dem IE.
 * http://www.thefutureoftheweb.com/blog/submit-a-form-in-ie-with-enter
 */
$(document).bind(
	'keypress',
	function(event)
	{
		if (event.keyCode == 13 && event.target.nodeName == 'INPUT')
		{
			// Mit Opera lässt sich das "keyup"-Event nicht abbrechen
			event.preventDefault();
			if ($.isReady)
			{
				$(event.target).parents('form').submit();
			}
		}
	}
);


//// Sicherstellen, dass der $.qoc-Namespace existiert, damit wir HIER schon statische Hilfsmethoden
//// hinzufügen können. Normalerweise wird dieser Namespace von der UI automatisch mit dem ersten
//// $.widget("qoc.meincontrol", ...) angelegt.
//if ($.qoc == undefined)	$.qoc = {};
//
///**
//	Hilfsfunktion um ein array unique zu machen
//	geklaut aus jquery und leicht angepasst an meine bedürfnisse 
//*/
//$.qoc.unique = function( array )
//{
//	var ret = [], done = {};
//	try
//	{
//		for ( var i = 0, length = array.length; i < length; i++ ) 
//		{
//			id = array[ i ];
//			if ( !done[ id ] ) 
//			{
//				done[ id ] = true;
//				ret.push(id );
//			}
//		}
//	} 
//	catch( e ) 
//	{
//		ret = array;
//	}
//	return ret;
//};


$.datepicker.regional['de'] = {
	clearText: 'löschen', 
	clearStatus: 'aktuelles Datum löschen',
	closeText: 'schließen', 
	closeStatus: 'ohne Änderungen schließen',
	prevText: '&#x3c;zurück', 
	prevStatus: 'letzten Monat zeigen',
	nextText: 'Vor&#x3e;', 
	nextStatus: 'nächsten Monat zeigen',
	currentText: 'heute', 
	currentStatus: '',
	monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
	monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun','Jul','Aug','Sep','Okt','Nov','Dez'],
	monthStatus: 'anderen Monat anzeigen', 
	yearStatus: 'anderes Jahr anzeigen',
	weekHeader: 'Wo', 
	weekStatus: 'Woche des Monats',
	dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
	dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
	dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
	dayStatus: 'Setze DD als ersten Wochentag', 
	dateStatus: 'Wähle D, M d',
	dateFormat: 'dd.mm.yy', 
	firstDay: 1, 
	initStatus: 'Wähle ein Datum', 
	isRTL: false
};
$.datepicker.setDefaults($.datepicker.regional['de']);



$.fn.getPositionRelative = function(a){
	var offset = {top:0,left:0};
	var a = $(a);
	var b = $(this);
	while (true){
		var t = a.get();
		t = t.concat(b.get());
		t = jQuery.unique(t);
		if (t.length==1) break;
		var _offset = b.position();
		offset.top += _offset.top
		offset.left += _offset.left
		b=$(b.parent());
	}
	return offset;
}

$.fn.getdimensions= function(){
	// ggf muss dies noch besser die vermutete Elementdimensionen ermittel (% wird zB noch falsch interpretiert)
	var $el = $(this);	
	
	var width = parseInt($el.css('width'));
	width = isNaN(width)?0:width;
	
	var height = parseInt($el.css('height'));
	height = isNaN(height)?0:height;
	
	var lineheight = parseInt($el.css('line-height'));
	lineheight = isNaN(lineheight)?0:lineheight;
	
	return {
		width : 
		(
			Math.max
			(
				width, 
				$el.width()
			) + 
			parseInt($el.css('padding-left')) + 
			parseInt($el.css('padding-right'))
		), 
		height:(
			Math.max
			(
				height, 
				$el.height(), 
				lineheight
			) + 
			parseInt($el.css('padding-top')) + 
			parseInt($el.css('padding-bottom'))
		)
	};
}



$.ui.tabs.prototype.removeTabPageById = function(tabId)
{
	var selector = '#' + tabId;
	var $tab = $(selector);
	var index;
	if ($tab.length != 0
		&& (index = this.panels.index($tab)) != -1)
	{
		this.remove(index);
	}
};

$.ui.tabs.prototype.addJson = function(title, id, ajaxOptions)
{
	var selector = '#' + id;

	// Prüfen, ob im DOM bereits ein Element mit der angegebenen ID ist.
	if ($(selector).length == 0) {
		// Tab hinzufügen
		this.add(selector, title);
	}
	// Tab aktivieren
	this.select(selector);
	// aus irgendeinem Grund muss das hier noch selbst gesetzt werden
	index = this.anchors.index(this.anchors.filter('[href$=' + selector + ']'));
	this.selected = index;
	this.options.selected = index;

	if(this._trigger('addjson')) {
		var self = this;
		var oldSuccess = ajaxOptions.success;
		
		ajaxOptions.container = selector;
		ajaxOptions.success = function(data)
		{
			var $tab = $(selector);
			// Index des Tabs zum jetzigen Zeitpunkt bestimmen 
			var index = self.panels.index($tab[0]);
			
			if (index != -1)
			{
				var ui = self._ui(self.anchors[index], self.panels[index]);
				// Der dritte Parameter ist etwas verwirrend; wird ein
				// Array übergeben, werden die einzelnen Array-Elemente
				// als Funktionsparameter an den Eventlistener weiter-
				// gegeben; wird kein Array angeben, wird der Wert als
				// einzelner Parameter an den Eventlistener
				// weitergegeben.
				self._trigger('addjsonsuccess', null, [ui,data]);
			}
		};
		
		Content.load(ajaxOptions);
	}
	
};

$.ui.tabs.prototype.addTabPage = function(tabId, title, html)
{
	var selector = '#' + tabId;
	var $tab = $(selector);
	var index;
	
	if ($tab.length != 0)
	{
		index = this.panels.index($tab[0]);
		this.remove(index);
	}
	
	index = this.lis.length;
	this.add(selector, title, index);
	this.select(index);
	$tab = $(selector);
	$tab.html(html);
};


/**
 * params ist ein Object mit den Eigenschaften
 * title	: Der Titel des dialogs
 * icon		: ein beliebiges UI-Icon 
 * display  : HTML oder Text welcher im dialog angezeigt wird
 * buttons	: wie die UI-dialog-buttons
 * height	: höhe
 * width	: breite
 * close	: closefuinction
 */
var $confirmDialogTemplate = $('<div id="dialog" title=""><span class="ui-icon" style="float:left; margin:0 7px 20px 0;"></span><p style="margin: 0 0 0 20px;"></p></div>');
confirmDialog = function (params)
{
	if (params.title == undefined)params.title = 'Modaldialog';
	if (params.icon == undefined)params.icon = 'comment';
	if (params.display == undefined)params.display = 'Hier gibt es nichts zu sehen. Weitergehen.';
	if (params.buttons == undefined)params.buttons = { Cancel: function() {	$(this).dialog('close');} }
	if (params.height == undefined)params.height = 200;
	if (params.width == undefined)params.width = 300;
	if (params.close == undefined)params.close = null;
	
	var element = $confirmDialogTemplate.clone();
	element.attr('title', params.title);
	element.find('span.ui-icon:first').addClass('ui-icon-'+params.icon);
	element.find('p:first').append(params.display);
	$('#managerFrameContentRoot').append(element);
	$(element).dialog({
		bgiframe: true,
		modal: true,
		resizable: false,
		height:params.height,
		width:params.width,
		overlay: {
			backgroundColor: '#000',
			opacity: 0.5
		},
		buttons: params.buttons,
		close:params.close
	});
};




/**
 * 
 * Methoden:
 *
 *		TODO
 * 
 * Events:
 *	-	contentpageloaded
 * 
 * 
 */


var Content = (function()
{
	var CONTENT_ROOT_SELECTOR = '#managerFrameContentRoot';
	
	var currentPageUrl = null;
	
	return {
		load: load,
		loadMenuId: loadMenuId,
		loadPage: loadPage,
		reload: reload,
		download:download
	};
	

	function idToUpperCamelCase(id)
	{
		return id.toLowerCase().replace(/(?:^|_)([a-z])/g, idToUpperCamelCaseReplace);
	}
	
	function idToUpperCamelCaseReplace(match0, match1)
	{
		return match1.toUpperCase();
	}
	
	/**
	 * Methode, die den eigentlichen Ajax-Request ausführt.
	 * 
	 * Erweiterte Eigenschaften:
	 *	container
	 *		Mit der container-Eigenschaft kann ein Container-Element angegeben
	 *		werden, in das nach erfolgreichem Laden data.htmlContent geschrieben
	 *		wird.
	 */
	function load(ajaxOptions)
	{
		ajaxOptions.__contentLoadInfo =
		{
			success: ajaxOptions.success
		};
		ajaxOptions.success = loadSuccessHandler;
		$.ajax(ajaxOptions);
	}
	
	// "Success" heißt in unserem Fall, dass der HTTP-Request erfolgreich war
	// und das die Daten als JSON interpretiert werden konnten. "Success" wird
	// aber auch aufgerufen, wenn auf Serverseite die reportError()-Methode
	// benutzt wird! Deshalb sollten alle "success"-Callbacks prüfen, ob die
	// erwarteten Daten auch wirklich angekommen sind, ansonsten sollte die
	// Funktion VERLASSEN werden (und nicht z.B. ein Defaultwert für den
	// weiteren Funktionsablauf benutzt werden).
	function loadSuccessHandler(data, textStatus)
	{
		var ajaxOptions = this;
		
		if (data.loginExpired)
		{
			Login.show();
		}
		
		
		if (ajaxOptions.container)
		{
			if (data.htmlContent != undefined)
			{
				$(ajaxOptions.container)
					.ensureSingleElement()
					.html(data.htmlContent);
			}
			else
			{
				// Nichts tun! Möglicherweise enthält ein Formularelement einen
				// ungültigen Wert und das Notification-Control soll darüber
				// erscheinen. D.h. hier wird nichts entfernt oder geändert.
			}
		}
		var success = ajaxOptions.__contentLoadInfo.success;
		if (success)
		{
			success.call(ajaxOptions, data, textStatus);
		}
	}
	
	function loadMenuId(id, ajaxOptions)
	{
		if (ajaxOptions == undefined) ajaxOptions = null;
		
		if (ajaxOptions == null)
		{
			ajaxOptions = {};
		}
		var controllerName = idToUpperCamelCase(id);
		ajaxOptions.url = '/' + controllerName;
		loadPage(ajaxOptions);
	}

	function loadPage(ajaxOptions)
	{
		ajaxOptions.__contentLoadPageInfo =
		{
			success: ajaxOptions.success
		};
		ajaxOptions.success = loadPageSuccessHandler;
		ajaxOptions.container = CONTENT_ROOT_SELECTOR;
		load(ajaxOptions);
	}
	
	function loadPageSuccessHandler(data, textStatus)
	{
		var ajaxOptions = this;
		if (data.htmlContent != undefined)
		{
			currentPageUrl = ajaxOptions.url;
			$(CONTENT_ROOT_SELECTOR).trigger('contentpageloaded');
		}
		var success = ajaxOptions.__contentLoadPageInfo.success;
		if (success)
		{
			success.call(ajaxOptions, data, textStatus);
		}
	}
	
	function reload()
	{
		if (currentPageUrl != null)
		{
			loadPage({url: currentPageUrl});
		}
	}
	
	function _download_input(data, prefix){
		var result = new Array();
		if(!prefix)prefix='';
		$.each(data,function(i,val)
		{
			name = prefix==''?i:prefix+'['+i+']';
			switch(typeof(val))
			{
				case 'string':
				case 'number':
				case 'boolean':
					var dat = document.createElement('input');
					dat.setAttribute('type','hidden');
					dat.setAttribute('name',name);
					dat.setAttribute('value',val);
					result.push(dat)
				break;
				case 'object':
				case 'array':
					result = result.concat(_download_input(val, name))
				break;
			}
		})
		return result;
	}
	
	function download(ajaxOptions)
	{
		// formular
		newform = document.createElement("form");
		newform.setAttribute('action',ajaxOptions.url);
		newform.setAttribute('method','POST');
		// daten erzeugen
		if (ajaxOptions.data){
			var data = _download_input(ajaxOptions.data);
			
			$.each(data, function(i, input){
				newform.appendChild(input);
			});
		}
		// anhängen senden und wieder entfernen
		document.body.appendChild(newform);
		newform.submit();		
		document.body.removeChild(newform);
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
})();



var Debugger = (function()
{
	
	var $frameTemplate = $(
			'<div class="debugger">'
		+		'<div class="message">'
		+		'</div>'
		+		'<div class="items">'
		+		'</div>'
		+		'<a href="#" class="close">Schließen</a>'
		+	'</div>'
		);
	
	var $itemTemplate = $(
			'<div class="item">'
		+		'<div class="info">'
		+			'<span class="call"></span>'
		+			'<span class="line-and-file">'
		+				' in line '
		+				'<span class="line"></span>'
		+				' of file '
		+				'<span class="file"></span>'
		+			'</span>'
		+		'</div>'
		+		'<div class="code"></div>'
		+	'</div>'
		);
	
	var $debugger = null;
	
	// Der Debugger hängt sich über das globale ajaxSuccess-Event an die
	// Anfragen.
	AjaxHook.registerCallback(successHandler);
	
	return {};
	
	function successHandler(data)
	{
		var xmlString = data.__debuggerXml;
		if (xmlString == undefined) return;
		
		var $xml = $.xmlDOM(xmlString);
		displayMessage($xml);
	}
	
	function destroy()
	{
		if ($debugger != null)
		{
			$debugger
				.find('.item').unbind('mouseenter mouseleave').end()
				.find('.close').unbind('click').end()
				.remove();
			$debugger = null;
		}		
	}
	
	function displayMessage($xml)
	{
		destroy();
		
		var messageHtml = '<span class="caption">Exception:</span> ' + StringUtils.htmlify($xml.find('message').text());
		var $infoSqlXml = $xml.find('info sql');
		if ($infoSqlXml.length)
		{
			messageHtml += '<br/>\n<span class="caption">Query:</span> ';
			messageHtml += StringUtils.htmlify($infoSqlXml.text());
		}
		
		var $frame = $frameTemplate.clone()
			.find('.message').html(messageHtml).end();
		var $items = $frame.find('.items');
		$xml.find('item').each(function()
		{
			var $this = $(this);
			var call = $this.find('class').text() + $this.find('type').text() + $this.find('function').text();
			var file = $this.find('file').text() || 'N/A';
			var line = $this.find('line').text() || 'N/A';
			var startLine = $this.find('startLine').text();
			var numLines = $this.find('numLines').text();
			var source = $this.find('source').text();
			var code;
			if (numLines != 0)
			{
				var skipNumLines = line - startLine;
				var regExp = new RegExp('((?:.*(?:\\r\\n|\\r|\\n)){' + skipNumLines + '}[\\x09\\x32]*)(.*)([\\S\\s]+)');
				var match = source.match(regExp);
				code = StringUtils.htmlify(match[1])
					+ '<span class="highlight">'
					+ StringUtils.htmlify(match[2])
					+ '</span>'
					+ StringUtils.htmlify(match[3]);
			}
			else
			{
				code = StringUtils.htmlify(source);
			}
			
			$itemTemplate.clone()
				.find('.line').text(line).end()
				.find('.file').text(file).end()
				.find('.call').text(call).end()
				.find('.code').html(code).hide().end()
				.appendTo($items);
		});
		$debugger = $frame
			.appendTo('body')
			.find('.item').hover(itemOverHandler, itemOutHandler).end()
			.find('.close').bind('click', closeClickHandler).end();
	}
	
	function closeClickHandler(event)
	{
		destroy();
	}
	
	function itemOverHandler(event)
	{
		$(this).children('.code').show();
	}
		
	function itemOutHandler(event)
	{
		$(this).children('.code').hide();
	}
	
})();



/**
 * Cookie class
 * @author brendel
 * example:
 * Cookie.set('hello', 'world!', 60 * 60 * 24); // 1 day
 * if(Cookie.get('hello') != null) alert('Hello ' + Cookie.get('hello'));
 */

function Cookie()
{
}

Cookie.set = function(name, value, numSeconds)
{
	var cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
	if (numSeconds != undefined && numSeconds != 0)
	{
		var expire = new Date();
		expire.setTime(expire.getTime() + numSeconds * 1000);
		cookie += ';expires=' + expire.toGMTString();
	}
	cookie += ';path=/';
	document.cookie = cookie;
};

Cookie.get = function(name)
{
	var cookies = document.cookie.split(';');
	for (var i = 0, l = cookies.length; i < l; ++i)
	{
		var cookie = cookies[i];
		var p = cookie.indexOf('=');
		if (p == -1)
		{
			continue;
		}
		var cookieName = StringUtils.trim(decodeURIComponent(cookie.substring(0, p)));
		if (cookieName == name)
		{
			var cookieValue = StringUtils.trim(decodeURIComponent(cookie.substring(p + 1)));
			return cookieValue;
		}
	}
	return null;
};

Cookie.remove = function(name)
{
	if (Cookie.get(name) === null)
	{
		return;
	}
	document.cookie = encodeURIComponent(name) + '=;expires=Thu, 01-Jan-1970 00:00:01 GMT;path=/';
};


(function ($) {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            'array': function (x) {
                var a = ['['], b, f, i, l = x.length, v;
                for (i = 0; i < l; i += 1) {
                    v = x[i];
                    f = s[typeof v];
                    if (f) {
                        v = f(v);
                        if (typeof v == 'string') {
                            if (b) {
                                a[a.length] = ',';
                            }
                            a[a.length] = v;
                            b = true;
                        }
                    }
                }
                a[a.length] = ']';
                return a.join('');
            },
            'boolean': function (x) {
                return String(x);
            },
            'null': function (x) {
                return "null";
            },
            'number': function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            'object': function (x) {
                if (x) {
                    if (x instanceof Array) {
                        return s.array(x);
                    }
                    var a = ['{'], b, f, i, v;
                    for (i in x) {
                        v = x[i];
                        f = s[typeof v];
                        if (f) {
                            v = f(v);
                            if (typeof v == 'string') {
                                if (b) {
                                    a[a.length] = ',';
                                }
                                a.push(s.string(i), ':', v);
                                b = true;
                            }
                        }
                    }
                    a[a.length] = '}';
                    return a.join('');
                }
                return 'null';
            },
            'string': function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            }
        };

	$.toJSON = function(v) {
		var f = isNaN(v) ? s[typeof v] : s['number'];
		if (f) return f(v);
	};
	
	$.parseJSON = function(v, safe) {
		if (safe === undefined) safe = $.parseJSON.safe;
		if (safe && !/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(v))
			return undefined;
		return eval('('+v+')');
	};
	
	$.parseJSON.safe = false;

})(jQuery);

/**
 * 
 * 
 */
$.widget("kru.pageload",function()
{
	return {
		_debug: function(x){},
		destroy: function()
		{
			this.element.unbind('.'+this.widgetName);
			$.widget.prototype.destroy.call(this);
		},
		_init: function()
		{
			var self = this;
			this._last = null;
			
			$('.linkajax').live('click', function(event){self._request(event)});
		},
		_request:function(event)
		{
			var self = this;
			event.preventDefault();
			source = $(event.target);
			
			var linkto = '#'; // fallback, nichts machen
			if ( source.attr('href') != undefined )
			{
				linkto = source.attr('href');
			}
			else
			{
				var found = source.extractClassString('linkajax');
				if (found)
				{
					linkto = found;
				}
			}
			if(linkto!='#'){ // 
				this._last = linkto;
				
				Content.load({
					url: linkto,
					data: {},
					success: function(response){self._response(response);}				
				});
			}
		},
		/*
		 * Ladt die bereits geöffnente Seite neu. Dient hauptsächlich dazu beim 
		 * Logout die Seite dem Status anzupassen
		 */
		reRequest:function()
		{
			var self = this;
			if (this._last != null)
			{
				Content.load({
					url: this._last,
					data: {},
					success: function(response){self._response(response);}				
				});
			}
		},
		/*
		 */
		request:function(linkto, data)
		{
			var self = this;
			this._last = linkto;
			Content.load({
				url: linkto,
				data: undefined != data?data:{},
				success: function(response){self._response(response);}				
			});
		
		},
		response : function(response)
		{
			this._response(response)
		},
		_umleitenFallsAusgeloggt : function(response)
		{
			if (response.notLoggedIn)
			{
				this.request('/Index');
			}
			return response.notLoggedIn;
		},
		_prepareThreadSaveChangepage : function()
		{
			// Dank an moderene Browser, Javascript ist jetzt gethreaded
			// deshalb muss hier das, mal langsame und mal schnelle(gecachete) 
			// laden der Bilder behandelt werden
			this._canChangePage = {
				imageLoaded : false,
				divsPrepared : false
			}
		},
		_finishedImageLoading : function()
		{
			this._canChangePage.imageLoaded = true;
			this._changepage();
		},
		_finishedDivsPrepared : function()
		{
			this._canChangePage.divsPrepared = true;
			this._changepage();
		},
		_areThreadsReady : function()
		{
			return this._canChangePage.imageLoaded && this._canChangePage.divsPrepared;
		},
		_holeBildInCache : function(response)
		{
			var self = this;
			image = new Image()
			image.onload = function(){self._finishedImageLoading();};
			image.src = response.shopbackground;
		},
		_istAntwortUngueltig : function(response)
		{
			return !( 
					response.htmlContent
					&&
					response.breadcrumb
					&&
					response.shopbackground
				);
		},
		_markiereZuEntfernendeElemente : function()
		{
			$('.content:last,.shopbackground:last').addClass('toBeRemoved');
		},		
		_uebernehmeDarzustellendenInhalt : function(response)
		{
			// mit dem htmlContent werden in vielen Fällen noch daten mitübergeben
			// damit diese den anderen Komponenten bzw auch der ggf eigenen 
			// initroutine zur verfügung steht wird aus der Response der htmlContent 
			// rausgenommen um das dem Content selbst die Variablen nochmals
			// anhängen zu können
			var $content = $(response.htmlContent);
			response.htmlContent = 'removed';
			$content.data('data',response);
			$('.content:last').after($content);
			$('.content:last').data('data',response);
		},
		_setzteHintergrundBild : function (response)
		{
			$('.shopbackground:last').after('<div class="shopbackground" style="background-image: url(\''+response.shopbackground+'\');"></div>');
		},
		_setzeBreadcrumb : function(response)
		{
			$('#menu-input > input')
				.attr('defaultValue',response.breadcrumb)
				.val(response.breadcrumb);
		},
		_response : function(response)
		{
			if (this._umleitenFallsAusgeloggt(response))return;
			if (this._istAntwortUngueltig(response))return;

			this._prepareThreadSaveChangepage();
			this._holeBildInCache(response);
			this._markiereZuEntfernendeElemente();
			this._uebernehmeDarzustellendenInhalt(response);
			this._setzteHintergrundBild(response);	
			this._setzeBreadcrumb(response);	

			this._finishedDivsPrepared();
		},
		_changepage:function(entferne)
		{
			if(!this._areThreadsReady())return;
			
			var $fadeInElements = $('.content:last,.shopbackground:last');
			var $fadeOutElements = $('.content.toBeRemoved,.shopbackground.toBeRemoved');
			
			var self = this;
			var obj = {cnt: 0};
			$fadeInElements.animate(
				{opacity: 1},
				{
					easing: 'linear',//'swing',
					duration:250,
					step: function(now, fx)
					{
						$fadeOutElements.css({opacity: 1-now }) 
					},
					complete:function(){self._cleanafterchange(entferne, obj)}
				}
			);
		},
		_cleanafterchange:function(entferne, obj)
		{
			obj.cnt++;
			if (obj.cnt == 2){
				var $fadeOutElements = $('.content.toBeRemoved,.shopbackground.toBeRemoved');
				$fadeOutElements.remove();
			}
		}
	}
}());
$.kru.pageload.getter = [];
$.kru.pageload.defaults = {};


$.widget("kru.primaryWindow",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			this.id = Math.round(Math.random()*100000);
			// alle 20 Sekunden den primären Window testen
			this.element.timer({
				delay: 5000,									
				callback: function(){self._refreshPrimaryWindow();}, 
				numTicks: 3
			});
			this.element.timer('start');
			this._refreshPrimaryWindow();
			
			$(window).unload( function () { self._removePrimaryWindow(); } );
			
			
			this.element.find('span>span.activate').bind('click',function()
			{
				self._setPrimaryWindow(true);
				$('#isNotPrimaryWindow').dialog('close');
			});
		},
		_refreshPrimaryWindow: function()
		{
			var self = this;
			// timer reset
			this.element.timer('stop');
			this.element.timer('start');
			var jetzt = new Date();
			if (!Cookie.get('primaryWindowId'))
			{
				// kein primärer Tab gesetzt, also werde ich es
				this._setPrimaryWindow(true);
			}
			else
			{
				// prüfen ob ich selbst der primäre Tab bin und es also 
				// bleiben kann
				if (Cookie.get('primaryWindowId') == this.id)
				{
					// refresh beides , keepalive
					this._setPrimaryWindow(false);
				}
				else
				{
					// Es ist zwar ein primärer Tab gesetzt, aber jetzt muss
					// geprüft werden wie lange er nicht mehr aktuell ist
					if (
						!Cookie.get('primaryWindowTime')
					)
					{
						// keine Zeit des primären Tabs gesetzt. Also werde ich es
						this._setPrimaryWindow(true);
					}
					else
					{
						// eine zeit ist vorhanden also schauen ob ich primär
						// werden darf oder nicht
						if (new Date(Cookie.get('primaryWindowTime')).getTime()+60000 <	jetzt.getTime())
						{
							// der andere Tab hat sich sehr lange nicht mehr gemeldet
							// ich darf es werden
							this._setPrimaryWindow(true);
						}
						else
						{
							// ich darf es nicht werden da der andere noch aktiv schein
							// den nutzer darauf hinweisen und anbieten dieses 
							// Fenster zu aktivieren
							this.element.dialog('open');
						}
					}
				}
			}
		},
		_removePrimaryWindow: function()
		{
			if (
				Cookie.get('primaryWindowId')
				&& 
				Cookie.get('primaryWindowId') == this.id
			){
				Cookie.remove('primaryWindowId');
				if (Cookie.get('primaryWindowTime')){Cookie.remove('primaryWindowTime');}
			}
		},
		_setPrimaryWindow: function(force)
		{
			var jetzt = new Date();
			if (
				force
				||
				(
					Cookie.get('primaryWindowTime')
					&& 
					new Date(Cookie.get('primaryWindowTime')).getTime()+20000 < jetzt.getTime() // der cookie braucht nur alle 20 sekunden aktualisiert zu werden
				)
			){
				Cookie.set('primaryWindowId', this.id);
				Cookie.set('primaryWindowTime', jetzt);
			}
		}
	}
}());
$.kru.primaryWindow.getter = [];
$.kru.primaryWindow.defaults = {};

/**
 * Verwalten den loginstatus, stellt also fest ob der nutzer Bereits eingeloggt
 * ist und ob dies das einzige Fenster ist welches der Benutzer verwendet. 
 * Ausserdem wird in regelmäßigen abständen geprüft ob der Login noch aktiv ist.
 * Alle Ajaxkommunikation wird auch geprüft ob der User noch eingeloggt ist
 * Ein Timeout 
 * 
 * 
 */
$.widget("kru.session",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			// den ajaxComplete callback einbinden um nach jeder komunikation zu 
			// prüfen ob es infos für mich gibt
			this.element.ajaxComplete(function(event,request, settings){self._ajaxComplete(event,request, settings)});
			// jede minute den loginstatus prüfen und falls drei versuche 
			// gescheitert sind braucht auch kein weiter unternommen werden
			this.element.timer({
				delay: 60000,									
				callback: function(){self._checkSession();}, 
				numTicks: 3
			});
			this.element.timer('start');
			
			
			
			this._checkSession();
		},
		destroy: function()
		{
			this.element.unbind('.'+this.widgetName);
			$.widget.prototype.destroy.call(this);
		},
		/* 
		 * Ein AjaX Request wurde abgeschlossen, ggf wurde der Nutzer 
		 * zwischenzeitlich ausgeloggt
		 */
		_ajaxComplete: function(event,request, settings)
		{
			var self = this;
			// timer reset
			this.element.timer('stop');
			this.element.timer('start');
			// daten extrahieren
			var data = $.httpData(request,settings.dataType);
			
			// auf den hasSession reagieren
			if (undefined != data.hasSession && data.hasSession == 0 && undefined != data.redirect)
			{
				window.location.href = data.redirect;
			}
			
			
			// Auf den loginstatus reagieren
			if (undefined != data.hasLogin)
			{
				switch(true)
				{
					case data.hasLogin==1 && this.element.hasClass('logged-out'):self._changeLoginStateToLoggedIn(data);break;
					case data.hasLogin==1 && this.element.hasClass('logged-in'):/* Nichts zu tun */;break;
					case data.hasLogin==0 && this.element.hasClass('logged-out'):/* Nichts zu tun */;break;
					case data.hasLogin==0 && this.element.hasClass('logged-in'):self._changeLoginStateToLoggedOut(data);event.preventDefault();break;
				}
			}
			// auf den warenkorb reagieren
			if (undefined != data.hasCart  )
			{
				if (data.hasCart == 1 && undefined != data.cartData)
				{
					$('div#shopcenter').shoppingCart('updateCart', data.cartData);
				}
				else
				{
					$('div#shopcenter').shoppingCart('hideCart');
				}
			}
		},
		
		/*
		 * erzeugt eine leere Ajaxanfrage welche den Server nicht veranlasst die 
		 * Session zu verlängern. Es wird keine weitere verarbeitung mit der 
		 * Antwort durchgeführt da die function self._ajaxComplete die Antwort 
		 * der Anfrage selbst verarbeiten kann. 
		 */
		_checkSession: function()
		{
			var self = this;
			Content.load({
				url: 'Customer/checkSession',
				data: {},
				success: function(response){/* NADA */}				
			});
		},
		enableLoginform:function()
		{
			var self = this;
			$('form.login').bind('submit',function(event){self._login(event)});
			$('[name="email"]')
			.bind
			(
				'focus',
				function(e)
				{
				 	if ($(e.target).val() == e.target.defaultValue)
				 	{
				 		$(e.target).val('');
				 	}
				}
			)
			.bind
			(
				'blur',
				function(e)
				{
				 	if ($.trim($(e.target).val()) == '')
				 	{
				 		$(e.target).val(e.target.defaultValue);
				 	}
				}
			);
			$('[name="pas[0]"],[name="pas[1]"],[name="pas[2]"],[name="pas[3]"],[name="pas[4]"]')
			.bind
			(
				'paste',
				function(e)
				{
					$(e.target).attr('maxlength', 50).val('');
					var self = e.target
					window.setTimeout(function()
					{
						var password = $.trim($(self).val())
						for(var i=0; i<password.length; i++)
						{
							$('[name="pas['+i+']"]').val(
								(/[0-9]/).test(password[i])
								?
								password[i]
								:
								''
							);
						}
						$(self).attr('maxlength', 1);
					},100);
				}
			)
			.bind
			(
				'keypress',
				function(e)
				{
					self.move=false;
					if($(e.target).val().length > 0 && !(/[0-9]/).test($(e.target).val()))
					{
						$(e.target).val('');
						return;
					}
					if(e.which >=48 && e.which <=57)
					{
						self.move=true;
						return;
					}
				}
			)
			.bind
			(
				'keydown',
				function(e)
				{
					if(e.keyCode == 37)
					{
						e.preventDefault();
						$(e.target).prev('input').not('[name="email"]').focus().select();
						e.keyCode = 0;
						return;
					}
					if(e.keyCode == 39)
					{
						e.preventDefault();
						$(e.target).next('input').focus().select();
						e.keyCode = 0;
						return;
					}
					if(e.keyCode == 8 && $(e.target).val().length == 0)
					{
						e.preventDefault();
						$(e.target).prev('input').not('[name="email"]').focus().select();
						e.keyCode = 0;					
						return;
					}	
				}
			)
			.bind
			(
				'keyup',
				function(e)
				{
					if (self.move==true)$(e.target).next('input').focus().select();
					self.move=false;
					
				}
			);
			this.errorbox =	this.element.find('div.content.loginmain > form > div.answer');
			this.errorbox.timer
			({
				delay: 10000,									
				callback: function(){self.errorbox.removeClass('ok error advice');},
				numTicks: 1
			});
			
			
			
			this.element.find('div.content.loginmain > div.lm-newcu + div.lm-newcu + div.lm-newcu.button + div.lm-newcu.button')
			.bind
			(
				'click',
				function(event)
				{
					Content.load
					({
						url: 'Customer/registerform',
						data: {email:$('[name="email"]').val()},
						success: function(response){/* NADA */}				
					});
				}
			)
			// letzten erfolgreichen loginnamen holen
			if(Cookie.get('lastLoginEmail') && 'undefined' != Cookie.get('lastLoginEmail'))
			{
				
				$('[name="email"]').val(Cookie.get('lastLoginEmail'));
				$('[name="pas[0]"]').focus();
			}
			
			$('div.content.loginmain>form.login>div.dologin').bind('click',function(event)
			{
				self._login(event);
			})
			
			
		},
		_login:function(event)
		{
			var self = this;
			event.preventDefault();
			
			// feststellen das der Loginknopf da ist
			if($('div.content.loginmain>form.login>div.dologin:visible').length == 0)
			{
				return;
			}
			$('div.content.loginmain>form.login>div.dologin').css({display:'none'});
			
			var password = '';
			for(var i=0; i<5; i++){
				password += $('[name="pas['+i+']"]').val();
			}
			if (password.length<5)
			{
				password = ''; 
			}
			
			var email = $('[name="email"]').val();
			if (email == $('[name="email"]').get(0).defaultValue)
			{
				email = ''; 
			}
			var flashPlayerVersion = swfobject.getFlashPlayerVersion();
			Content.load
			({
				url: 'Customer/login',
				data: 
				{
					email				: email,
					password			: MD5(password),
					screenwidth			: screen.width?screen.width:'n.a.',
					screenheight		: screen.height?screen.height:'n.a.',
					pixelDepth			: screen.pixelDepth?screen.pixelDepth:'n.a',
					flashPlayerVersion	: flashPlayerVersion.major + '.' + flashPlayerVersion.minor + '.' + flashPlayerVersion.release
				},
				success: function(response){self._loginSuccess(response);}				
			});
		
		},
		logout:function()
		{
			// feststellen das der Loginknopf da ist
			if($('div.content button.ausloggen:visible').length == 0)
			{
				return;
			}
			$('div.content button.ausloggen').css({display:'none'});
			
			
			var self = this;
			Content.load
			({
				url: 'Customer/logout',
				data: {},
				success: function(response){/* NADA */}
			});
		},
		_loginSuccess :function(response)
		{
			var self = this;
			this.errorbox.removeClass('ok error advice');
			this.errorbox.html(response.meldung)
			this.errorbox.addClass(response.state);
			this.errorbox.timer('stop');
			this.errorbox.timer('start');
			
			if (response.state=='ok')
			{
				Cookie.set('lastLoginEmail', $('[name="email"]').val(), 60 * 60 * 24 * 365);
				var forward = this.element.find('div.content.loginmain > form');
				forward.timer
				({
					delay: 2000,									
					callback: function(){
						//self.element.pageload('request', '/Customer');
						self.element.pageload
						(
							'request',
							'Customer',
							{loadContainer:'Customer/welcome'}
						);
						
					},
					numTicks: 1
				});
				forward.timer('start');
			}else{
				$('div.content.loginmain>form.login>div.dologin').css({display:'block'});
			}	
		},
		_changeLoginStateToLoggedIn:function(data)
		{
			this.element.removeClass('logged-out logged-in');
			this.element.addClass('logged-in');
			$('#hereLogin').css({display:'none'});
		},
		_changeLoginStateToLoggedOut:function(data)
		{
			this.element.removeClass('logged-out logged-in');
			this.element.addClass('logged-out');
			$('#hereLogin').css({display:'block'});
			if(data.explicitLogout)
			{
				this.element.pageload('request','/Login/loggedOut');
			}
			else
			{
				this.element.pageload('request','/Login');
			}
			//this.element.pageload('reRequest')
		}
		
		
	}
}());
$.kru.session.getter = [];
$.kru.session.defaults = {};

$.widget("kru.slidetable",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			var o = this.options;
			this.current = 1;
			
			if ($(o.slider).length==0)
			{
				return ;
			}
			this.anzahl = $('>tbody>tr', this.element).length
			this.max = this.anzahl - o.cnt + 1 - o.fixedStartRows - o.fixedEndRows;
			
			var value = this.max;
			var value = o.current == -1 ? this.max :  Math.max(0,Math.min(this.max, this.max - o.current));
			
			if (this.anzahl > o.cnt)
			{
				this._scrollTable(this.max);
				$(o.slider).slider({
					animate: true,
					orientation: "vertical",
					value:value,
					min: 1,
					max: this.max,
					step: 1,
					slide: function(event, ui) {self._scrollTable(ui.value);}
				})
			}
		},
		_scrollTable: function(i)
		{
			this._trigger('scroll',null,null);
			i = Math.max(0,Math.min(this.max,this.max - i)); 
			this.current = i;
			var o = this.options;
			var anzahl = $('>tbody>tr', this.element).length - o.fixedStartRows; 
			$('>tbody>tr'+(o.fixedStartRows > 0?':gt('+(o.fixedStartRows-1)+')':'') +(o.fixedEndRows > 0?':lt('+( anzahl - o.fixedEndRows )+')':'')       +':lt('+(i           )+')', this.element).css({display:'none'});
			$('>tbody>tr'+(o.fixedStartRows > 0?':gt('+(o.fixedStartRows-1)+')':'') +(o.fixedEndRows > 0?':lt('+( anzahl - o.fixedEndRows )+')':'')       +':lt('+(i + o.cnt   )+')'+(i > 0?':gt('+(i-1)+')':''), this.element).css({display:'table-row'});
			$('>tbody>tr'+(o.fixedStartRows > 0?':gt('+(o.fixedStartRows-1)+')':'') +(o.fixedEndRows > 0?':lt('+( anzahl - o.fixedEndRows )+')':'')       +':gt('+(i + o.cnt-1 )+')', this.element).css({display:'none'});
		},
		scrollUp: function()
		{
			this.current++;
			this._scrollTable(this.current)
		},
		scrollDown: function()
		{
			this.current--;
			this._scrollTable(this.current)
		},
		getsliderpos:function()
		{
			return this.current;
		}
	}
}());
$.kru.slidetable.getter = ['getsliderpos'];
$.kru.slidetable.defaults = {cnt:10,slider:null, current:-1, fixedStartRows:0, fixedEndRows:0};





/**
 * Verwaltung vom Kundenaktionen 
 * 
 */
$.widget("qoc.customer",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
		},
		
		_writeCurrency : function (field,anzeigewert,haben)
		{
			field.removeClass('H S').addClass(haben?'H':'S');
			$('>span:nth-child(1)',field).text(haben?'+':'-');
			$('>span:nth-child(2)',field).text(anzeigewert);
		},
		writeCustomeraccount : function(anzeigewert, haben)
		{
			var self = this;
			self._writeCurrency($('div.content.customer:last>div.information.customeraccount'),anzeigewert,haben);
		},
		writeCustomertokenvalue : function(anzeigewert, haben)
		{
			var self = this;
			self._writeCurrency($('div.content.customer:last>div.information.customertokens'),anzeigewert,haben);
		},
		
		changeProfileImage : function(path)
		{
			$('div.content.customer:last>div.information.customerimage').css({backgroundImage:'url("'+path+'")'});
		},
		changeProfileLogo : function(path)
		{
			$('div.content.customer:last>div.information.customerlogo').css({backgroundImage:'url("'+path+'")'});
		},
		
		enableCustomerarea:function(loadContainer)
		{
			var self = this;
			
			var data = $('div.content.customer:last').data('data');
			
			$('div.content.customer:last>div.information.customerid').text(data.customerid);
			$('div.content.customer:last>div.information.customersince').text(data.customersince);
			this.writeCustomeraccount(data.customeraccount,data.customeraccountHaben);
			this.writeCustomertokenvalue(data.customertokens,data.customertokensHaben);
			this.changeProfileImage(data.customerimage);
			this.changeProfileLogo(data.customerlogo);
			
			
			$('div.content.customer:last>div.information.customerorders').text(data.customerorders);
			//
			$('div.content.customer:last>div.container').html(data.container);
			
			// Elemente aktivieren
			
			$('div.content.customer:last>div.sub1>span').bind('click',function(event){self._sub1(event);})
			$('div.content.customer:last>div.sub2>div').bind('click',function(event){self._sub2(event);})
			
			$('div.content.customer:last>div.sub2>div').hover(
				function(){
					$(this).addClass('hover');
				},
				function(){
					$(this).removeClass('hover');
				}
			);
			
			// wenn ein bestimmter bereich gewünscht ist den laden
			if (undefined != loadContainer)
			{
				/* keine ahnung warum elemente nicht gefunden werden
				// falls dieser gewünschte bereich ein Menumunkt ist muss das menu gesetzt werden
				console.log(loadContainer);
				console.log(StringUtils.encode64(loadContainer));
				console.log($('div.content.customer:last>div.sub2>div'));
				console.log($('div.content.customer:last>div.sub2>div.load-'+StringUtils.encode64(loadContainer)));
				
				var submenu = $('div.content.customer:last>div.sub2>div.load-'+StringUtils.encode64(loadContainer));
				
				if (submenu.length > 0)
				{
					var hauptmenu = $('div.content.customer:last>div.sub1>span.menuitem-'+StringUtils.encode64(submenu.closest('div.sub2').extractClassString('sub2')));
					if (hauptmenu.length > 0)
					{
						hauptmenu.click();				
					} 
				}
				*/
				self.loadContainer(loadContainer);
			}
			else
			{
				$('div.content.customer:last>div.sub1>span.default').click();
			}	
		},
		_sub1:function(event)
		{
			var self = this;
			event.preventDefault();
			$('div.content.customer:last>div.sub1>span').removeClass('aktiv');
			$(event.target).addClass('aktiv');
			$('div.content.customer:last>div.sub2').removeClass('aktiv');
			$('div.content.customer:last>div.sub2.'+$(event.target).extractClassString('menuitem')).addClass('aktiv');
			
			$('div.content.customer:last>div.sub2.aktiv>div.default').click();
		},
		_sub2:function(event)
		{
			var self = this;
			event.preventDefault();
			$('div.content.customer:last>div.sub2.aktiv>div').removeClass('aktiv');
			$(event.target).addClass('aktiv');
			this.loadContainer($(event.target).extractClassString('load'))
		},
		loadContainer:function(load)
		{
			var self = this;
			$('div.content.customer:last>div.container').animate(
				{opacity:0},
				{
					duration:150,
					easing: 'swing',
					complete:function(){self.loadContainerStep2(load);}
				}
			);
		},
		loadContainerStep2:function(load)
		{
			var self = this;
			Content.load({
				url: load,
				data:{},
				success: function(response){
					$('div.content.customer:last>div.container').html(response.container);
					$('div.content.customer:last>div.container').animate(
						{opacity:1},
						{
							duration:200,
							easing: 'swing'
						}	
					);
				}				
			});
		}
	}
}());
$.qoc.customer.getter = [];
$.qoc.customer.defaults = {};

/**
 * Verwaltung vom Multisuchfeld 
 * 
 */
$.widget("qoc.search",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			$('#menu-search')
			.bind
			(
				'click',
				function(event)
				{
					self._search(event);
				}
			);
			
			this.presearchresult = '';
			this.selected = 0;
			
			this.element
			.timer
			({
				delay: 300,									
				callback: function(){self._autocomplete();},
				numTicks: 1
			});
			this.element
			.bind(
				'keypress',
				function(event)
				{
					if (event.keyCode == 13 && event.target.nodeName == 'INPUT')
					{
						if ($.trim($(self.element).val()) == self.text)
						{
							self._search(event);
						}
					}
				}
			)
			.bind
			(
				'focus',
				function(event)
				{
				 	if ($(event.target).val() == event.target.defaultValue)
				 	{
				 		$(event.target).val('');
				 	}
				}
			)
			.bind
			(
				'blur',
				function(event)
				{
				 	// blur lässt ein self._cancelSearch(); aufrufen 
				 	window.setTimeout(function(){self._cancelSearch(event);},500);
				}
			)
			.bind(
				'paste',
				function(event)
				{
					var text = $.trim($(self.element).val());
					if( self.presearchresult != text)
					{
						$(self.element).timer('stop');
						$(self.element).timer('start');
						self.presearchresult = text;
					}
				}
			)
			.bind(
				'keyup',
				function(event)
				{
					if(event.keyCode==27)
					{
						$('div.content').focus();						
					}
					else if(event.keyCode==38)
					{
						//event.preventDefault();
						self._moveSelectionUp();
					}
					else if(event.keyCode==40)
					{
						//event.preventDefault();
						self._moveSelectionDown();
					}
					else{
						var text = $.trim($(self.element).val());
						if( self.presearchresult != text && event.keyCode != 13)
						{
							$(self.element).timer('stop');
							$(self.element).timer('start');
							self.presearchresult = text;
						}
					}
				}
			)
			;
		},
		_cancelSearch:function(event)
		{
			
			var self = this;
			$(event.target).val(event.target.defaultValue);
			$('#searchdropdown').css({display:'none'});
			this.presearchresult = '';
		},
		_autocomplete:function()
		{
			var self = this;
			var text = $.trim($(self.element).val());
			
			
			if(text != '')
			{
				// suche laden 
				Content.load({
					url: 'Search/presearch',
					data: {
						text : text
					},
					success: function(response){
						self.text = text;
						self._presearchresult(response);
					}				
				});
			}
			else
			{
				$('#searchdropdown').css({display:'none'});
			}
		},
		_presearchresult : function(response)
		{
			var self = this;
			if (response.success && response.list)
			{
				$('#searchdropdown').css({display:'block'});
				$('#searchdropdown').html(response.list);
				$('#searchdropdown').find('>div:not(.head)')
					.bind('mouseover',function(event){
						self._select($(event.currentTarget));
					}).bind('click',function(event){
						self._select($(event.currentTarget));
						self._search(event);
					});
			}
			else
			{
				$('#searchdropdown').css({display:'none'});
			}
		},
		
		_moveSelectionDown:function()
		{
			var self = this;
			var aktiver = $('#searchdropdown').find('>div.selected');
			if (aktiver.length >= 1 && aktiver.siblings('div:not(.head)').length >= 1){
				var naechster = aktiver.next('div');
				if (naechster.length == 0){naechster = aktiver.siblings('div:not(.head):first');};
				self._select(naechster);
			}
		},
		_moveSelectionUp:function()
		{
			var self = this;
			var aktiver = $('#searchdropdown').find('>div.selected');
			if (aktiver.length >= 1 && aktiver.siblings('div:not(.head)').length >= 1){
				var naechster = aktiver.prev('div:not(.head)');
				if (naechster.length == 0){naechster = aktiver.siblings('div:last');};
				self._select(naechster);
			}
		},
		
		_select:function(element)
		{
			var self = this;
			$('#searchdropdown').find('>div').removeClass('selected');
			element.addClass('selected');
		},
		
		_search:function(event)
		{
			var self = this;
			var text = $.trim($(self.element).val());
			
			event.preventDefault();
			var aktiver = $('#searchdropdown').find('>div.selected:not(.head)');
			
			
			// falls es einen 100% Treffer gibt 
			if(aktiver.length==0 && text != ''){
				var aktiver = $("div#searchdropdown>div:not(.head):Contains('"+text+"'):eq(0)")
				self._select(aktiver);
			}
			
			if(aktiver.length>0)
			{
				$('#searchdropdown').css({display:'none'});
				self.presearchresult = '';
				
				var searchindex_id = aktiver.extractClassId('searchindex_id')
				var request = aktiver.extractClassString('request');
				var category = aktiver.extractClassString('category');
				var reference = aktiver.extractClassId('reference');
				var basemodel_id= aktiver.extractClassId('basemodel_id');
				var colormodel_id= aktiver.extractClassId('colormodel_id');
				
				if (request == 'Shop/model')
				{
					if (basemodel_id>0){
						var data = {basemodel_id: basemodel_id};
					}
					else if(colormodel_id > 0)
					{
						var data = {colormodel_id: colormodel_id};
					}
					else
					{
						alert('hmmm'+ request)
					}
					
				}
				else if(request == 'Shop/searchindex')
				{
					// umleiten 
					request = 'Shop/modellist';
					var data = {
						category: category,
						searchindex_id: searchindex_id
					};
				}
				else if(request == 'Shop/modellist')
				{
					var data = {basemodel_id: basemodel_id};
				}
				else
				{
					//alert('ohop'+ request)
				}
					
				$('div#shopcenter').pageload
				(
					'request',
					request,
					data
				);
				this.element.blur();
			}
		}
	}
}());
$.qoc.search.getter = [];
$.qoc.search.defaults = {};



/**
 * kann title durch eine bubble ersetzen
 * falls der titel noch eine oder mehrere Zahlen per | abgetrennt hält wird dies
 * als ein alter
 *
 * text der steht|100|ein längerer Text der dort steht|200
 *
 */
$.widget("qoc.titlehints",function()
{
	var $bubbleTemplate = $('\
<div class="bubble">\
	<div class="left"></div>\
	<div class="middle-l" />\
	<div class="middle-a" />\
	<div class="middle-a-a" />\
	<div class="middle-r" />\
	<div class="right"></div>\
	<span></span>\
</div>');
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			this.overlay = null;
			
			this.title = this.element.attr('title');
			this.element.removeAttr('title');
			this.element.bind(
				'mouseover.'+this.widgetName,
				function(event){self._mouseover(event);}
			);
			this.element.bind(
				'mouseout.'+this.widgetName,
				function(event){self._mouseout(event);}
			);
			this.element.timer({
				callback: function(){self._visible();},
				delay: 500,
				numTicks: 1
			});
		},
		destroy: function()
		{
			this.element.unbind('.'+this.widgetName);
			$.widget.prototype.destroy.call(this);
		},
		
		_mouseover: function(events)
		{
			var self = this;
			if (this.overlay == null)
			{
				var parts = this.title.split('|');
				this.overlay = $bubbleTemplate.clone();
				var img = this.overlay.find('img');
				var span = this.overlay.find('span');
				span.text(parts[0]);
				
				var offsetParent = this.element.offsetParent();
				var position = this.element.position();
				var widthFrom = this.element;
				var width;
				while (widthFrom){
					width = widthFrom.innerWidth();
					if (width > 0) break;
					widthFrom = widthFrom.parent();
				}

				
				if (parts.length>1 && parts[1]=='r')
				{
					// pfeil sitzt rechts
					this.overlay.addClass('right')
					this.overlay.css({
						width:'179px',
						left:(parseInt(position.left) + width/2 - (30 + 158 + 5))+'px',
						top:(parseInt(position.top)-80)+'px'
					});
				}
				else
				{
					// pfeil sitzt links
					this.overlay.addClass('left')
					this.overlay.css({
						width:'179px',
						left:(parseInt(position.left) + width/2 - (30 + 20 - 5))+'px',
						top:(parseInt(position.top) -80)+'px'
					});
				}
				$(offsetParent).append(this.overlay);
				this.overlay.find('div').bind(
					'mouseout.'+this.widgetName,
					function(event){self._mouseout(event);}
				);
				
				if (this.element.closest('a').length==1){
					this.overlay.find('div.middle-a-a').css({display:'block'}).bind(
						'click.'+this.widgetName,
						function(event)
						{
							//window.location.href = self.element.closest('a').attr('href');
							self.element.closest('a').click();
						}
					);
				}
				this.element.timer('start');
			}	
		},
		_mouseout: function(event)
		{
			if (
				this.overlay != null && 
				$(event.relatedTarget).closest('.bubble>div').length == 0 && 
				$(event.relatedTarget) != this.element
			)
			{
				this.element.timer('stop');
				this.overlay.remove();
				this.overlay = null;
			}
		},
		
		_visible:function(event){
			this.overlay.css({display:'block'});
		}
	}
}());
$.qoc.titlehints.getter = [];
$.qoc.titlehints.defaults = {};

/**
 * kann title durch eine bubble ersetzen
 * falls der titel noch eine oder mehrere Zahlen per | abgetrennt hält wird dies
 * als ein alter
 *
 * text der steht|100|ein längerer Text der dort steht|200
 *
 */
$.widget("qoc.shoppingCart",function()
{
	return {
		_debug: function(x){},
		destroy: function(){},


		selected_tokencode					: null,
		selected_addto_order_id				: null,
		selected_dispatchmode_id			: null,
		selected_customerDeliveryAddress_id	: null,
		
		_init: function()
		{
			var self = this;
			$('#header-cart').bind('click',function(event){self.element.pageload('request','Cart/index')});
			this.restoreliderpos = -1;
		},
		
		
		
		/*********************** Cart *****************************************/
		
		enableCart:function()
		{
			var self = this;
			
			selected_tokencode					= null;
			selected_addto_order_id				= null;
			selected_dispatchmode_id			= null;
			selected_customerDeliveryAddress_id	= null;
			
			// die Timer erzeugen
			this.prepareWarranted();
			$('div.content.cart:last>div.container').timer({
				delay: 200,									
				callback: function(){self.tickWarranted();}, 
				numTicks: 0
			});
			$('div.content.cart:last>div.container').timer('start');

			$('div.content.cart:last>div.container>table>tbody>tr').hover(
				function(event){
					$(this).addClass('hover')
				},
				function(event){
					$(this).removeClass('hover')
				}
			)
			$('div.content.cart:last>div.container>div.metrics>div.data>table>tbody>tr').hover(
				function(event){
					$(this).addClass('hover')
				},
				function(event){
					$(this).removeClass('hover')
				}
			)

			$('div.content.cart:last>div.container>table').slidetable({cnt:10, slider:'div.content.cart:last>div.container>div.slider', current:this.restoreliderpos});
			
			$('div.content.cart:last>div.container>table')
			.bind('slidetablescroll',	function()		{self.closeMetrics();});
			
			$('div.content.cart:last>div.container>div.metrics>div.fenster')
			.bind('click',				function(event)	{self.closeMetrics();});
			
			// falls keine Order ausgewählt wurde dann in den Cashdesk I ansonsten in den Cashdesk II nur noch zum bestätigen das hinzugefügt werden soll
			$('div.content.cart>div.container>div.goto_cashdesk')
			.bind
			(
				'click',
				function(event)	
				{
					self.closeMetrics
					(
						function()
						{
							if (self.getAddtoOrderId()==0)
							{
								self.toCashdeskI(event);
							}
							else
							{
								self.selected_addto_order_id = self.getAddtoOrderId();
								self.toCashdeskII(event);
							}
						}
					);
				}
			);
			
			$('div.content.cart:last>div.container>table>tbody>tr>td.model')
			.bind('click',				function(event)	{self.closeMetrics(function(){ var basemodel_id = $(event.target).closest('tr').extractClassId('basemodel'); self.showArticles(basemodel_id);});});
			
			$('div.content.cart:last>div.container>table>tbody>tr>td.img.colormodel')
			.bind('click',				function(event)	{self.closeMetrics(function(){ var basemodel_id = $(event.target).closest('tr').extractClassId('basemodel');var colormodel_id = $(event.target).closest('td').extractClassId('colormodel'); self.element.pageload('request', 'Shop/model', {basemodel_id:basemodel_id, colormodel_id:colormodel_id})});});
			
			$('div.content.cart:last>div.container>table>tbody>tr>td.trash')
			.bind('click',				function(event)	{self.closeMetrics(function(){ var basemodel_id = $(event.target).closest('tr').extractClassId('basemodel'); self.removeBasemodel(basemodel_id);});});
			
		},
		determineSavedata : function(element, data)
		{
			var self = this;
			var anzahl = 0;
			
			$('input', element).each(function(i,e){
				if ($(e).val() != e.defaultValue)
				{
					data['update['+$(e).extractClassId('article')+']'] = $(e).val();
					anzahl++;
				}
			});
			return anzahl;
		},
		closeMetrics : function(continuewith)
		{
			var self = this;
			var element = $('div.content.cart:last>div.container>div.metrics.aktiv');
			// festellen ob überhaupt eines geöffnet ist
			if(element.length==0)
			{
				if (typeof(continuewith) == 'function'){continuewith();}
			}
			else
			{
				// feststellen ob es etwas zu speichern gibt?
				var data = {}; 
				var aenderungenCnt = self.determineSavedata(element, data);
				if (aenderungenCnt==0)
				{
					element.removeClass('aktiv');
					if (typeof(continuewith) == 'function'){continuewith();}
				}
				else
				{
					element.removeClass('aktiv');
					self.loadContainer('Cart/updateArticles',data,continuewith);
				}
			}
		},
		removeBasemodel :function(basemodel_id)
		{
			var self = this;
			self.loadContainer('Cart/removeBasemodel',{basemodel_id:basemodel_id});
		},		
		showArticles :function(basemodel_id)
		{
			var zeile = $('div.content.cart:last>div.container>table>tbody>tr.basemodel-'+basemodel_id);
			var istOben = zeile.prevAll('tr').length < 5;
			var position = zeile.position();
			tabletop = zeile.closest('table').position().top;
			var metric = $('div.metrics.basemodel-'+basemodel_id);
			$('div.metrics.aktiv').removeClass('aktiv');
			metric.removeClass(istOben?'unten':'oben');
			metric.addClass(istOben?'oben':'unten');
			var innenplatz = (20+1)*($('>div.data>table>tbody>tr',metric).length) + 10 +3;
			var gesamthoehe = 20 + 70 + 20 + innenplatz ;
			$(metric).css({height:gesamthoehe +'px'});
			$('>div.links,>div.rechts',metric).css({height: gesamthoehe+'px'});
			$('>div.data',metric).css({height:innenplatz+'px'})
			var verschieb = gesamthoehe -20 -20 -70;
			metric.css
			({
				left	:(parseInt(position.left)+90+50-20)+'px',
				top		:(parseInt(position.top)+tabletop - 20 -(istOben?0:verschieb))+'px'
			});
			metric.addClass('aktiv');
		},
		prepareWarranted :function()
		{
			var self = this;
			$('div.content.cart:last>div.container>table>tbody>tr>td.warranted').each(function(i,e)
			{
				var seconds = $(e).extractClassId('for');
				$(e).data('ablauf', new Date().getTime()+(seconds*1000));
			});
		},
		tickWarranted:function()
		{
			var self = this;
			var jetzt = new Date();
			
			$('div.content.cart:last>div.container>table>tbody>tr:visible>td.warranted').each(function(i,e)
			{
				var sec = Math.round(Math.max(0,new Date($(e).data('ablauf')).getTime() - jetzt.getTime())/1000);
				if (sec == 0 && !$(e).hasClass('out'))
				{
					$(e).addClass('out');
					$(e).text('00:00');
				}
				else
				{
					var min = Math.floor(sec/60);
					var sec = sec%60;
					$(e).text(
						(min<10?'0':'')+
						min+
						':'+
						(sec<10?'0':'')+
						sec
					);
				}
			});
		},
		hideCart:function()
		{
			$('#header-cart').addClass('empty');
		
		},
		updateCart: function(data)
		{
			$('#header-cart').removeClass('empty');
			$('#header-cart>span.b1').html(data.cnt + " Artikel");
			$('#header-cart>span.b2').html(StringUtils.toCurrency(data.value)+ "€"); 
			
			// Preis farblich hervorheben, wenn Mindestbestellpreis noch nicht erreicht ist
			$('#header-cart>span.b2,#header-cart>span.c2').css(
				data.value < data.minimumOrderNet ? {color: '#ff2224'} : {color: ''}
			);
			
			if(data.value >= data.minimumOrderNet)
			{
				$('#warenkorbTopTextGroesser').show();
				$('#warenkorbTopTextKleiner').hide();
			}
			else
			{
				$('#warenkorbTopTextGroesser').hide();
				$('#warenkorbTopTextKleiner').show();
			}
			if(data.value>0.00)
			{
				$('.a1,.b1').show();
				$('#wkLeer').hide();
			}
			else
			{
				$('.a1,.b1').hide();
				$('#wkLeer').show();
			}
		},
		loadContainer:function(load,data,continuewith)
		{
			var self = this;
			this.restoreliderpos = $('div.content.cart:last>div.container>table').slidetable('getsliderpos'); 
			$('div.content.cart:last>div.container').animate(
				{opacity:.5},
				{
					duration:100,
					easing: 'swing',
					complete:function(){self.loadContainerStep2(load,data,continuewith);}
				}
			);
		},
		loadContainerStep2:function(load,data,continuewith)
		{
			var self = this;
			var addtoOrderId = this.getAddtoOrderId();
			//this.selected_addtoOrderId = this.getAddtoOrderId();
			Content.load({
				url: load,
				data:data,
				success: function(response){
					$('div.content.cart:last>div.container').html(response.container);
					self.enableCart();
					
					$('div.content.cart:last>div.container').animate(
						{opacity:1},
						{
							duration:100,
							easing: 'swing',
							complete:function()
							{
								self.setAddtoOrderId(addtoOrderId);
								if (typeof(continuewith)=='function'){continuewith();}
							}
						}	
					);
				}				
			});
		},
		setAddtoOrderId : function(addtoOrderId)
		{
			var addtoOrder = $('div.content.cart:last>div.container>div.add_to_order');
			if (addtoOrder.length > 0)
			{
				$('>select',addtoOrder).val(addtoOrderId);
			}
		},
		getAddtoOrderId : function()
		{
			var addtoOrder = $('div.content.cart:last>div.container>div.add_to_order');
			return addtoOrder.length == 0 ? 0 :	$('>select',addtoOrder).val();
		},
		toCashdeskI : function(event)
		{
			var self = this; 
			$('div#shopcenter').pageload
			(
				'request',
				'Cart/cashdeskI',
				{
					addto_order_id:  self.getAddtoOrderId()
				}
			);
		},
		
		/*********************** Cashdesk I ***********************************/
		enableCashdesk1 : function()
		{
			var self = this;
			$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypes>div.dispatchmode').bind('click',function(event){self.selectDispatchmode(event);});
			$('div.content.cashdesk:last>div.container>div.cashdeskI>div.token>div:gt(0)').bind('click',function(event){self.selectToken(event);});
			
			// an oder aus des wechslers falls mehr als eine Adresse vorhanden 
			$('div.content.cashdesk:last>div.container>div.cashdeskI>div.delivertoPrev,div.content.cashdesk:last>div.container>div.cashdeskI>div.delivertoNext')
			.css({display:($('div.content.cashdesk:last>div.container>div.cashdeskI>div.deliverto>div').length > 1) ? 'block' : 'none'})
			.bind('click',function(event){self.rotateDeliveryaddress(event)});
			
			$('div.content.cashdesk>div.container>div.cashdeskI>div.toCashdeskII')
			.bind('click',function(event){self.toCashdeskII(event);})
			
			
			// und erste sichtbare Zahlart auswählen
			//$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypes>div.dispatchmode:visible').click();
			
			
		},
		
		getDispatchmode : function()
		{
			var mode = $('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypes>div.aktiv')
			
			return mode.length > 0 ? mode.extractClassId('dispatchmode') : 0;
		},		
		getToken : function()
		{
			var token = $('div.content.cashdesk:last>div.container>div.cashdeskI>div.token>div.aktiv');
			return token.length > 0 ? token.extractClassId('token') : 0;
		},		
		getCustomerDeliveryAddress : function()
		{
			return $('div.content.cashdesk:last>div.container>div.cashdeskI>div.deliverto>div.aktiv').extractClassId('address');
		},
				
		toCashdeskII : function(event)
		{
			$(event.target).fadeOut();
			var self = this; 
			if (self.selected_addto_order_id != null && self.selected_addto_order_id != 0)
			{
				// hinzufügen order
				$('div#shopcenter').pageload
				(
					'request',
					'Cart/cashdeskII',
					{
						addto_order_id : this.selected_addto_order_id
					}
				)
			}
			else
			{
				var selected_addto_order_id = this.selected_addto_order_id;
				var getDispatchmode = self.getDispatchmode();
				var getToken = self.getToken();
				var getCustomerDeliveryAddress = self.getCustomerDeliveryAddress()
				// neue order
				$('div#shopcenter').pageload
				(
					'request',
					'Cart/cashdeskII',
					{
						addto_order_id : selected_addto_order_id,
						dispatchmode_id : getDispatchmode,
						tokencode : getToken,					
						customerDeliveryAddress_id : getCustomerDeliveryAddress,
						paymenttypesDownpay : $('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDownpay.aktiv:visible').length > 0 ? 1 : 0
					}
				)
			}
		},
		rotateDeliveryaddress : function(event)
		{
			var contain = $('div.content.cashdesk:last>div.container>div.cashdeskI>div.deliverto')
			//festellen ob noch eine animation läuft
			if ($(':animated',contain).length > 0) return ; 
			
			// festellen welcher gedrückt
			var links = $(event.target).hasClass('delivertoPrev');
			var aktiver = $('div.content.cashdesk:last>div.container>div.cashdeskI>div.deliverto>div.aktiv');
			// nächsten finden
			var naechster = links ? aktiver.prev('div') : aktiver.next('div');
			if (naechster.length == 0){naechster = links ? aktiver.siblings('div:last') : aktiver.siblings('div:first');}
			// positionen setzen
			naechster.css({left:links?'-400px':'400px',display:'block', opacity:0});
			naechster.animate(
				{left:'0px',opacity:1},
				{
					easing:'swing', 
					duration:200, 
					step:function(v,o){
						if (o.prop == 'opacity')
						{
							aktiver.css({left:((links?1:-1)*400*(v))+'px',opacity:(1-v)})
						}
					},
					complete:function(){
						aktiver.removeClass('aktiv').css({left:'',display:''});
						naechster.addClass('aktiv').css({left:'',display:''});
						
						
						$('div.paymenttypes div').css({display:'none'});					
						$('div.paymenttypes div.country-'+naechster.extractClassId('country')).css({display:'block'});
						// hier müsste jetzt die richtige paymentart gewählt werden
						//selectDispatchmode()
						//$('div.paymenttypes div:visible:eq(1)').click();
						
						if($('div.paymenttypes div:visible.DOWNPAY.aktiv').length > 0)
						{
							$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDownpay').addClass('aktiv');
						}
						else
						{
							$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDownpay').removeClass('aktiv');
						}
					}
				}
			);
		},
		/*********************** Cashdesk II **********************************/
		enableCashdesk2 : function(selected_addto_order_id,selected_dispatchmode_id,selected_tokencode, selected_customerDeliveryAddress_id )
		{
			var self = this;
			this.selected_addto_order_id				= selected_addto_order_id;
			this.selected_dispatchmode_id				= selected_dispatchmode_id;
			this.selected_tokencode						= selected_tokencode;
			this.selected_customerDeliveryAddress_id	= selected_customerDeliveryAddress_id;
			$('div.content.cashdesk>div.container>div.cashdeskII>div.toCashdeskIII')
			.bind('click',function(event){self.toCashdeskIII(event);})
			
		},
		
				
		selectToken: function(event)
		{
			var self = this;
			$(event.target).siblings('div').removeClass('aktiv');
			$(event.target).addClass('aktiv');
		},
		selectDispatchmode : function(event)
		{
			var self = this;
			$(event.target).siblings('div').removeClass('aktiv');
			$(event.target).addClass('aktiv');
			$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDescription>div').removeClass('aktiv');
			$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDescription>div.dispatchmode-'+self.getDispatchmode()).addClass('aktiv');
			
			if($(event.target).hasClass('DOWNPAY'))
			{
				$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDownpay').addClass('aktiv');
			}
			else
			{
				$('div.content.cashdesk:last>div.container>div.cashdeskI>div.paymenttypesDownpay').removeClass('aktiv');
			}
		},
		
		toCashdeskIII : function(event)
		{
			$(event.target).css({display:'none'});
			
			var self = this; 
			if (self.selected_addto_order_id != null && self.selected_addto_order_id != 0)
			{
				// hinzufügen order
				$('div#shopcenter').pageload
				(
					'request',
					'Cart/cashdeskIII',
					{
						addto_order_id : this.selected_addto_order_id,
						accept_gtac : ($('input#yes_gtac:checked').length > 0 ? 'yes' : 'no')
					}
				)
			}
			else
			{
				$('div#shopcenter').pageload
				(
					'request',
					'Cart/cashdeskIII',
					{
						addto_order_id : this.selected_addto_order_id,
						dispatchmode_id : this.selected_dispatchmode_id,
						tokencode : this.selected_tokencode,					
						customerDeliveryAddress_id : this.selected_customerDeliveryAddress_id,
						//inform_me : ($('input#yes_newsletter:checked').length > 0 ? 'yes' : 'no'),
						accept_gtac : ($('input#yes_gtac:checked').length > 0 ? 'yes' : 'no'),
						paymenttypesDownpay : $('div.content.cashdesk:last>div.container>div.cashdeskII>div.paymenttypesDownpay>input').length > 0 ? 1 : 0
					}
				);
			};
		},
		/*********************** Cashdesk III **********************************/
		enableCashdesk3 : function()
		{
			// und jetzt auf die Dank für ihre Bestellungseite im Kundenbereich weiterleiten.
			
			// kann ähnlich der Willkommenseite werden
			
			// dank auch an die Willkommenmeldung 
			
			// und an die Ausgabe der Nachricht an den Kunden  
			
			/*
			if (self.selected_addto_order_id != null && self.selected_addto_order_id != 0)
			{
				$('div#shopcenter').pageload
				(
					'request',
					'Customer',
					{loadContainer:'Customer/articlesAdded'}
				);
			}
			else
			{
				$('div#shopcenter').pageload
				(
					'request',
					'Customer',
					{loadContainer:'Customer/ordered'}
				);
			}
			*/
			
			$('div.content.cashdesk>div.container>div.cashdeskIII>div.toCustomerArea')
			.bind('click',function(event){
				$('div#shopcenter').pageload
				(
					'request',
					'Customer',
					{loadContainer:'CustomerOrder/ordersOpen'}
				);
			})
		}
	}
}());
$.qoc.shoppingCart.getter = [];
$.qoc.shoppingCart.defaults = {};	

/**
 * Verwaltung vom Kundenaktionen 
 * 
 */
$.widget("qoc.customerAccount",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			
			var o = this.options;
			
			$('>div.scrollable>form',this.element).bind('submit',function(event){self.requestPayout(event)});
			if(o.currentAmount > 2)
			{
				$('>div.scrollable>p',this.element).css({display:'none'});
				$('>div.scrollable>form',this.element).css({display:'inline'});
			}
			else
			{
				$('>div.scrollable>p',this.element).css({display:'inline'});
				$('>div.scrollable>form',this.element).css({display:'none'});
			}
		},
		requestPayout : function(event)
		{
			var self = this;
			event.preventDefault();
			$('>div.scrollable>form',this.element).ajaxSubmit({success: function(response){self.requestPayoutAnswer(response);}});
			$('>div.scrollable>form>table',this.element).animate({opacity:0},{duration:150,easing: 'swing'});
		},
		requestPayoutAnswer : function(response)
		{
			var self = this;
			if (response.success == 1){
				$('>div.scrollable>p',this.element).html(response.message).css({display:'inline'});
				$('div#shopcenter').customer('writeCustomeraccount', response.customeraccount);
			}
			else
			{
				$('>div.scrollable>form>table',this.element).animate({opacity:1},{duration:150,easing: 'swing'});
				$('>div.scrollable>form>table>tbody>tr.error',this.element).css({display:'table-row'}).find('td').html(response.error);
			}
		}
	}
}());
$.qoc.customerAccount.getter = [];
$.qoc.customerAccount.defaults = {currentAmount:0};

$.widget("qoc.customerOrder.js",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			var o = this.options;
			if (o.details){
				$('>tbody>tr>td:not(.mergeable)',this.element).bind('click',function(event){self.openOrderdetails(event)});
			}
			$('>tbody>tr>td.mergeable',this.element).bind('click',function(event){self.markToMerge(event)});
			$('>thead>tr>th.mergeable',this.element).bind('click',function(event){self.merge(event)});
			
		},
		markToMerge : function(event)
		{
			var self = this;
			$(event.target).toggleClass('aktiv')
			
			if ($('>tbody>tr>td.mergeable.aktiv',this.element).length > 1)
			{
				$('>thead>tr>th.mergeable',this.element).addClass('aktiv');
			}
			else
			{
				$('>thead>tr>th.mergeable',this.element).removeClass('aktiv');
			}			
		},
		merge : function(event)
		{
			var self = this;
			if ($('>thead>tr>th.mergeable.aktiv',this.element).length<1)
			{
				// einen allein ignorieren
				return;
			}
			// markierte
			orders =  $.map($('>tbody>tr>td.mergeable.aktiv',this.element),function(e,i){
				return $(e).closest('tr').extractClassId('order');
			});
			$('>thead>tr>th.mergeable.aktiv',this.element).removeClass('mergeable');
			Content.load({
				url: 'CustomerOrder/mergeOrders',
				data:{'order_ids[]':orders},
				success: function(response){
					// danach die Liste neu laden
					$('div#shopcenter').customer('loadContainer','CustomerOrder/ordersOpen');
				}	
			});
		},
		openOrderdetails : function (event)
		{
			var self = this;
			var row = $(event.target).closest('tr');
			var layer = row.closest('div.layer');
			var container = layer.closest('div.container');
			var order_id = row.extractClassId('order');
			var ordertype = layer.extractClassString('orderstype');
			
			var load = 'CustomerOrder/'+ordertype+'Details';
			var data = {order_id:order_id};
			container.animate({opacity:'0'},{duration:100,easing:'swing',complete:function(){
				Content.load({
					url: load,
					data:data,
					success: function(response){
						layer.css({display:'none'});
						layer.after(response.layer);
						container.animate({opacity:1},{duration:200,easing: 'swing'});
					}		
				});
			}});
		}
	}
}());
$.qoc.customerOrder.getter = [];
$.qoc.customerOrder.defaults = {details:true};

$.widget("qoc.customerOrderDetails.js",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			var o = this.options;
			// sicht schliessen
			// links zu den modellen
			$('>tbody>tr:gt(0) table td.link',this.element).bind('click',function(event){
				var basemodel_id = $(event.target).closest('tr').extractClassId('basemodel');
				var colormodel_id = $(event.target).closest('tr').extractClassId('colormodel'); 
				$('div#shopcenter').pageload('request', 'Shop/model', {basemodel_id:basemodel_id, colormodel_id:colormodel_id});
			});	
			$('>tbody>tr:eq(0)>td:eq(0)',this.element).bind('click',function(event){self.closeOrderdetails(event)});
			

			
		},
		closeOrderdetails : function (event)
		{
			var self = this;
			var layer = self.element.closest('div.layer');
			var container = layer.closest('div.container');
			
			container.animate({opacity:'0'},{duration:100,easing:'swing',complete:function(){
				layer.prev('div.layer').css({display:'block'});
				layer.css({display:'none'});
				container.animate({opacity:1},{duration:200,easing: 'swing', complete:function(){
					layer.remove();
				}});
			}});
		}
	}
}());
$.qoc.customerOrderDetails.getter = [];
$.qoc.customerOrderDetails.defaults = {};

$.widget("qoc.customerToken.js",function()
{
	return {
		_debug: function(x){},
		_init: function()
		{
			var self = this;
			var o = this.options;
			$('>tbody>tr>td.mergeable',this.element).bind('click',function(event){self.markToMerge(event)});
			
			$('>thead>tr>th.mergeable',this.element).bind('click',function(event){self.merge(event)});
			
		},
		markToMerge : function(event)
		{
			var self = this;
			$(event.target).toggleClass('aktiv')
			
			if ($('>tbody>tr>td.mergeable.aktiv',this.element).length > 1)
			{
				$('>thead>tr>th.mergeable',this.element).addClass('aktiv');
			}
			else
			{
				$('>thead>tr>th.mergeable',this.element).removeClass('aktiv');
			}			
		},
		merge : function(event)
		{
			var self = this;
			if ($('>thead>tr>th.mergeable.aktiv',this.element).length<1)
			{
				// einen allein ignorieren
				return;
			}
			// markierte
			tokens =  $.map($('>tbody>tr>td.mergeable.aktiv',this.element),function(e,i){
				return $(e).closest('tr').extractClassId('token');
			});
			$('>thead>tr>th.mergeable.aktiv',this.element).removeClass('mergeable');
			Content.load({
				url: 'CustomerToken/mergeTokens',
				data:{'token_ids[]':tokens},
				success: function(response){
					// danach die Liste neu laden
					$('div#shopcenter').customer('loadContainer','CustomerToken/token');
				}	
			});
		}
	}
}());
$.qoc.customerToken.getter = [];
$.qoc.customerToken.defaults = {};

