<?php
session_id();
session_start();
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
		"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Formular und JavaScript</title>
<script type="text/javascript">//<![CDATA[
function navigation(obj) {
// URL, auf der die zu bearbeitende Seite liegt
	var url = "http://localhost/AjaxIntro/Formular+JavaScript.php";
//	var url = "Formular+JavaScript.php";
	var httprequest;
	if (window.XMLHttpRequest) {
		// code for IE7+, Firefox, Chrome, Opera, Safari
		httprequest=new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		// code for IE6, IE5
		httprequest=new ActiveXObject("Microsoft.XMLHTTP");
	} else {
		alert("Your browser does not support XMLHttpRequest!");
	}
	httprequest.onreadystatechange=function() {
		if(httprequest.readyState==4) {

			url += "?sid=" + Math.random();
			url += '?' + obj.name + '=' + obj.value;
			alert('navigation: ' + url);
			document.getElementById("Form")=url;
		}
	}
	if (navigator.appName == 'Opera') {
	} else if (navigator.appName == 'Microsoft Internet Explorer') {
	} else if (navigator.appName == 'Netscape') {
		httprequest.overrideMimeType("text/xml"); // neccessary for responseXML in FF!! Although mime.types "text/xml xml" was set in apache!
	}
	httprequest.open("GET",url,true);
	httprequest.send(null);
}
function rowInput(obj) {
	var msg = "";
	var httprequest;
	if (window.XMLHttpRequest) {
		// code for IE7+, Firefox, Chrome, Opera, Safari
		httprequest=new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		// code for IE6, IE5
		httprequest=new ActiveXObject("Microsoft.XMLHTTP");
	} else {
		alert("Your browser does not support XMLHttpRequest!");
	}
	httprequest.onreadystatechange=function() {
		if(httprequest.readyState==4) {

			msg = obj.name + '<br/>' + obj.value;
			// alert('rowInput: ' + msg);
			document.getElementById("Output" + obj.name).innerHTML=msg;
		}
	}
	var url="Formular+JavaScript.php";
	url=url+"?sid="+Math.random();
	if (navigator.appName == 'Opera') {
	} else if (navigator.appName == 'Microsoft Internet Explorer') {
	} else if (navigator.appName == 'Netscape') {
		httprequest.overrideMimeType("text/xml"); // neccessary for responseXML in FF!! Although mime.types "text/xml xml" was set in apache!
	}
	httprequest.open("GET",url,true);
	httprequest.send(null);
}
//]]></script>
</head>
<body>

<?php

// adaptID
function adaptID($database, $table, $colKey, $colKeyValCur) {
	$fst = getFirstID($database, $table, $colKey);
	$lst = getLastID($database, $table, $colKey);
	if ($colKeyValCur < $fst) {
		$colKeyValCur = $fst;
	} else if ($colKeyValCur > $lst) {
		$colKeyValCur = $lst;
	} else {
		$colKeyValCur--;
		$colKeyValCur = getNextID($database, $table, $colKey, $colKeyValCur);
	}
	return $colKeyValCur;
}

// choseLanguageDictionary
function choseLanguageDictionary($languageInp, $table) {
	global $colKey, $database, $dict, $eDict, $isEnabled, $isNeeded, $isPredefined, $mDict, $pDict;
	// languageInp = 'de' | 'en' | 'us' | 'fr' | 'nl'
	// table in worldwallmaps = 'maps' | 'publishers' | 'exhibitions'

	$languageOut = $languageInp;
	switch ($languageInp) {
		case 'en':
		case 'us':
		case 'fr':
		case 'nl':
		case 'de':
			$images = $languageInp;
		break;
		default:
			$languageOut = 'en';
			$images = 'en';
		break;
	}

	switch ($table) {
		case 'customer':
			$colNames = $dict;
		break;
/*
		case 'maps':
			$colNames = $mDict;
		break;
		case 'publishers':
			$colNames = $pDict;
		break;
		case 'exhibitions':
			$colNames = $eDict;
		break;
*/
		default:
			$colNames = getColumnNames($database, $table);
			foreach ($colNames as $col) {
				$isEnabled[$col] = 1;
				$isNeeded[$col] = 1;
				$isPredefined[$col] = '';
			}
			$isEnabled[$colKey] = 0;
			$isNeeded[$colKey] = 0;
		break;
	}

	return array($languageOut, $images, $colNames);
}

// dbConn to database
function dbConn($database) {
	require_once('../dbConnect.php');
	dbConnect ($database, 'AjaxIntro');
	global $database;
	$sth = mysql_query("SET @@SESSION.character_set_client='utf8'");
	$sth = mysql_query("SET @@SESSION.character_set_connection='utf8'");
	$sth = mysql_query("SET @@SESSION.character_set_database='utf8'");
	$sth = mysql_query("SET @@SESSION.character_set_results='utf8'");
	$sth = mysql_query("SET @@SESSION.character_set_server='utf8'");
}

