Object.extend(Date.prototype,
{
	SimpleDateTimeFormat: function(format, data) {
		return this.SimpleTimeFormat( this.SimpleFormat( format, data ) );
	},
	SimpleTimeFormat: function(format) {
		var bits = new Array();
		
		bits['H'] = this.getHours();
		bits['HH'] = String(this.getHours()).zerofill(2);
		
		bits['m'] = this.getMinutes();
		bits['mm'] = String(this.getMinutes()).zerofill(2);
		
		bits['s'] = this. getSeconds();
		bits['ss'] = String(this.getSeconds()).zerofill(2);

		// do some funky regexs to replace the format string
		// with the real values
		var frm = new String(format);
		for (var sect in bits)
		{
			var reg = new RegExp("\\b"+sect+"\\b" ,"g");
			frm = frm.replace(reg, bits[sect]);
		}
		return frm;
	}
});

/***************************************************************
 *       Direkte Eingriffe in die JavaScript-Funktionen
 ***************************************************************/
/**
 * document.pointerX und document.pointerY enthalten die momentane
 * Position des Mauszeigers
 */
document.observe( 'mousemove', function( ev ) {
	document.pointerX = ev.pointerX();
	document.pointerY = ev.pointerY();
} );

/**
 * Die alert-Funktion wird erweitert, so dass - wenn vorhanden - ein AlertWindow angezeigt wird.
 */
function info( msg ) {
	alert( msg );
}

function warning( msg ) {
	alert( msg );
}

/**
 * Kapselung der IMLib-JavaScript-Methoden
 */
var IMLib = {
	Alert: function( msg ) {
		var errorWindow = $( 'Window_Error' );
		if( !errorWindow ) {
			alert( msg );
		}
		else {
			$( 'ErrorMessage' ).innerHTML = msg;
			errorWindow.windowHandle.show( true, true );
			errorWindow.windowHandle.bringToFront.bind(errorWindow.windowHandle).delay(0.5);
		}
	},
    AlertModalTo: function( srcwindow, msg ) {
        var errorWindow = $( 'Window_Error' );
        if( !errorWindow ) {
            alert( msg );
        }
        else {
            $( 'ErrorMessage' ).innerHTML = msg;
            errorWindow.windowHandle.showSubmodalTo( srcwindow );
        }
    },
	extractContainerID: function( base ) {
		var m=base.match( /ContainerID_(\d+)$/ );
		if(m==null) {
			return -1;
		}
		return m[1];
	},
	Options: {
		/**
		 * @var array Statische Parameter, die von der getPageID-Methode ignoriert werden sollen
		 */
		PageIDParams: [],
		/**
		 * @var array Benutzerdefinierte Argumente zum Überschreiben der PageID
		 */
		OverwritePageID: null
	},
	overwritePageID: function(param) {
		IMLib.Options.OverwritePageID=param;
	},
	getPageID: function() {
		var params;
		if(IMLib.Options.OverwritePageID==null) {
			params=window.location.search.toQueryParams();
		}
		else {
			params=IMLib.Options.OverwritePageID;
		}
		
		var useParams={};
		
		// statische Parameter herausfiltern
		IMLib.Options.PageIDParams.each(function(item) {
			useParams[item]=params[item];
		});
		
		return(Object.toJSON(useParams));
	},
	arrayEquals: function(a, b) {
		if(a.length!=b.length) {
			return false;
		}
		for(var i=0; i<a.length; i++) {
			if(a[i]!=b[i]) {
				return false;
			}
		}
		return true;
	}
}
IMLib.WebUI = {};
IMLib.Ajax = {
	FailureResponder: Class.create({
		callback: null,
  		initialize: function(callback) {
  			this.callback=callback;
		},
		onComplete: function(request, transport) {
			if(!request.success()) {
				this.callback(request, transport);
			}
		}
	})
}

/**
 * Umgangsmethoden für Elemente
 */
