/**
 * Ten plik jest częścią pakietu SOWA-WWW. Ten plik jest częścią pakietu SOWA-WWW.
 *
 * Plik JavaScript obsługujący formularze z kryteriami
 *
 * @package SOWA-WWW 
 * @author Michał Fryska
 * @copyright SOKRATES-Software (http://www.sokrates.pl)
 * 
 * $Id: formz.js 130 2008-08-21 08:03:34Z szumek $
 */

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); };

function doGetCaretPosition(control) {
	if (control.selectionStart == undefined) {
		// Sposób wręcz karygodny, ale podobno "polecany" przez Microsoft :P
		control.focus();
		var tmpt = control.value;
		var st = '~~`~';
		var range = document.selection.createRange();
		range.text = st;
		var pos = control.value.search(st);
		control.value = tmpt;
		return pos;
	}
	else {
		return control.selectionStart;
	}
}

function doSetCaretPosition(ctrl, pos) {
	if(ctrl.setSelectionRange) {
		ctrl.focus();
		ctrl.setSelectionRange(pos,pos);
	}
	else if (ctrl.createTextRange) {
		var range = ctrl.createTextRange();
		range.collapse(true);
		range.moveEnd('character', pos);
		range.moveStart('character', pos);
		range.select();
	}
}

function insertAtCaret(control, txt) {
	control.focus();
	if (control.selectionStart == undefined) {
		var range = document.selection.createRange();
		range.text = txt;
		range.moveStart('character', txt.length);
	}
	else {
		var t=control.value;
		var p=control.selectionStart;
		control.value = t.substring(0,p)+txt+t.substring(p);
		control.setSelectionRange(p+txt.length,p+txt.length);
	}
}

/**
 * Konstruktor.
 * @param Nazwę formularza HTML w którym się znajduuje nasz form.
 */
function SowwwaFormz(formName) {
	/** Nazwa obiektu */
	this.selfName;
	/** Nazwa formularza */
	this.formName = formName;
	/** Referencya do obiektu formularza HTML */
	this.formObject;
	/** nazwa bazy danych [dość potrzebne w jednym krytycznym momencie] */
	this.baseName;
	/** Tablica dostępnych kryteriów [każdy element to dwuelementowa tablica z nazwą i tytułem kryterium] */
	this.crittab;
	/** Tablica dobrych indeksów [KHW] */
	this.kwhIndexes;
	/** Nazwa elementu zawierającego podsumowanie [opis] */
	this.summarySpanName;
	/** Referencya do owego obiektu */
	this.summarySpanObject;
	/** Tablica do odpowiedniej obsługi zdarzenia onChange dla combosów. */
	this.onChangeTab;
	/** Tablica z maskami, które trzeba skontrolowac [fieldy] przed wysłaniem. */
	this.maskFieldsTab;

	this.init();
}

/**
 * Inicjalizuje nasz obiekt.
 */
SowwwaFormz.prototype.init = function() {
	this.formObject = document.getElementById(this.formName);
	this.crittab = new Array();
	this.khwIndexes = new Array();
	this.onChangeTab = new Array();
	this.maskFieldsTab = new Array();
}

/**
 * Rejestruje siebie samego - swoją nazwę w swoich strukturach.
 * @param String selfName Nazwa siebie samego
 */
SowwwaFormz.prototype.registerSelf = function(selfName) {
	this.selfName = selfName;
}

/**
 * Ustawia nazwę bazy danych. Dość istotna operacja, polecam robić to od razu po selfrejestracji.
 * @param String baseName Nazwa bazy SOWY [np. SOWA1, SOWA2, SOWA3]
 */
SowwwaFormz.prototype.setBaseName = function(baseName) {
	this.baseName = baseName;
}

/**
 * Ustawia nazwę elementu [span'a], który ma zawierać opis "human form" podsumowania.
 * @param String spanName Nazwa spanu
 */