// echoAndLog
function echoAndLog($func, $msg, $bool) {
	global $msgEcho, $msgLog;
	if ($bool) {
		$str = '<p>Called by: '.$func.', message: '.$msg.' </p>';
		if ($msgEcho) {
			echo $str;
		}
		if ($msgLog) {
			error_log($str);
		}
	}
	return;
}

// getAllValues, all but different in column col.
function getAllValues($database, $table, $col) {
	$sql = "SELECT DISTINCT $col FROM $database.$table ORDER BY $col"; // Table is assumed not to be empty!
	$sth = mysql_query($sql);
	$values = array();
	while ($row = mysql_fetch_assoc($sth)) {
		$values[] = $row[$col];
	}
	mysql_free_result($sth);
	return $values;
}

// getColumnNames
function getColumnNames($database, $table) {
	$colNames = array();
	$sql = "SHOW columns FROM $database.$table";
	$sth = mysql_query($sql);
	while ($row = mysql_fetch_array($sth,MYSQL_ASSOC)) {
		$colNames[$row['Field']] = $row['Field'];
	}
	mysql_free_result($sth);
	return $colNames;
}

// getFirstID. There may be gaps in the sequence of id's.
function getFirstID($database, $table, $colKey) {
	$sql = "SELECT MIN($colKey) 'RESULT' FROM $database.$table";
	$sth = mysql_query($sql);
	$row = mysql_fetch_assoc($sth);
	$colKeyValCur = ($row['RESULT'] != '') ? $row['RESULT'] : 0;
	echoAndLog(__function__, "database: $database table: $table colKey: $colKey colKeyValCur: $colKeyValCur sql: $sql", false);
	return $colKeyValCur;
}

// getLastID. There may be gaps in the sequence of id's.
function getLastID($database, $table, $colKey) {
	$sql = "SELECT MAX($colKey) 'RESULT' FROM $database.$table";
	$sth = mysql_query($sql);
	$row = mysql_fetch_assoc($sth);
	$colKeyValCur = ($row['RESULT'] != '') ? $row['RESULT'] : 0;
	return $colKeyValCur;
}

// getNextID. There may be gaps in the sequence of id's.
function getNextID($database, $table, $colKey, $cur) {
	$sql = "SELECT MIN($colKey) 'RESULT' FROM $database.$table WHERE $colKey > $cur";
	$sth = mysql_query($sql);
	$row = mysql_fetch_assoc($sth);
	$colKeyValCur = ($row['RESULT'] != '') ? $row['RESULT'] : $cur;
	echoAndLog(__function__, "database: $database table: $table colKey: $colKey cur: $cur sql: $sql", false);
	return $colKeyValCur;
}

// getPreviousID. There may be gaps in the sequence of id's.
function getPreviousID($database, $table, $colKey, $cur) {
	$sql = "SELECT MAX($colKey) 'RESULT' FROM $database.$table WHERE $colKey < $cur";
	$sth = mysql_query($sql);
	$row = mysql_fetch_assoc($sth);
	$colKeyValCur = ($row['RESULT'] != '') ? $row['RESULT'] : $cur;
	echoAndLog(__function__, "database: $database table: $table colKey: $colKey cur: $cur sql: $sql", false);
	return $colKeyValCur;
}

// getRow
function getRow($colKeyValCur, $colKeyValPrv) {	
	global $database, $table, $colKey, $colNames, $isPredefined;
	if ($colKeyValCur == 0) {
		$colNames = getColumnNames($database, $table);
		// new dummy data
		$row = array();
		foreach ($colNames as $col=>$value) {
			$row[$col] = '';
		}
	} else if ($colKeyValCur == -1) {
		$row = array();
		foreach ($colNames as $col=>$value) {
			$row[$col] = $isPredefined[$col];
		}
		$row[$colKey] = $colKeyValPrv;
	} else {
		// Get data from database
		$sql = "SELECT * FROM $database.$table WHERE $colKey = $colKeyValCur";
		$sth = mysql_query($sql);
		$row = mysql_fetch_array($sth,MYSQL_ASSOC);
		mysql_free_result($sth);
	}
	return $row;
}

