/********************************************************************
   formObserver

   Datum: 14.12.2006
   Autor: J. Strübig
   http://jstruebig.de
   
   Updates:
   * 12.02.2007: das KeyEvent Objekt geändert, es existiert nur noch eines.
   
   Version: 1.0.1

   Der Formobserver beobachtet die Felder eines Formulares auf Änderugen
   und zeigt diese dem Beobachter an.

   Funktionen:

   formObserver( form )
   Der Parameter ist eine Referenz auf ein Formular das beobachtet werden soll.
   Das Formular bekommt eine Funktion:

   .addObserver( observer )
   Der Observer muss ein Objekt sein, mit der Funktion update(),
   die aufgerufen wird, wenn ein Formularelement geändert wird.

   Die Formularelemente bekommen ebenfalls Funktionen:
   .setValue(val)
   .getValue()

   je nach Typ werden entsprechende Eventhandler gesetzt.

********************************************************************/
function formObserverAll(win) {
	if(!win) win = window;

    var doc = win.document;
    if(!doc) return;

    var f = doc.forms;
    if(!f) return;

    for(var i = 0; i < f.length; i++) formObserver( f[i] );
}

function formObserver( f ) {
    if(!f) return;
	
    // Ein Objekt, das die Informationen des Events sammelt
	// und Browserübergreifend auswertet
	var evt = new function ()
	{
		var obj;
		this.set = function(e) {
			if(!e) e = window.event;
			obj = e.target ? e.target : e.srcElement ? e.srcElement : null;
			
			if(obj &&  obj.nodeType == 3) obj = obj.parentNode;
			
			this.Y = obj.offsetTop;
			this.X = obj.offsetLeft;
			var p = obj.offsetParent;
			while(p)
			{
				this.Y += p.offsetTop;
				this.X += p.offsetLeft;
				p = p.offsetParent;
			}
		};
		this.top = function() { return this.Y; };
		this.left = function() { return this.X; };
	}
    var addObserver = function( observer ) {
		if(!observer || typeof observer.update != 'function') 
			return alert('Das Objekt ist kein Observer [update Funktion fehlt]');
		this.observerList[this.observerList.length] = observer;
	};

    // Die Funktion, die die Observer informiert
    var changed = function(o, e) {
		evt.set(e);
		if(!o.getChanged() ) return;
		o.form.changed(evt);
		for(var i = 0; i < o.observerList.length; i++) o.observerList[i].update(o, evt);
		o.clearChanged();
		return;
    };

    // Die elemente beobachtbar machen
    var change_call = function(e)
    {
		this.form.last = this;
		this.setChanged(true);
		changed(this, e);
	};
	var get_value = function() { return this.value; };
	
	for(var i = 0; i < f.elements.length; i++)
	{
		var el = f.elements[i];
		// Events nach Elementyp auswählen
		el.isObserver = true;
		switch(el.type)
		{
			case 'text':
			case 'textarea':
			el.onkeyup = el.onblur =  function(e) {
			
				this.form.last = this;
				this.setChanged ( this.value != this.oldValue );
				changed(this, e);
				this.oldValue = this.value;
			};
			el.setValue = function(val) {
				this.oldValue = this.value = val;
			};
			el.getValue = get_value;
			break;
			
			case 'checkbox':
			case 'radio':
			case 'button':
			el.onclick =  change_call;
			el.getValue = get_value;
			el.setValue = function() {};
			break;
			
			case 'select-one':
			case 'select':
			el.onchange =  change_call;
			el.setValue = function(val) {
				for(var i = 0; i < this.options; i++)
				if(val == this.options[i].value) {
					this.option[i].selected;
					this.setChanged( (val != this.oldValue));
					this.oldValue = this.value = val;
				}
				changed(this);
			};
			el.getValue = function() { return this.options[this.selectedIndex].value; };
			break;
			
			default:
			el.isObserver = false;
		}
		if( !el.isObserver ) continue;
		
		// Observer Eigenschaften
		el.observerList = [];
		el._Changed = 0;
		el.oldValue = el.value;
		
		// Observer Funktionen
		el.addObserver = addObserver;
		el.setChanged = function(bool)  { if(bool) this._Changed++; };
		el.getChanged = function()  { return this._Changed; };
		el.clearChanged = function() { this._Changed = 0; };
	}
	
	// und das Formular.
	f.observerList = [];
	f.getChanged = function () { return this.last.getChanged()};
	f.clearChanged = function () { return true;};
    f.getValue = function () { return this.last.getValue();};
    f.setValue = function (val) { return this.last.setValue(val);};

    f.addObserver = addObserver;
    f.changed = function(e)
    {
		for(var i = 0; i < this.observerList.length; i++) this.observerList[i].update(this.last, evt);
    };
}