IMLib.Element = {
	/**
	 * Extrahiert aus dem Css-Klassennamen des Objektes den Namen des zugehörigen Callback-Controls
	 */
	getCallbackNames: function( element ) {
		var names = [];
		$w( element.className ).each( function( el ) {
			if( el.startsWith( 'Callback::' ) ) {
				names.push( el.substr( 10 ) );
			}
		} );
		document.fire( 'IMLib', {source: "IMLib.Element.getCallbackNames", names: names} );
		return( names );
	},
	/**
	 * Extrahiert aus dem Css-Klassennamen des Objektes die ID des zugehörigen TriggeredWebControl
	 * 
	 * @return string null, wenn nicht gefunden
	 * @param Element
	 * @param string Css-Klasse des TriggeredWebControl
	 */
	getTriggeredWebControlID: function( element, type ) {
		var id = null;
		if( !type.endsWith( '::' ) ) {
			type += '::';
		}
		
		$w( element.className ).each( function( el ) {
			if( el.startsWith( type ) ) {
				id = el.substr( type.length );
			}
		} );
		return( id );
	},
	/** 
	 * Extrahiert aus dem Css-Klassennamen des Objektes die Einträge für den Container
	 */
	getContainerData: function( element ) {
		var containerData = null, matches, regex = /^(.+)\(([0-9]+)\)$/;
		$w( element.className ).each( function( el ) {
			if( el.startsWith( 'Container::' ) ) {
				el = el.substr( 11 );
				matches = el.match( regex );
				if( matches ) {
					containerData = {
						type:	matches[1],
						id:		parseInt( matches[2] )
					};
				}
			}
		} );
		return( containerData );
	},
	Modal: {
		counter: 0,
		currentEffect: null,
		create: function() {
			var div = Builder.node( 'div', {
				id:			'Modal'
			} );
			div.style.background = '#000';
			div.style.zIndex = 200;
			div.style.width = '100%';
			div.style.height = '100%';
			div.style.position = 'absolute';
			div.style.display = 'none';
			
			return( div );
		},
		destroy: function() {
			$( 'Modal' ).remove();
		},
		show: function() {
			if( !Object.isElement( $( 'Modal' ) ) ) {
				var div = IMLib.Element.Modal.create();
				var body = $$( 'body' )[0];
				body.addClassName( 'overflow_hidden' );
				body.insertBefore( div, body.childNodes[0] );
				window.scrollTo(0,0);
				
				if(IMLib.Element.Modal.currentEffect) IMLib.Element.Modal.currentEffect.cancel();
				IMLib.Element.Modal.currentEffect=new Effect.Appear( div,
					{
						duration:			0.5,
						to:					0.2
					}
				);
			}
			IMLib.Element.Modal.counter++;
		},
		hide: function() {
			if( IMLib.Element.Modal.counter<=1 ) {
				IMLib.Element.Modal.counter=0;
				
				var div = $( 'Modal' );
				if( !div ) {
					return;
				}
				
				$$( 'body' )[0].removeClassName( 'overflow_hidden' );
				
				if(IMLib.Element.Modal.currentEffect) IMLib.Element.Modal.currentEffect.cancel();
				IMLib.Element.Modal.currentEffect=new Effect.Fade( div,
					{
						duration:			0.5,
						afterFinish:		IMLib.Element.Modal.destroy
					}
				);
			}
			else {
				IMLib.Element.Modal.counter--;
			}
		}
	}
}

/**
 * Stellt Methoden zur Erzeugung von Icon-Bildern zur Verfügung
 */