// getWhatTodo
function getWhatTodo($database, $table, $colKey) {
	global $allowedKeys, $colKeyValPrv;
	if (array_key_exists('number',$_GET) && $_GET['number'] != '') {
		// number field has been filled
		$number = $_GET['number'];
		if (is_numeric($number)) {
			// number field has been filled with a number
			$colKeyValCur = $number;
			$todo = 'Nmb';
			echoAndLog(__function__, "is_numeric($number)", true); //false
		} else {
			// number field has been filled with something not a number: 
			// reset default database `ajaxtest`.`customer`
			resetDefaultDatabase();
			$todo = 'Fst';
			$colKeyValCur = getFirstID($database, $table, $colKey);
			echoAndLog(__function__, "!is_numeric($number)", true);
		}
	} else if (array_key_exists('Fst_x',$_GET)) {
		// $_GET contains a 'Fst' field
		$todo = 'Fst';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Prv_x',$_GET)) {
		// $_GET contains a 'Prv' field
		$todo = 'Prv';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Nxt_x',$_GET)) {
		// $_GET contains a 'Nxt' field
		$todo = 'Nxt';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Lst_x',$_GET)) {
		// $_GET contains a 'Lst' field
		$todo = 'Lst';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Clr_x',$_GET)) {
		// $_GET contains a 'Clr' field
		$todo = 'Clr';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Ins_x',$_GET)) {
		// $_GET contains a 'Ins' field
		$todo = 'Ins';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Chg_x',$_GET)) {
		// $_GET contains a 'Chg' field
		$todo = 'Chg';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('Del_x',$_GET)) {
		// $_GET contains a 'Del' field
		$todo = 'Del';
		$colKeyValCur = $_GET[$colKey];
		echoAndLog(__function__, "array_key_exists('todo',_GET) $todo", true); //false
	} else if (array_key_exists('language',$_GET)) {
		// $_GET contains a 'language' field
		$todo = $_GET['language'];
		$colKeyValCur = $colKeyValPrv;
		echoAndLog(__function__, "array_key_exists('language',_GET) $todo", true); //false
	} else {
		// $_GET contains no valid 'todo' field
		if (count($_GET) == 0) {
			// The first call of the program. $_GET is still empty. Reset default database `ajaxtest`.`customer`
			resetDefaultDatabase();
		}
		$todo = 'Fst';
		$colKeyValCur = getFirstID($database, $table, $colKey);
		echoAndLog(__function__, "\$_GET contains no valid 'todo' field! \$todo now: $todo", true); //false
	}

	if (array_key_exists('language',$_GET)) {
	} else {
		if ($colKeyValCur == 0) {
			foreach ($allowedKeys as $key=>$value) {
				$allowedKeys[$key] = false;
			}
			$allowedKeys['Ins'] = true;
			echo "<p class='errors'>Table <b>$database.$table</b> with key <b>$colKey</b> is empty. Insert lines first!</p>";
		}
	}
	return array($todo, $colKeyValCur);
}