SowwwaFormz.prototype.setSummaryItem = function(spanName) {
	this.summarySpanName = spanName;
	this.summarySpanObject = document.getElementById(this.summarySpanName);
}

/**
 * Rejestruje kryterium. Nazwę i tytuł kryterium, oraz boolean czy ma ono być od razu
 * domyślnie oznaczone jako używane, czy tez nie.
 * @param String critName Nazwa kryterium
 * @param String critTitle Tytuł [opis] kryterium
 * @param Bool used Informacja, czy kryterium jest w użyciu, czy nie :)
 */
SowwwaFormz.prototype.registerCriterium = function(critName, critTitle, used) {
	this.crittab.push( new Array(critName, critTitle, used) );
}

/**
 * Rejestruje "dobry" indkes KHW - dla takiego indeksu będzie wyświetlany button [o ile się pojawi na formularzyku]
 * @param String indexName Nazwa indeksu
 * @param String khw Symbol KHW
 */
SowwwaFormz.prototype.registerKHWIndex = function(indexName, khw) {
	this.khwIndexes.push( new Array(indexName, khw ));
}

/**
 * Rejestruje kontrolki indkesu jako takiego
 * @param String comboName Nazwa kombo boxa obsługującego indeks
 * @param String buttonName nazwa przycisku wywzwalającego okienko z indeksem
 * @param String editName Nazwa pola, w którym edytuje się treść kryterium, celem umieszczenia tam wybranych pozycji z indeksu.
 */
SowwwaFormz.prototype.registerIndexControls = function(comboName, buttonName, editName) {
	if ( this.baseName != 'SOWA3' )
		this.onChangeTab.push( new Array( comboName, buttonName, editName ) );
}

/**
 * Rejestruje kontrolkę z maską, którą będzie trzeba skontrolować przez wysłaniem formsa.
 * @param String critName Nazwa kryterium
 * @param String controlName Nazwa kontrolki
 */
SowwwaFormz.prototype.registerMaskField = function(critName, controlName) {
	this.maskFieldsTab.push( new Array(critName, controlName) );
}

/**
 * Ustawia wpis do algorytmu obliczania human formsa, czyli czytelnego dla ludzia opisu kryterium.
 * Co to oznacza - otóż jeśli method jest 'value' to sprawdza wartość elementu i wyświetla ją.
 * Jeśli method jest 'check', to sprawdza czy element jest zaznaczony i jeśli tak - wyświetla
 * staticText. Aderłajz - wyświetla staticText.
 * @param String critName Nazwa Kryterium
 * @param String itemName Nazwa elementu formularza
 * @param String method Sposób generowania formy czytelnej dla człeka
 * @param String staticText Tekst statyczny wyświetlany gdy method tak nakazuje.
 */
SowwwaFormz.prototype.setHumanFormAlg = function(critName, itemName, method, staticText) {
	for (var i=0; i<this.crittab.length; i++)
		if (this.crittab[i][0] == critName) {
			if ( this.crittab[i].length < 4 )
				this.crittab[i][3] = new Array();
			this.crittab[i][3].push( new Array(itemName, method, staticText) );
		}
}

/**
 * Zwraca czytelny dla człowieka opis kryterium na podstawie algorytmu ustawionego wcześniej.
 * @param String critName Nazwa kryterium
 * @return String Czytelny tekst opisu kryterium
 */
SowwwaFormz.prototype.getCriteriumHumanForm = function(critName) {
	var description = '';
	for (var i=0; i<this.crittab.length; i++)
		if (this.crittab[i][0] == critName ) {
			var alg = this.crittab[i][3];
			for (var j=0; j<alg.length; j++) {
				if (alg[j][1] == 'value') {
					var item = document.getElementById(alg[j][0]);
					if (item.value == '') description += ' <i>brak</i>';
					else description += ' '+item.value.replace(/</g,"&lt;").replace(/>/g,"&gt;");
				}
				else if (alg[j][1] == 'check') {
					var item = document.getElementById(alg[j][0]);
					if (item.checked)
						description += ' '+alg[j][2];
				}
				else { // W domyśle static lub cokolwiek innego
					description += ' '+alg[j][2];
				}
			}
			break;
		}
	return description;
}

