var
	httpRequestEndless = false;
	lastHttpRequestEndless = false;

/**
 * Returns the current row in an endless.
 */
function getCurrentRow(field) {
	var tr = field;
	while (tr.tagName != 'TR') {
		tr = tr.parentNode; 
	}	
	return tr.rowIndex;
}

/**
 * Returns the table for an endless.
 */
function getCurrentTable(field) {
	var tbl = field;
	while (tbl.tagName != 'TABLE') {
		tbl = tbl.offsetParent; 
	}
	return tbl;
}

/**
 * Returns true if the field is the last field in an endless row.
 */
function checkIfLastFieldInRow(field, my_table) {
	var tr = field;
  	while (tr.tagName != 'TR') tr = tr.parentNode; 

  	var td = tr.getElementsByTagName('TD');

	for (var i = (td.length -1); i >=0; i--) { 
		if (td[i].hasChildNodes) {
			var tdchild = td[i].childNodes;
			var helpResult = checkIfLastFieldInRowHelper(tdchild, tr, field, my_table);
			if (helpResult != undefined) return helpResult;
		}
	}
	return false;
}

/**
 * Helper function to checkIfLastFieldInRow.
 * Searches for the right INPUT or SELECT tag in the given td, tr and table.
 * Search down through DIV tags.
 */
function checkIfLastFieldInRowHelper(tdchild, tr, field, my_table) {
	for (j=0; j<tdchild.length; j++) {
		if (tdchild[j].tagName == 'DIV') {
			var divResult = checkIfLastFieldInRowHelper(tdchild[j].childNodes, tr, field, my_table);
			if (divResult != undefined) return divResult;
		} else if ((tdchild[j].tagName == 'INPUT') || (tdchild[j].tagName == 'SELECT')) {
			if ((!tdchild[j].disabled) && (!tdchild[j].readOnly)) {
				return ((field == tdchild[j]) && (tr.rowIndex == (my_table.rows.length-1)));			
			}				
		}
	}
	return undefined;
}

/**
 * Performs a delete in an endless for the current row.
 */
function removeRowFromTable(field,row) {
 	var tbl = getCurrentTable(field); 
	onEndlessChange(field,'delete',row);
}

/**
 * Returns true it is possible to insert more rows in an endless.
 */
function canInsertInEndless(table) {
	var maxrows = parseInt(table.getAttribute('maxrows'));
	var nrOfRows = table.tBodies[0].rows.length;
	return nrOfRows < maxrows;
}

/**
 * Returns true if it is possible to delete rows in an endless.
 */
function canDeleteInEndless(table) {
	var minrows = parseInt(table.getAttribute('minrows'));
	var nrOfRows = table.tBodies[0].rows.length;
	return (nrOfRows == 1 || nrOfRows > minrows);
}

/**
 * Handles the onKeyDown event for fields in endless controls.
 */
function onKeyDownEndless(field, event) {
	if (field.readOnly) return true;
 	var keynum;
  	var row;
  	if (window.event) {
		keynum = event.keyCode;
  	} else if (event.which) {
		keynum = event.which;
  	}
  	if (keynum == 46) { //Delete key
  		if (canDeleteInEndless(getCurrentTable(field))) {
	  		row = getCurrentRow(field);
			removeRowFromTable(field, row);
  		} else {
  			showEndlessMessage(3);
  			field.focus();
  		}
		return false;
  	} else if (keynum == 13) { //Enter key
  		if (field.onchange)
  			field.onchange();
		if (checkIfLastFieldInRow(field, getCurrentTable(field))) {
 		  	if (canInsertInEndless(getCurrentTable(field))) {
	 		  	row = getCurrentRow(field);
			  	onEndlessChange(field, 'add', row);
		  	} else {
		  		showEndlessMessage(1);
		  		field.focus();
		  	}
		} else {
			handleEnter(field);
	  	}
	  	return false;
  	} else if (keynum == 45) { //insert same as enter?
  		if (canInsertInEndless(getCurrentTable(field))) {
  			row = getCurrentRow(field);
		  	onEndlessChange(field, 'insert', row);
  		} else {
  			showEndlessMessage(2);
  			field.focus();
  		}
	  	return false;
  	} else if (keynum == 9) { //Tab key
  		if (event.shiftKey)
  			focusPrevField(getCurrentTable(field));
  		else
  			focusNextField(getCurrentTable(field));
  		return false;
  	} else if (keynum == 37 || keynum == 39) { //left or right key
  		if (field.type == 'text') {
	  		if (field.className != 'editmode') {
	  			return navigateInEndless(keynum, field);
	  		}
  		} else {
	  		return navigateInEndless(keynum, field);
  		}
  	} else if (keynum == 38 || keynum == 40) { //up or down key
		if (keynum == 40 && event.altKey) {
			var button = document.getElementById('button_' + field.id);
			if (button) {
		  		row = getCurrentRow(field);
				onSelectClick(field.id, row);
				menuActivate(field.id, row, button);
				return false;
			}
		}
	  	return navigateInEndless(keynum, field);
  	}
  	if (field.className != 'editmode') {
		/*
		switch (validation_code) {
			case 8: case 9: case 10: case 14:
				var str = field.value;
				field.value = str.replace(/ /g, '');
				field.value = str.replace(/\u00A0/g, '');
				break;
		}
		*/		
		field.className = 'editmode';
		field.style.textAlign = 'left';
		field.select();
	}
  	return true;
}