// main
function main() {
	global $allowedKeys, $colKey, $colNames, $colorLUT, $database, $dict, $eDict, $isEnabled, $isNeeded, $isPredefined, $languageDefault, $mDict, $msgEcho, $msgLog, $pDict, $table;
	// Set all navigation button to true. If $table is empty set $allowedKeys to false besides 'Ins'.
	$allowedKeys = array('Chg' => true, 'Clr' => true, 'Del' => true, 'Fst' => true, 'Ins' => true, 'Lst' => true, 'Nmb' => true, 'Nxt' => true, 'Prv' => true);

	// get colors
	$colorLUT = setColorLUT();
	$colormax = count($colorLUT);

	// get previous todo and row. Chg is done only if rowPrv and row are different.
	list($todoPrv, $rowPrv, $language, $colKeyValPrv) = sessionDataGet();

	// include arrays $dict, $isNeeded, $isEnabled, $ruleOfPlausibility, $isPredefined.
	include "./$language/dict.inc.php"; // führt bisweilen zum Absturz, da $language = ''

	// chose the $images folder and the $colnames depending on $language and $table
	list($language, $images, $colNames) = choseLanguageDictionary($language, $table);

	echoAndLog(__function__, "language: $language", true); //ganz raus
	// list the content of array $_GET
	// showArray('0', $colNames);

	// what todo depending on $_GET? If $table is empty set $allowedKeys to false besides 'Ins'.
	list($todo, $colKeyValCur) = getWhatTodo($database, $table, $colKey);
	
	switch ($todo) {
		case 'Chg':
			if ($allowedKeys['Chg']) {
				$hasChanged = false;
				foreach ($colNames as $col=>$value) {
					if ($rowPrv[$col] != $_GET[$col]) {
						$hasChanged = true;
						echoAndLog(__function__, "col: $col Prv: $rowPrv[$col] Act: $_GET[$col]", false);
						break;
					}
				}
				if ($hasChanged) {
					if (!parseForInputErrors($_GET)) {
						$setClause = makeSetClause($database, $table, $colKey, $colNames, 'Chg');
						$sql = "UPDATE $database.$table SET $setClause";
						mysql_query($sql) or die('die on query: '.$sql);
						$colKeyValCur = $_GET[$colKey];
						echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur sql: $sql", false);
						$sql = "FLUSH TABLES";
						mysql_query($sql) or die('die on query: '.$sql);
					} else {
						echoAndLog(__function__, "Input contains errors. Nothing changed", true);
					}
				} else {
					echoAndLog(__function__, "nothing changed", true);
				}
			}
			break;
		case 'Clr':
			if ($allowedKeys['Clr']) {
				$colKeyValPrv = $colKeyValCur;
				$colKeyValCur = -1;
			}
			break;
		case 'Del':
			if ($allowedKeys['Del']) {
				$sql = "DELETE FROM $database.$table WHERE $colKey=$colKeyValCur";
				mysql_query($sql);
				$colKeyValCur = adaptID($database, $table, $colKey, $colKeyValCur);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur sql: $sql", false);
				$sql = "FLUSH TABLES";
				mysql_query($sql) or die('die on query: '.$sql);
			}
			break;
		case 'Fst':
			if ($allowedKeys['Fst']) {
				$colKeyValCur = getFirstID($database, $table, $colKey);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			}
			break;
		case 'Ins':
			if ($allowedKeys['Ins']) {
				$hasChanged = false;
				foreach ($colNames as $col=>$value) {
					if ($col != $colKey && $_GET[$col] != '') {
						$hasChanged = true;
						echoAndLog(__function__, "col: $col Prv: $rowPrv[$col] Act: $_GET[$col]", false);
						break;
					}
				}
				if ($hasChanged) {
					if (!parseForInputErrors($_GET)) {
						$setClause = makeSetClause($database, $table, $colKey, $colNames, 'Ins');
						$sql = "INSERT INTO $database.$table SET $setClause";
						mysql_query($sql) or die('die on query: '.$sql);
						$colKeyValCur = getLastID($database, $table, $colKey);
						echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur sql: $sql", false);
						$sql = "FLUSH TABLES";
						mysql_query($sql) or die('die on query: '.$sql);
					} else {
						echoAndLog(__function__, "Input contains errors. Nothing entered", true);
					}
				} else {
					echoAndLog(__function__, "nothing entered", true);
				}
			}
			break;
		case 'Lst':
			if ($allowedKeys['Lst']) {
				$colKeyValCur = getLastID($database, $table, $colKey);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			}
			break;
		case 'Nmb':
			if ($allowedKeys['Nmb']) {
				//$colKeyValCur = $_GET['number'];
				$colKeyValCur = adaptID($database, $table, $colKey, $colKeyValCur);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			}
			break;
		case 'Nxt':
			if ($allowedKeys['Nxt']) {
				$colKeyValCur = getNextID($database, $table, $colKey, $colKeyValCur);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			}
			break;
		case 'Prv':
			if ($allowedKeys['Prv']) {
				$colKeyValCur = getPreviousID($database, $table, $colKey, $colKeyValCur);
				echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			}
			break;
		case 'en':
		case 'de':
		case 'fr':
		case 'nl':
		case 'us':
			list($todoOld, $row, $language, $colKeyValPrv) = sessionDataGet();
			$language = $todo;
			sessionDataStore($todoOld, $row, $language, $colKeyValCur);
			echoAndLog(__function__, "language: $language", true);
			break;
		default:
			$colKeyValCur = getFirstID($database, $table, $colKey);
			echoAndLog(__function__, "$todo: colKeyValCur: $colKeyValCur", false);
			break;
	}

	$row = getRow($colKeyValCur, $colKeyValPrv);

	// now we know the new todo and row
	sessionDataStore($todo, $row, $language, $colKeyValCur);
	
	echoAndLog(__function__, "todoPrv: $todoPrv: rowPrv[colKey]: $rowPrv[$colKey]", false);
	echoAndLog(__function__, "todoAct: $todo: rowAct[colKey]: $row[$colKey]", false);

	echo "<div style='position:absolute; top:355px; left:10px; width:175px; background: #7cfc00; overflow: auto;'><p>
	<a href='./Formular+JavaScript.php?language=de'><img style='border-width:0;padding:0;margin:0;' src='./de.gif' width='16' height='11' alt='de' title='de' /></a>
	<a href='./Formular+JavaScript.php?language=en'><img style='border-width:0;padding:0;margin:0;' src='./gb.gif' width='16' height='11' alt='gb' title='gb' /></a>
	<a href='./Formular+JavaScript.php?language=fr'><img style='border-width:0;padding:0;margin:0;' src='./fr.gif' width='16' height='11' alt='fr' title='fr' /></a>
	<a href='./Formular+JavaScript.php?language=nl'><img style='border-width:0;padding:0;margin:0;' src='./nl.gif' width='16' height='11' alt='nl' title='nl' /></a>
	<a href='./Formular+JavaScript.php?language=us'><img style='border-width:0;padding:0;margin:0;' src='./us.gif' width='16' height='11' alt='us' title='us' /></a>
	</p></div>";

	// Define <form>
	// Define dynamically generated <input>, name and value are taken from database.

	echo "
		<form action='' method='get' id='Form'>\n
	"; // mit class='yform' "tanzt" die Navigationszeile!

	// table navigation
	echo '
		<div style="position:absolute; top:200px; left:10px; width:175px; background: #7cfc00; overflow: auto;">
	<h3>Tabellennavigation</h3><p>&nbsp;</p><p>
	';
	// define button
	echo "<input type='image' src='./".$images."/first.png' alt='first.png' name='Fst' value='Fst' />\n";
	echo "<input type='image' src='./".$images."/previous.png' alt='previous.png' name='Prv' value='Prv' />\n";
	echo "<input type='text' size='4' maxlength='8' name='number' />\n"; // show $colKeyValCur, but do process only if changed!
	echo "<input type='image' src='./".$images."/next.png' alt='next.png' name='Nxt' value='Nxt' />\n";
	echo "<input type='image' src='./".$images."/last.png' alt='last.png' name='Lst' value='Lst' /><br/>\n";
	echo "<input type='image' src='./".$images."/clear.png' alt='clear.png' name='Clr' value='Clr' />\n";
	echo "<input type='image' src='./".$images."/insert.png' alt='insert.png' name='Ins' value='Ins' />\n";
	echo "<input type='image' src='./".$images."/change.png' alt='change.png' name='Chg' value='Chg' />\n";
	echo "<input type='image' src='./".$images."/delete.png' alt='delete.png' name='Del' value='Del' />\n";
	echo "</p></div>\n";
	
	// Define dynamically generated <input>. name and value are taken from database.
	presentTableEach($row);
	
	echo "</form>\n";

	// Some explanations
	echo '<div style="position:absolute; top:200px; left:650px; width:600px; background: #fafad2; overflow: auto;
">
	<h3>Entwicklungsziele für dieses Programm</h3><p>
1. Zeilen einer beliebigen Tabelle einer beliebigen Mysql-Datenbank sollen
	angesehen, geändert, gelöscht und eingefügt werden können. Es sollen nur
	die Namen der Datenbank, der Tabelle und der Schlüsselspalte bekannt sein.
	Das gilt sowohl für den PHP-, als auch für den JS-Teil. Als Beispiel
	wird die Datenbank <em>ajaxtest</em> mit der Tabelle <em>customer</em> und dem Schlüssel <em>id</em>
	verwendet. Die Folge der Schlüsselwerte der Tabelle <em>customer</em> hat Löcher!<br/>
2. Um die Ausgaben der Spaltenwerte an bestimmte Bildschirmpositionen zu
	bringen, werden p-Tags mit style- und id-Attribut automatisch erzeugt und
	positioniert. <br/>
3. Mit Ajax werden Ausgaben "on the fly" erzeugt, aber nicht weiter verarbeitet.<br/>
4. Die Button zur Tabellennavigation bestehen aus Graphiken.<br/>
	<img src="./en/first.png" alt="first.png"/>
	zeigt die Zeile mit dem niedrigsten Schlüssel.<br/>

	<img src="./en/previous.png" alt="previous.png"/>
	zeigt die Zeile mit dem nächst niedrigeren Schlüssel.<br/>

	Trägt man in <input type="text" size="4"/> einen Schlüssel ein,
	wird die Zeile mit diesem Schlüssel gezeigt. Wenn es diese Zeile nicht gibt, der Schlüssel aber 
	im Bereich MIN bis MAX liegt, wird die Zeile mit dem nächst höheren Schlüssel gezeigt.
	Liegt der Schlüssel außerhalb von MIN bis MAX, wird MIN bzw. MAX angezeigt.<br/>

	<img src="./en/next.png" alt="next.png"/>
	zeigt die Zeile mit dem nächst höheren Schlüssel.<br/>

	<img src="./en/last.png" alt="last.png"/>
	zeigt die Zeile mit dem höchsten Schlüssel.<br/>

	<img src="./en/clear.png" alt="clear.png"/>:
	Alle Felder bis auf das mit dem Schlüssel werden gelöscht. Jetzt kann man die Felder neu belegen.
	Gibt man anschließend <img src="./en/insert.png" alt="insert.png"/>,
	wird eine neue Zeile angelegt. Gibt man dagegen <img src="./en/change.png" alt="change.png"/>,
	wird die Zeile mit dem angezeigten Schlüssel geändert.<br/>

	<img src="./en/insert.png" alt="insert.png"/>:
	Die angezeigten Felder werden als neue Zeile eingetragen, falls sie nicht alle leer sind. 
	Die Zeile erhält einen Schlüssel, der um 1 größer als der bisher größste Schlüssel ist.<br/>

	<img src="./en/change.png" alt="change.png"/>
	ändert die Felder der angezeigten Zeile. Die Änderung erfolgt aber nur dann,
	wenn tatsächlich Änderungen vorgenommen wurden.<br/>

	<img src="./en/delete.png" alt="delete.png"/>
	löscht die angezeigte Zeile.<br/>
5. Für den allgemeinen Gebrauch wird jeweils beim Starten des Programms die default-Datenbank <em>ajaxtest</em>
	zurückgesetzt.
	<br/>
6. JavaScript wird aus HTML nach Ajax-Art aufgerufen,
	wenn in einer Tabellenzeile geschrieben wird: onkeyup=rowInput(this)<br/>
7. Multilingualität, benötigte Felder, vorbelegte Felder, zu ändernde Felder, Plausibilitätsprüfung:<br/>
--	Um die Spaltennamen in verständlicherer Form auszugeben und
	Mehrsprachigkeit zu ermöglichen, wird für jede Sprache ein Dictionary <em>dict</em>
	verwendet. Beispielhaft wurde das für die Sprachen EN und DE realisiert.
	Bei noch nicht realisierten Sprachen (auch NL und FR) wird auf Englisch
	ausgewichen. Dictionarys sind für die Tabellen <em>maps</em>, <em>publisher</em> und <em>exhibitions</em>
	aus der Datenbank <em>worldwallmaps</em> und für die Tabelle <em>customer</em> aus der Datenbank <em>ajaxtest</em>
	vorhanden. Bei anderen Tabellen werden die Spaltennamen als Dictionary verwendet.<br/>
	Ein Teil der Navigationsbutton ist sprachabhängig.<br/>
--	Benötigte Felder werden in einem Array $isNeeded definiert.<br/>
--	Vorbelegte Felder werden in einem Array $isPredefined definiert.<br/>
--	Zu ändernde und nicht zu ändernde Felder werden in einem Array $isEnabled definiert.<br/>
--	Die Felder müssen Regeln genügen. Die Regeln und die zugehörigen Fehlermeldungen werden in einem Array <em>$ruleOfPlausibility</em> definiert.<br/>
--	Die Sprachabhängigkeit wird so gelöst, dass es
	Unterordner <em>en</em>, <em>de</em>, ... gibt, die unter jeweils gleichem Namen
	die erforderlichen Dateien enthalten. <br/>
	Im Unterordner <em>en</em> gibt es die Dateien dict.inc.php, first.png, ...<br/>
	Im Unterordner <em>de</em> ebenfalls die Dateien dict.inc.php, first.png, ...<br/>
</p></div>';
}