/**
 * Uaktualnia podsumowanie formularza - czytelne dla człowieka podsumowanie wprowadzonych kryteriów.
 */
SowwwaFormz.prototype.updateSummary = function() {
	var innerHTML = '<b>Użyte kryteria</b><ol style="margin-top: 0px;">';
	var counter = 0;
	for (var i=0; i<this.crittab.length; i++) {
		var critname = this.crittab[i][0];
		var checkbox = document.getElementById('chk_'+critname);
		if ( checkbox.checked ) {
			counter++;
			innerHTML += '<li>';
			
			if (this.crittab.length > 1) {
				innerHTML += '<a href="#" onClick="'+this.selfName+'.removeCriterium(\''+critname+'\')">';
				innerHTML += '<img src="img/usun.png" border="0" style="vertical-align:text-bottom;"/></a>';
			}
			innerHTML += '<b><a href="#" onClick="'+this.selfName+'.activateCriteriaEditor(\''+critname+'\')">'+this.crittab[i][1]+'</a>:</b> ';
			innerHTML += this.getCriteriumHumanForm(critname)+'</li>';
		}
	}
	innerHTML += '</ol>';
	if ( counter == 0 ) innerHTML = '';
	this.summarySpanObject.innerHTML = innerHTML;
}


/**
 * Zwraca opis kryterium o podanej nazwie.
 * @param String critName Nazwa kryterium
 * @return String Opis kryterium
 */	
SowwwaFormz.prototype.getCriteriumDescription = function(critName) {
	for (var i=0; i < this.crittab.length; i++)
		if (this.crittab[i][0] == critName) return this.crittab[i][1];
	return 'Błąd: nieznane kryterium! '+critName;
}


/**
 * Czyści formularz wskazanego kryterium. [usuwa zeń wartości]
 * @param String critName Nazwa kryterium
 */
SowwwaFormz.prototype.clearForm = function(critName) {
	var prefix = critName+'-';
	for (var i=0; i < this.formObject.elements.length; i++) {
		e = this.formObject.elements[i];
		if ( e.name.substr(0,prefix.length) == prefix) {
			if (e.tagName == 'SELECT' )			e.selectedIndex = 0;
			else if (e.type == 'checkbox')		e.checked = false;
			else if (e.tagName != 'BUTTON')		e.value = '';
		}
	}
}

/**
 * Deaktywuje edytory WSZYSTKICH kryteriów.
 */
SowwwaFormz.prototype.deactivateCriteriaEditors = function() {
	for ( var i = 0; i < this.crittab.length; i++ ) {
		var div = document.getElementById('div_'+this.crittab[i][0]);
		div.style['visibility'] = 'hidden';
		this.showHideButtons(this.crittab[i][0], false);
	}
}

/**
 * Aktywuje edytor kryterium o podanej nazwie.
 * @param String critName Nazwa kryterium
 */
SowwwaFormz.prototype.activateCriteriaEditor = function(critName) {
	this.deactivateCriteriaEditors();
	var base_tab = document.getElementById('basic_tab');
	if (critName == '') {
		base_tab.style['visibility'] = 'visible';
		var div = base_tab;
	}
	else {
		base_tab.style['visibility'] = 'hidden';
		div = document.getElementById('div_'+critName);
		div.style['visibility'] = 'visible';
		this.showHideButtons(critName, true);
		
		// Nim pokażemy taba edycyjnego odhaczemy fakt włączenia kryterium.
		var checkbox = document.getElementById('chk_'+critName);
		checkbox.checked = true;
		
		// Span:
		span = document.getElementById('span_'+critName);
		span.innerHTML = '<b>'+this.getCriteriumDescription(critName)+'</b>';
	}
	// Powyższy div jest usytuowany w tabberze!
	// To jest tab pokazywany/chowany - nam zależy na divie głównym - tabberlive;
	var tabberlive = div.parentNode.parentNode;
	tabberlive.tabber.tabShow(0);
	
	this.updateSummary();
}