IMLib.Icon = {
	/**
	 * Gibt den Pfad zu dem Iconverzeichnis zurück
	 * 
	 * @return string
	 */
	getIconPath: function() {
		return( '/icon/' );
	},
	/**
	 * Gibt den Pfad zu einem Icon zurück
	 * 
	 * @return string
	 * @param string Name des Icon
	 */
	getPath: function( icon ) {
		return( IMLib.Icon.getIconPath() + icon + '.png' );
	},
	/**
	 * Gibt den Namen eines Icons zu seinem Pfad zurück.
	 * Ein solcher Pfad muss die Form [path/to/]icon/iconname.png besitzen
	 * 
	 * @return string Leere Zeichenkette bei nicht finden eines Icons
	 * @param string Pfad des Icon
	 */
	getName: function( path ) {
		var regex = /^(?:.*\/)?icon\/(.*).png$/;
		var m = path.match( regex );
		
		if( !m ) {
			return( '' );
		}
		else {
			return( m[1] );
		}
	},
	/**
	 * Gibt ein IMG-Tag zu einem Icon zurück
	 * 
	 * @return string
	 * @param string Name des Icon
	 * @param array Weitere Attribute des Icons
	 */
	getIcon: function( icon ) {
		var img = document.createElement( 'img' );
		img.writeAttribute( 'src', IMLib.Icon.getPath( icon ) );
		
		var attrs = arguments.length>1 ? arguments[1] : [];
		for( var attribute in attrs ) {
			img.writeAttribute( attribute, attrs[attribute] );
		}
		
		if( !attrs['alt'] ) {
			img.writeAttribute( 'alt', icon );
		}
		
		return( img );
	}
}

/**
 * Logger
 * Stellt Methoden zum Schreiben von Logdaten in ein HTMLElement zur Verfügung
 * 
 * @author Martin Kuckert
 * @version $Revision: 1.19.2.1 $  $Date: 2009/03/10 10:54:00 $
 * @package JS.IMLib.Logger
 * @since 23.11.2007
 */
IMLib.Logger = Class.create();
Object.extend( IMLib.Logger.prototype, {
	/**
	 * @var Element Referenz auf das zu verwendende HTMLElement
	 */
	elRef: null,
	/**
	 * @var boolean Flag, ob Icon vor die Nachrichten gerendert werden sollen
	 */
	useIcons: true,
	/**
	 * @var Hash Zuordnungstabelle der Icons zu den Log-Typen
	 */
	iconMap: new Hash( {
		log:		'arrow_right_green',
		info:		'information',
		debug:		'debug',
		warning:	'warning',
		error:		'error'
	} ),
	/**
	 * Konstruktor
	 * 
	 * @param Element Referenz auf das zu verwendende HTMLElement
	 */
	initialize: function( el ) {
		this.elRef = el;
	},
	/**
	 * Leert das Zielelement
	 * 
	 * @return void
	 */
	clear: function() {
		this.elRef.innerHTML = '';
	},
	/**
	 * Fügt dem Logger eine Logmeldung hinzu
	 * 
	 * @return void
	 * @param string Der zu loggende Text
	 */
	log: function( msg ) {
		this.writeLogEntry( msg, 'log' );
	},
	/**
	 * Fügt dem Logger eine Information hinzu
	 * 
	 * @return void
	 * @param string Der Fehlertext
	 */
	info: function( msg ) {
		this.writeLogEntry( msg, 'info' );
	},
	/**
	 * Fügt dem Logger eine Debugmeldung hinzu
	 * 
	 * @return void
	 * @param string Die Debugmeldung
	 */
	debug: function( msg ) {
		this.writeLogEntry( msg, 'debug' );
	},
	/**
	 * Fügt dem Logger eine Warnung hinzu
	 * 
	 * @return void
	 * @param string Der Fehlertext
	 */
	warning: function( msg ) {
		this.writeLogEntry( msg, 'warning' );
	},
	/**
	 * Fügt dem Logger eine Fehlermeldung hinzu
	 * 
	 * @return void
	 * @param string Der Fehlertext
	 */
	error: function( msg ) {
		this.writeLogEntry( msg, 'error' );
	},
	/**
	 * Schreibt einen Eintrag in den Log
	 * 
	 * @return void
	 * @param string Nachricht
	 * @param string Typ der Nachricht
	 */
	writeLogEntry: function( msg, type ) {
		if( this.useIcons && this.iconMap[type] ) {
			this.write( IMLib.Icon.getIcon( this.iconMap[type] ) );
		}
		this.writeln( '<span class="logger-'+type+'">'+msg+'</span>' );
	},
	/**
	 * Schreibt Text in das Debugfenster
	 * 
	 * @return void
	 * @param string
	 */
	write: function( msg ) {
		this.elRef.insert( msg );
		this.elRef.scrollTop = this.elRef.scrollHeight;
	},
	/**
	 * Schreibt Text in das Debugfenster und hängt ein Newline an
	 * 
	 * @return void
	 * @param string
	 */
	writeln: function( msg ) {
		this.write( msg+"<br />" );
	}
} );