// makeSetClause for UPDATE and INSERT
function makeSetClause($database, $table, $colKey, $colNames, $kind) {
	// UPDATE: $kind == 'Chg'
	// INSERT: $kind == 'Ins'
	$sql = '';
	foreach ($colNames as $col=>$value) {
		if ($col != $colKey) {
			$sql .= $col."='".$_GET[$col]."',";
		}
	}
	if ($kind == 'Chg') {
		$sql = substr($sql, 0, strlen($sql)-1);
		$sql .= " WHERE $colKey=$_GET[$colKey]";
	} else if ($kind == 'Ins') {
		$sql .= $colKey."='".(getLastID($database, $table, $colKey)+1)."'";
	}
	return $sql;
}

// parseForInputErrors
function parseForInputErrors($row) {
	global $ruleOfPlausibility;
	$hasError = false;

	echo '
		<div style="position:absolute; top:400px; left:10px; width:175px; background: red; overflow: visible;">
	<h3>Fehlerhafte Eingaben</h3>
	';
	$top = 1;
	$topIncr = 5;
	$left = 0;
	$height = 40;
	$width = 175;
	$i = 8;
	// apply rules
	foreach ($ruleOfPlausibility as $plausibility) {
		eval('$x = '.$plausibility['rule'].';');
		if (!$x) {
			$hasError = true;
			eval('$y = "' . $plausibility['emsg'] . '";');
			echo "
				<p style='position:relative; top:".$top."px; left:".$left."px; width:".$width."px; height:".$height."px;background-color:red;'>".$y."</p>\n
			"; 
			$top += $topIncr;
			$i++;
		}
	}
	echo '
		</div>
	';

	return $hasError;
}