/**
 * Usuwa kryterium z listy aktywnych i oczywiście deaktywuje jej edytor [aktywując inny]
 * @param String critName Nazwa kryterium
 */
 SowwwaFormz.prototype.removeCriterium = function(critName) {
 	if ( confirm('Na pewno chcesz wyłączyć kryterium \''+this.getCriteriumDescription(critName)+'\'?')) {
 		// Nim pokażemy taba edycyjnego odhaczemy fakt włączenia kryterium.
 		var checkbox = document.getElementById('chk_'+critName);
 		checkbox.checked = false;
 
 		// Span:
 		var span = document.getElementById('span_'+critName);
 		span.innerHTML = this.getCriteriumDescription(critName);
 		
 		this.clearForm(critName);
 
 		// A na koniec musimy zdecydować się które kryterium aktywować - najlepiej pierwsze z brzegu!
 		var newcrit = '';
 		for (var i=0; i<this.crittab.length; i++) {
 			checkbox = document.getElementById('chk_'+this.crittab[i][0]);
 			if ( checkbox.checked ) {
 				newcrit = this.crittab[i][0];
 				break;
 			}
 		}
 
 		this.activateCriteriaEditor(newcrit);
 	}
 }
 
 /**
  * Inicjuje edytory kryteriów na wypadek, gdyby to był reenter [trzeba odhaczyć zaznaczone],
  * tudzież aktywuje domyślny [pierwszy] jeśli to nie był reenter.
  */
SowwwaFormz.prototype.initCriteriaEditors = function() {
	// czyścimy - bo Firefox zachowuje niepotrzebnie zaznaczenia checkboxów.
	var critname;
	var found = false;
	for ( var i = 0; i < this.crittab.length; i++) {
		var checkbox = document.getElementById('chk_'+this.crittab[i][0]);
		if (this.crittab[i][2]) {
			checkbox.checked = true;
			if ( !found ) {
				found = true;
				critname = this.crittab[i][0];
				var div = document.getElementById('div_'+critname);
				div.style['visibility'] = 'visible';
			}
		}
		else
			checkbox.checked = false;
	}
	if ( !found ) {
		// Oznacza to zatem, że winniśmy włączyć pierwsze - domyślne kryterium.
		critname = this.crittab[0][0];
		var checkbox = document.getElementById('chk_'+critname);
		checkbox.checked = true;
		var div = document.getElementById('div_'+critname);
		div.style['visibility'] = 'visible';
	}
	var base_tab = document.getElementById('basic_tab');
	base_tab.style['visibility'] = 'hidden';
	this.updateSummary();
	this.showHideButtons(critname, true);	
}

/**
 * Pobiera symbol KHW dla wartości z podanego combosa. Z uwagi na to, że inaczej działa SOWA3 a inaczej inne,
 * koniecznie trzeba mieć ustawione this.baseName
 * @param String comboName Nazwa combosa
 * @return String Symbol KHW
 */
SowwwaFormz.prototype.getKHW = function(comboName) {
	var comboCtrl = document.getElementById(comboName);
	var khw = '';
	if ( this.baseName == 'SOWA3' ) {
		khw = comboCtrl.value;
	}
	else {
		for (var i=0; i< this.khwIndexes.length; i++)
			if (this.khwIndexes[i][0] == comboCtrl.value)
				khw = this.khwIndexes[i][1];
	}
	return khw;
}

/**
 * Pokazuje/chowa przycisk związany z podanym combosem, o ile wartość KHW jest niepusta, czyli że istnieje indeks.
 * @param String buttonName Nazwa przycisku
 * @param String comboName nazwa combosa
 */