/**
 * Handles the navigation with arrow keys in endless controls.
 */
function navigateInEndless(keynum, field) {
	var table = getCurrentTable(field);
	var row = getCurrentRow(field);
	switch (keynum) {
		case 37: // left arrow
			var cells = table.tBodies[0].rows[row].cells;
			if (getChildField(cells[0]) == field) {
				return true;
			}
			var i;
			for (i = 0; i < cells.length; i++) {
				if (getChildField(cells[i]) == field) {
					break;
				}
			}
			i--;
			while (getChildField(cells[i]).readOnly || getChildField(cells[i]).disabled) {
				i--;
				if (i == -1)
					return true;
			}
			getChildField(cells[i]).focus();
			return false;
		case 38: // up arrow
			if (row == 0)
				return true;
			var fields = document.getElementsByName(field.id);
			var i = row - 1;
			while (fields[i].readOnly || fields[i].disabled) {
				i--;
				if (i == -1) 
					return true;
			}
			fields[i].focus();
			return false;
		case 39: // right arrow
			var cells = table.tBodies[0].rows[row].cells;
			if (getChildField(cells[cells.length-1]) == field)
				return true;
			var i;
			for (i = 0; i < cells.length; i++) {
				if (getChildField(cells[i]) == field) {
					break;
				}
			}
			i++;
			while (getChildField(cells[i]).readOnly || getChildField(cells[i]).disabled) {
				i++;
				if (i == cells.length)
					return true;
			}
			getChildField(cells[i]).focus();
			return false;
		case 40: // down arrow
			if (row == table.rows.length-1)
				return true;
			var fields = document.getElementsByName(field.id);
			var i = row + 1;
			while (fields[i].readOnly || fields[i].disabled) {
				i++;
				if (i == table.rows.length)
					return true;
			}
			fields[i].focus();
			return false;
	}
	return true;
}

/**
 * Get the field in a given cell. Searches down through DIV tags.
 */
function getChildField(cell) {
	if (cell.childNodes[0].tagName == 'DIV') {
		return getChildField(cell.childNodes[0]);
	} else {
		return cell.childNodes[0];
	}
}

/**
 * Handles the enter key in endless controls.
 */
function handleEnter(field) {
	var i;
	var j;
	for (i = 0; i < field.form.elements.length; i++)
	if (field == field.form.elements[i])
		break;
	i = (i + 1) % field.form.elements.length;
	//Now check the first non readonly/disabled field
	for (j = i; j < field.form.elements.length; j++) {		
		if ((!field.form.elements[j].disabled) && (!field.form.elements[j].readOnly)) {
			if (field.form.elements[j].type != 'button') {
				field.form.elements[j].focus();
				break;
			}
		}
	}
}

/**
 * Called when a field in endless controls gains focus.
 */
function onCellFocusGain(field) {
	field.className = 'focused';
	setFSHHint(field.id);
}