// presentTableEach (without special knowledge concerning the table) 
function presentTableEach($row) {
	global $database, $table, $colKey, $colNames, $colorLUT, $isNeeded, $isEnabled, $isPredefined;
	echo "
		<div style='position:absolute; top:200px; left:200px; width:230px; background: #ffffd0; overflow: visible;'>\n
		<h3>Tabellenzeile</h3><p>Pflichtfelder <span style='color: red;'>*</span></p>
	";
	// Define dynamically generated <p> for input, see javascript.
	$top = 1;
	$topIncr = 5;
	$left = 10;
	$height = 40;
	$width = 210;
	$i = 8;
	foreach ($colNames as $col=>$value) {
		if ($isEnabled[$col]) {
			$disabled = '';
		} else {
			$disabled = "disabled='disabled'";
			// <input type='hidden'> neccessary, because disabled id is not transmitted!
			echo "<p class='normal'><input type='hidden' size='30' maxlength='50' name='".$col."' value='".$row["$col"]."' /></p>\n";
		}
		if ($isNeeded[$col]) {
			$needed = "<span style='color: red;'>*</span>";
		} else {
			$needed = '';
		}
		$row[$col] = htmlentities($row[$col],ENT_QUOTES,'UTF-8');
		echo "
			<p style='position:relative; top:".$top."px; left:".$left."px; width:".$width."px; height:".$height."px;background-color:".$colorLUT[$i].";' id='".$col."'>".$value.":".$needed."
			<br /><input type='text' size='30' maxlength='50' name='".$col."' ".$disabled." value='".$row["$col"]."' onkeyup='rowInput(this)'/></p>\n
		"; // onkeyup='rowInput(this)' 
		$top += $topIncr;
		$i++;
	}
	echo "
		</div>
	";

	// table row ajax output
	echo "
		<div style='position:absolute; top:200px; left:450px; width:180px; background: #add8e6; overflow: visible;'>
		<h3>Ajax-Ausgabe</h3><p>&nbsp;</p>
	";

	$top = 1;
	$topIncr = 5;
	$left = 10;
	$height = 40;
	$width = 160;
	$i = 8;
	foreach ($colNames as $col=>$value) {
		echo "
		<p style='position:relative; top:".$top."px; left:".$left."px; width:".$width."px; height:".$height."px; background-color:".$colorLUT[$i].";' id='Output".$col."'>".$value.":<br />".$row[$col]."</p>\n
		";
		$top += $topIncr;
		$i++;
	}
	echo "<p class='normal'>&nbsp;</p></div>\n";
}