SowwwaFormz.prototype.showHideButton = function(buttonName, comboName) {
	var comboObj = document.getElementById(comboName);
	var buttonObj = document.getElementById(buttonName);
	var khw = this.getKHW(comboName);
	if (khw == '')
		buttonObj.style['visibility'] = 'hidden';
	else
		buttonObj.style['visibility'] = 'visible';		
}

/**
 * Wykonuje operacje takie, aby pokazać/ukryć przycisk dla indeksu w odpowiednich momentach, 
 * gdy obiekt o podanym ID zmienia swój stan.
 * @param String objectId Identyfikator obiektu
 */
SowwwaFormz.prototype.processOnChangeIndex = function(objectId) {
	for (var i = 0; i < this.onChangeTab.length; i++ ) {
		if (objectId == this.onChangeTab[i][1]) {
			this.showHideButton(this.onChangeTab[i][0], this.onChangeTab[i][1]);
			break;
		}
	}
}

/**
 * Pokazuje/ukrywa wszystkie przyciski zapodanego kryterium. Jeśli visibility jest false,
 * to chowa wszystkie, jeśli true - to pokazuje tylko te, które warto.
 * @param String critName Nazwa kryterium
 * @param Bool visibility Czy pokazać, czy schować przyciski (TRUE pokazać)
 */
SowwwaFormz.prototype.showHideButtons = function(critName, visibility) {
	for (var i = 0; i < this.onChangeTab.length; i++ ) {
		if (this.onChangeTab[i][0].substr(0,critName.length) == critName) {
			if ( visibility ) {
				this.showHideButton(this.onChangeTab[i][0], this.onChangeTab[i][1]);
			}
			else {
				var buttonObj = document.getElementById(this.onChangeTab[i][0]);
				buttonObj.style['visibility'] = 'hidden';
			}
		}
	}
}

/**
 * Sprawdza, czy choć jedno kryterium zostało właściwie wypełnione i czy można posłać formularz zapytania.
 * @return Bool TRUE jeśli jest OK.
 */
SowwwaFormz.prototype.isFormFilled = function() {
	var isOK = false;
	for (var i = 0; i < this.crittab.length; i++) {
		var checkboxName = 'chk_'+this.crittab[i][0];
		var checkbox = document.getElementById(checkboxName);
		if (checkbox.checked) {
			var isvalueset = false;
			var isnonselect = false;
			// Teraz musimy dla danego kryterium sprawdzić, czy choć jeden element został zaznaczony!
			var prefix = this.crittab[i][0]+'-';
			for (var j=0; j < this.formObject.elements.length; j++) {
				e = this.formObject.elements[j];
				if ( e.name.substr(0,prefix.length) == prefix) {
					if (e.tagName) {
						if (e.tagName != 'SELECT' && e.tagName != 'BUTTON' ) {
							isnonselect = true;
							if (e.type == 'checkbox') {
								if (e.checked)
									isvalueset = true;
							}
							else if (e.value.trim() != '')
								isvalueset = true;
						}
					}
				}
			}
			if (!isnonselect || isvalueset) {
				isOK = true;
				break;
			}
		}
	}
	return isOK;
}

/**
 * Sprawdza, czy pola masek są właściwie wypełnione. Jeśli nie są to krzyczy i ustawia się na błędnej 
 * masce.
 * @return Bool TRUE jeśli maski sa OK
 */
SowwwaFormz.prototype.checkMasks = function() {
	for (var i=0; i < this.maskFieldsTab.length; i++ ) {
		var checkbox = document.getElementById('chk_'+this.maskFieldsTab[i][0]);
		if ( checkbox.checked ) {
			var control = document.getElementById(this.maskFieldsTab[i][1]);
			if ( !control.maskEdit.isValidValue() ) {
				alert('Wartość \''+control.maskEdit.getText()+'\' nie jest prawidłowa dla tego pola.');
				this.activateCriteriaEditor(this.maskFieldsTab[i][0]);
				control.focus();
				return false;
			}
		}
	}
	return true;
}