/**
 * Listener
 * Horcht auf bestimmte Ereignisse an einem Element und leitet diese an weitere Funktionen
 * 
 * @author Martin Kuckert
 * @version $Revision: 1.19.2.1 $  $Date: 2009/03/10 10:54:00 $
 * @package JS.IMLib.Listener
 * @since 23.11.2007
 */
IMLib.Delegate = Class.create();
Object.extend( IMLib.Delegate.prototype, {
	/**
	 * @var Element Element, auf dem der Delegate horcht
	 */
	el: null,
	/**
	 * @var Array Callbackfunktionen, die immer ausgelöst werden, wenn ein Ereignis auftritt.
	 * Die Signatur der Callbackfunktion ist: function( string eventName, Event event )
	 */
	everyEvent: new Array(),
	/**
	 * @var Hash Events und deren Callbackfunktionen.
	 * Die Signatur der Callbackfunktion ist: function( string eventName, Event event )
	 */
	listener: new Hash(),
	/**
	 * Konstruktor
	 * 
	 * @param Element Element, auf dem der Delegate horchen soll
	 */
	initialize: function( el ) {
		this.el = el;
	},
	/**
	 * Fügt eine Callbackfunktion für ein Event hinzu
	 * 
	 * @return void
	 * @param string Name des Events
	 * @param function Die Callbackfunktion
	 */
	add: function( eventname, callback ) {
		if( !this.listener[eventname] ) {
			this.listener[eventname] = new Array();
			document.observe( eventname, function( ev ) {
				this.react( eventname, ev );
			}.bindAsEventListener( this ) );
		}
		this.listener[eventname].push( callback );
	},
	/**
	 * Entfernt eine Callbackfunktion für ein Event
	 * 
	 * @return void
	 * @param string Name des Events
	 * @param function Die Callbackfunktion
	 */
	remove: function( eventname, callback ) {
		if( !this.listener[eventname] ) {
			this.listener[eventname] = new Array();
			document.observe( eventname, function( ev ) {
				this.react( eventname, ev );
			}.bindAsEventListener( this ) );
		}
		
		
		var index = this.listener[eventname].indexOf( callback );
		if( index!=-1 ) {
			delete this.listener[eventname][index];
		}
	},
	/**
	 * Fügt eine Callbackfunktion für jedes Event hinzu
	 * 
	 * @return void
	 * @param function Die Callbackfunktion
	 */
	addEvery: function( callback ) {
		this.everyEvent.push( callback );
	},
	/**
	 * Entfernt eine Callbackfunktion für jedes Event
	 * 
	 * @return void
	 * @param function Die Callbackfunktion
	 */
	removeEvery: function( callback ) {
		var index = this.everyEvent.indexOf( callback );
		if( index!=-1 ) {
			delete this.everyEvent[index];
		}
	},
	/**
	 * Reagiert auf ein Event
	 * 
	 * @return void
	 * @param string Name des Events
	 * @param Event Das Event
	 */
	react: function( eventname, event ) {
		this.everyEvent.each( function( func ) {
			try {
				func( eventname, event );
			}
			catch( ex ) {}
		} );
		
		if( !this.listener[eventname] ) {
			return;
		}
		
		this.listener[eventname].each( function( func ) {
			try {
				func( eventname, event );
			}
			catch( ex ) {}
		} );
	}
} );