// resetDefaultDatabase
function resetDefaultDatabase() {
	global $database, $table, $colKey, $dbConnection, $dbh;
	$sql = "DELETE FROM `ajaxtest`.`customer`";
	mysql_query($sql) or die('die on query: '.$sql);
	$sql = "
		INSERT INTO `ajaxtest`.`customer` (id, FirstName, LastName, Age, Hometown, Job, Email) VALUES
		(3, 'Peter', 'Griffin', 41, 'Quahog', 'Brewery', 'peter.griffin@web.com'),
		(6, 'Lois', 'Malcolm', 40, 'Newport', 'Piano Teacher', 'lois_malcolm@yahoo.org'),
		(9, 'Joseph', 'Swanson', 39, 'Quahog', 'Police Officer', 'info@police.us'),
		(12, 'Glenn', 'Quagmire', 41, 'Quahog', 'Pilot', 'office@iata.com')
	";
	mysql_query($sql) or die('die on query: '.$sql);
	return;
}

// sessionDataDefault (store and get)
function sessionDataDefault() {
	global $languageDefault;
	$todo = 'Fst';
	$_SESSION['todo'] = $todo;
	$row = getRow(0, 0);
	$_SESSION['row'] = $row;
	$language = $languageDefault;
	$_SESSION['language'] = $language;
	$colKeyValPrv = 0;
	$_SESSION['colKeyValPrv'] = $colKeyValPrv;

	return array($todo, $row, $language, $colKeyValPrv);
}

// sessionDataGet
function sessionDataGet() {
	global $languageDefault;
	if (count($_GET) == 0) {
		// The first call of the program. $_GET is still empty.
		list($todo, $row, $language, $colKeyValPrv) = sessionDataDefault();
		echoAndLog(__function__, " todo: $todo, language: $language, colKeyValPrv: $colKeyValPrv", true); //false
	} else {
		if (isset($_SESSION['todo'])) {
			$todo = $_SESSION['todo'];
		} else {
			echoAndLog(__function__, "'todo' is not set in _SESSION<br />", true);
			$todo = 'Fst';
			$_SESSION['todo'] = $todo;
		}
		if (isset($_SESSION['row'])) {
			$row = $_SESSION['row'];
		} else {
			echoAndLog(__function__, "'row' is not set in _SESSION<br />", true);
			$row = getRow(0, 0);
			$_SESSION['row'] = $row;
		}
		if (isset($_SESSION['language'])) {
			$language = $_SESSION['language'];
		} else {
			echoAndLog(__function__, "'language' is not set in _SESSION<br />", true);
			$language = $languageDefault;
			$_SESSION['language'] = $language;
		}
		if (isset($_SESSION['colKeyValPrv'])) {
			$colKeyValPrv = $_SESSION['colKeyValPrv'];
		} else {
			echoAndLog(__function__, "'colKeyValPrv' is not set in _SESSION<br />", true);
			$colKeyValPrv = 0;
			$_SESSION['colKeyValPrv'] = $colKeyValPrv;
		}
	}
	return array($todo, $row, $language, $colKeyValPrv);
}