/**
 * Called when a field in endless controls loses focus.
 */
function onCellFocusLost(field) {
	field.className = 'enabled';
}

// This is a fix for IE. Needs to set focus in a timer.
var fieldToFocus;

/**
 * Sets the valus for a new endless row.
 */
function setDefaultRowValues(xmldoc, row) {
	var values = xmldoc.getElementsByTagName('newrowvalue');
	for (var i = 0; i < values.length; i++) {
		var value = values.item(i);
		field = document.getElementsByName(value.getAttribute('name'))[row];
		if (field.type == 'checkbox') {
			field.checked = value.getAttribute('value') == '1';
		} else {
			field.value = value.getAttribute('value');
		}
	}
}

/**
 * Clears an endless row to the default values.
 */
function clearTableCells(cells) {
	for (var i = 0; i < cells.length; i++) {
		if (cells[i].childNodes[0].className == 'focused')
			cells[i].childNodes[0].className = 'enabled';
		if (cells[i].childNodes[0].getAttribute('oldTextAlign') != null)
			cells[i].childNodes[0].style.textAlign = cells[i].childNodes[0].getAttribute('oldTextAlign');
	}
}

/**
 * Creates the Ajax request for changes in an endless control.
 */
function onEndlessChange(field, action, row) {
	httpRequestEndless = createXMLHttpRequest();
	if (!httpRequestEndless) {
		if (showMessage) showMessage('error.xmlhttp.endless');
		return false;
	}

	httpRequestEndless.onreadystatechange = endlessCallback;
	httpRequestEndless.open('POST', 'endlesschanged', false);
	httpRequestEndless.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	lastHttpRequestEndless = false;
	httpRequestEndless.send('bean=' + bean + '&field=' + field.name + '&action=' + action + '&row=' + row);
	if (window.XMLHttpRequest) {
		endlessCallback();
	}
}

/**
 * The Ajax callback for the endless request.
 */
function endlessCallback() {
	if (httpRequestEndless.readyState == 4) {
		if (httpRequestEndless.status == 200) {
			//This is a fix for IE7, which is calling this method twice with the same request, generating "ghost rows".
			if (lastHttpRequestEndless == httpRequestEndless.responseText) return;
			lastHttpRequestEndless = httpRequestEndless.responseText;

			var xmldoc = httpRequestEndless.responseXML;
			if (checkForTimeout(xmldoc)) {
				return;
			}
			
			var endless = xmldoc.getElementsByTagName('endless').item(0);
			var command = endless.getAttribute('command');
			var table = document.getElementById('tbl_' + endless.getAttribute('name'));
			var row = parseInt(endless.getAttribute('row'));
			
			if (command == 'add') {
				var clonedRow = table.rows[0].cloneNode(true);
				table.tBodies[0].appendChild(clonedRow);
				var cells = table.tBodies[0].rows[row+1].cells;
				clearTableCells(cells);
				
				for (var i = 0; i < cells.length; i++) {
					if (!cells[i].childNodes[0].readOnly) {
						cells[i].childNodes[0].focus();
						break;
					}
				}
			} else if (command == 'delete') {
				if (table.rows.length > 1)
					table.tBodies[0].removeChild(table.rows[row]);
				var elements = document.getElementsByName(endless.getAttribute('field'));
				fieldToFocus = elements[row == elements.length ? row-1 : row];
				//This is a fix for IE
				setTimeout('fieldToFocus.focus();', 1);
			} else if (command == 'insert') {
				var clonedRow = table.rows[0].cloneNode(true);
				table.tBodies[0].insertBefore(clonedRow, table.rows[row]);
				clearTableCells(table.tBodies[0].rows[row].cells);
				setDefaultRowValues(xmldoc, row);
				var elements = document.getElementsByName(endless.getAttribute('field'));
				elements[row].focus();
			} else {
				if (showMessage) showMessage('error.endless.command');
				window.location.reload();
			}
			
			updateAttributes(xmldoc);
		} else {
			lastHttpRequestEndless = false;
			if (showMessage) showMessage('error.request.endless', httpRequestEndless.status);
		}
	} else {
		lastHttpRequestEndless = false;
	}
}