/**
 * Ermittelt die Position der Mitte eines Elementes
 * 
 * @return Array( x, y )
 */
Position.getCenter = function( element ) {
	element = $( element );
	
	// Position des Elementes berechnen
	var position = Position.positionedOffset( element );
	
	// Mitte des Elementes berechnen
	var x = parseInt( element.getWidth()/2 );
	var y = parseInt( element.getHeight()/2 );
	
	return( [position[0] + x, position[1] + y] );
}

/**
 * Loading
 * Bietet statische Methoden, um den Loading-Indicator ein- bzw. auszublenden.
 * 
 * @author Martin Kuckert
 * @version $Revision: 1.19.2.1 $  $Date: 2009/03/10 10:54:00 $
 * @package JS.Loading
 * @since 21.11.2007
 */
var Loading = {
	/**
	 * @var string Die Css-Klasse für den Loading-Indicator
	 */
	CSS_CLASS: 'Loading',
	/**
	 * @var integer Counter, wie viele Loading::show-Aufrufe stattgefunden haben, um entsprechend
	 * erst nach dieser Anzahl wieder Loading::hide zu erlauben
	 */
	count: 0,
	/**
	 * Blendet den Loading-Indicator ein
	 * 
	 * @return void
	 * @param boolean Flag, ob der Indicator Modal angezeigt werden soll
	 */
	show: function() {
		$$( '.'+Loading.CSS_CLASS ).invoke( 'show' );
		Loading.count++;
		document.getElementsByTagName( 'body' )[0].setStyle( {
			cursor:	'wait'
		} );
		if(arguments.length>0) {
			IMLib.Element.Modal.show();
		}
	},
	/**
	 * Blendet den Loading-Indicator aus
	 * 
	 * @return void
	 * @param boolean Flag, ob der Indicator Modal angezeigt wurde
	 */
	hide: function() {
		Loading.count--;
		if( Loading.count<=0 ) {
			$$( '.'+Loading.CSS_CLASS ).invoke( 'hide' );
			Loading.count = 0;
			document.getElementsByTagName( 'body' )[0].setStyle( {
				cursor:	'default'
			} );
			if(arguments.length>0) {
				IMLib.Element.Modal.hide();
			}
		}
	}
}

/**
 * Link
 * Bietet Methoden für die Simulation des target-Attributs bei dem Betätigen eines Links
 * 
 * @author Martin Kuckert
 * @version $Revision: 1.19.2.1 $  $Date: 2009/03/10 10:54:00 $
 * @package JS.Link
 * @since 21.11.2007
 */
var Link = {
	/**
	 * Simuliert das Attribut target="_blank"
	 * 
	 * @return boolean Gibt immer false zurück
	 * @param Element
	 * @param string Name für das zu öffnende Fenster
	 */
	blank: function( element ) {
		element = $( element );
		var href=element.href;
		
		// Ungültige Url
		if(href.match(/^https?:\/\//i)==null) {
			href=location.protocol+'//'+href;
		}
		
		var name='_blank';
		if(arguments.length>1) {
			name=arguments[1];
		}
		
		window.open( href, name );
		return( false );
	},
	/**
	 * Simuliert das Attribut target="_self"
	 * 
	 * @return boolean Gibt immer false zurück
	 * @param Element
	 */
	self: function( element ) {
		//IMLib.Debug.log( 'Using element as if had target "_self"' );
		element = $( element );
		Link.navigate( element.href );
		return( false );
	},
	/**
	 * Navigiert zu einer URL
	 * 
	 * @return void
	 * @param string Die URL
	 */
	navigate: function( url ) {
		window.location.href = url;
	},
	/**
	 * Lädt diese Seite neu
	 * 
	 * @return void
	 */
	reload: function() {
		window.location.reload(true);
		//Link.navigate( window.location.href.split("#")[0] );
		return false;
	}
}