// sessionDataStore
function sessionDataStore($todo, $row, $language, $colKeyValCur) {
	$_SESSION['todo'] = $todo;
	$_SESSION['row'] = $row;
	$_SESSION['language'] = $language;
	$_SESSION['colKeyValPrv'] = $colKeyValCur;
	return;
}

// setColorLUT
function setColorLUT() {
	$colorLUT = array(0 =>
	'#fffacd',
	'#f0f0f0',
	'#ffffd0',
	'#7cfc00',
	'#add8e6',
	'#f08080',
	'#e0ffff',
	'#fafad2',
	'#90ee90',
	'#d3d3d3',

	'#ffb6c1',
	'#ffa07a',
	'#20b2aa',
	'#87cefa',
	'#778899',
	'#b0c4de',
	'#32cd32',
	'#faf0e6',
	'#66cdaa',
	'#ba55d3',
	'#3cb371',
	'#7b68ee',
	'#00fa9a',
	'#48d1cc',
	'#c71585',
	'#f5fffa',
	'#ffe4e1',
	'#ffe4b5',
	'#ffdead',
	'#fdf5e6',
	'#6b8e23',
	'#ffa500',
	'#ff4500',
	'#da70d6',
	'#eee8aa',
	'#98fb98',
	'#afeeee',
	'#db7093',
	'#ffefd5',
	'#ffdab9',
	'#cd853f',
	'#ffc0cb',
	'#dda0dd',
	'#b0e0e6',
	'#bc8f8f',
	'#4169e1',
	'#8b4513',
	'#fa8072',
	'#f4a460',
	'#2e8b57',
	'#fff5ee',
	'#a0522d',
	'#87ceeb',
	'#6a5acd',
	'#708090',
	'#fffafa',
	'#00ff7f',
	'#4682b4',
	'#d2b48c',
	'#d8bfd8',
	'#ff6347',
	'#40e0d0',
	'#ee82ee',
	'#f5deb3',
	'#f5f5f5',
	'#9acd32'
	);
	return $colorLUT;
}

// showArray
function showArray($depth, $array) {
	$size = count($array);
	$i = 0;
	$depthOld = $depth;
	echo "<p class='normal'> depth: $depthOld array has $size elements!&nbsp;&nbsp;&nbsp;";
	foreach ($array as $key => $value) {
		$depth = $depthOld . '.' . $i . ' ';
		if (is_array($array[$key])) {
			showArray($depth, $array[$key]);
		} else {
			echo $depth . '("'.$key.', '.$value.'")&nbsp;&nbsp;&nbsp;';
		}
		$i++;
	}
	echo "</p>\n";
	return;
}

// variables
global $colKey, $database, $languageDefault, $msgEcho, $msgLog, $table;
$msgEcho = true; // Provides echo, should be true during testing and development, false in production
$msgLog = false; // Provides error_log, can be true even in production
$database = "ajaxtest";
$table = "customer";
$languageDefault = "en";
$colKey = "id"; // name of column being the key column of table, type must be numeric NOT NULL, values can not be changed!

// connect with database
$database = 'ajaxtest';
dbConn($database);

/*
// start test of functions
$myArray = array('Chg' => true, 'Del' => 'leD', 'Fst' => array('my' => 'mein', 'yours' => 'dein'), 'Ins' => true, 'Lst' => true, 'Nmb' => true, 'Nxt' => true, 'Prv' => true);
showArray('0', $myArray);

echo '<p>';
$getFirstID = getFirstID($database, $table, $colKey);
echo "getFirstID: $getFirstID<br/>\n";

$getLastID = getLastID($database, $table, $colKey);
echo "getLastID: $getLastID<br/>\n";

$getAllValues = getAllValues($database, $table, $colKey);
foreach ($getAllValues as $key=>$value) {
	echo "getAllValues key: $key value: $value<br/>\n";
}
foreach ($getAllValues as $key=>$cur) {
	echo "cur: $cur getNextID:".getNextID($database, $table, $colKey, $cur)."<br/>\n";
}

$getAllValues = getAllValues($database, $table, $colKey);
foreach ($getAllValues as $key=>$value) {
	echo "getAllValues key: $key value: $value<br/>\n";
}
foreach ($getAllValues as $key=>$cur) {
	echo "cur: $cur getPreviousID:".getPreviousID($database, $table, $colKey, $cur)."<br/>\n";
}
echo '</p>';
// end test of functions
*/

main();


?>

<div id="Output" style="position:absolute; top:10px; left:10px; width:100%; background: #7cfc00;"></div>

</body>
</html>