// data source
	var DATA_SOURCE = "ajax_search.php";
	
	// names of the book detail tags
	var DETAIL_NAMES = new Array( "ProductName", "Author", "ReleaseDate", "Manufacturer", "ImageUrlMedium", "ListPrice" ) ;
	
	// some global result vars
	var intResultLen = 0;
	
	var intManufacturer = -1;
	
	var action = 0;
	
	var strRecentSearch = '';
	
	var arrArticles = new Array();
	
	// global timer to monitor search input
	var timerRessource = null;
	
	// time to wait before sending a search request
	// waiting is necessary to ensure input has finished
	var WAIT_TIME = 100;
	
	// global xmlhttprequest object
	var xmlHttp = false;
	
	// current request param
	// save it for showing server response in a new window
	var strRequestParam;
	
	// register monitor function for search input field
	window.onload = function( ) { 
		document.getElementById( "articleid" ).onkeyup = doSearch;
		document.getElementById( "manufacturer" ).onchange = doManufacturer;
		intManufacturer = document.getElementById( "manufacturer" ).value;
	}
	
	/** AJAX functions **/
	
	// constants
	var REQUEST_GET		= 0;
	var REQEST_POST		= 2;
	var REQUEST_HEAD	= 1;
	var REQUEST_XML		= 3;
	
	
	
	/**
	 * instantiates a new xmlhttprequest object
	 *
	 * @return xmlhttprequest object or false
	 */
	function getXMLRequester( )
	{
		var xmlHttp = false;
				
		// try to create a new instance of the xmlhttprequest object		
		try
		{
			// Internet Explorer
			if( window.ActiveXObject )
			{
				for( var i = 5; i; i-- )
				{
					try
					{
						// loading of a newer version of msxml dll (msxml3 - msxml5) failed
						// use fallback solution
						// old style msxml version independent, deprecated
						if( i == 2 )
						{
							xmlHttp = new ActiveXObject( "Microsoft.XMLHTTP" );	
						}
						// try to use the latest msxml dll
						else
						{
							
							xmlHttp = new ActiveXObject( "Msxml2.XMLHTTP." + i + ".0" );
						}
						break;
					}
					catch( excNotLoadable )
					{						
						xmlHttp = false;
					}
				}
			}
			// Mozilla, Opera und Safari
			else if( window.XMLHttpRequest )
			{
				xmlHttp = new XMLHttpRequest();
			}
		}
		// loading of xmlhttp object failed
		catch( excNotLoadable )
		{
			xmlHttp = false;
		}
		return xmlHttp ;
	}
	
	
	/**
	 * sends a http request to server
	 *
	 * @param strSource, String, datasource on server, e.g. data.php
	 *
	 * @param strData, String, data to send to server, optionally
	 *
	 * @param intType, Integer,request type, possible values: REQUEST_GET, REQUEST_POST, REQUEST_XML, REQUEST_HEAD default REQUEST_GET
	 *
	 * @param strData, Integer, ID of this request, will be given to registered event handler onreadystatechange', optionally
	 *
	 * @return String, request data or data source
	 */
	function sendRequest( strSource, strData, intType, intID )
	{
		
		if( !strData )
			strData = '';
	
		// default type (0 = GET, 1 = xml, 2 = POST )
		if( isNaN( intType ) )
			intType = 0; // GET
	
		// previous request not finished yet, abort it before sending a new request
		if( xmlHttp && xmlHttp.readyState )
		{
			xmlHttp.abort( );
			xmlHttp = false;
		}
		
		// create a new instance of xmlhttprequest object
		// if it fails, return
		if( !xmlHttp )
		{
			xmlHttp = getXMLRequester( );
			if( !xmlHttp )
				return;
		}
		
		// parse query string
		if( intType != 1 && ( strData && strData.substr( 0, 1 ) == '&' || strData.substr( 0, 1 ) == '?' ) )
			strData = strData.substring( 1, strData.length );

		// data to send using POST
		var dataReturn = strData ? strData : strSource;
		
		switch( intType )
		{
			case 1:	// xml
				strData = "xml=" + strData;
			case 2: // POST
				// open the connection 
				xmlHttp.open( "POST", strSource, true );
				xmlHttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
				xmlHttp.setRequestHeader( 'Content-length', strData.length );
				break;
			case 3: // HEAD
				// open the connection 
				xmlHttp.open( "HEAD", strSource, true );
				strData = null;
				break;
			default: // GET
				// open the connection 
				var strDataFile = strSource + (strData ? '?' + strData : '' );
				xmlHttp.open( "GET", strDataFile, true );
				strData = null;
		}
		
		// set onload data event-handler
		xmlHttp.onreadystatechange = new Function( "", "processResponse(" + intID + ")" ); ;

		// send request to server
		xmlHttp.send( strData );	// param = POST data
		
		return dataReturn;
	}
		
	
	/**
	 * process the response data from server
	 *
	 * @param intID, Integer, ID of this response
	 */
	function processResponse( intID )
	{
		// status 0 UNINITIALIZED open() has not been called yet.
		// status 1 LOADING send() has not been called yet.
		// status 2 LOADED send() has been called, headers and status are available.
		// status 3 INTERACTIVE Downloading, responseText holds the partial data.
		// status 4 COMPLETED Finished with all operations.
		switch( xmlHttp.readyState )
		{
			// uninitialized
			case 0:
			// loading
			case 1:
			// loaded
			case 2:
			// interactive
			case 3:
				break;
			// complete
			case 4:	
				// check http status
				if( xmlHttp.status == 200 )	// success
				{
					processData( xmlHttp, intID );
				}
				// loading not successfull, e.g. page not available
				else
				{
					if( window.handleAJAXError )
						handleAJAXError( xmlHttp, intID );
					else
						alert( "ERROR\n HTTP status = " + xmlHttp.status + "\n" + xmlHttp.statusText ) ;
				}
		}
	}
	
	/** End AJAX functions **/
	
	
	
	/** real application functions **/
	
	// process data from server
	function processData( xmlHttp, intID )
	{
		if(action == "search") {
			// alert("Suche!");
			// hide image that indicates search processing
			hideElement( "searchanim" );		
			// show link to see server output
			showElement( "showxml" );
			// process xml data
			createArrayFromXML( xmlHttp.responseXML );
		}
		if(action == "manufacturer") {
			// alert("Hersteller!");
			// show link to see server output
			showElement( "showxml" );
			// process xml data
			createDropdownFromXML( xmlHttp.responseXML );
		}
	}
	
	
	// handle response errors
	function handleAJAXError( xmlHttp, intID )
	{
		// hide image that indicates search processing
		hideElement( "searchanim" );
		// alert( "Leider ist ein Fehler bei der Datenbeschaffung aufgetreten." ) ;
	}
	
	
	function doManufacturer() {
		action = "manufacturer";
		intManufacturer = document.getElementById( "manufacturer" ).value;
		var strRequest = '?action=manufacturer&manufacturer=' + intManufacturer + '&lang=' + lang;
		strRequestParam = sendRequest( DATA_SOURCE, strRequest );
	}
	
	// execute the article search
	// set timer after every keystroke to wait for end of input
	// then execute the search by invoking 'sendRequest'
	function doSearch( objEvent, blnUpdate )
	{
		if( !blnUpdate )
		{
			// monitor key strokes 
			if( timerRessource )
				window.clearTimeout( timerRessource );
			timerRessource = window.setTimeout( "doSearch( null, true )", WAIT_TIME );
		}
		// input has finished, send request
		else
		{
			// check, if Articleid has changed
			var strArticleid = document.getElementById( "articleid" ).value;
			var intManufacturer = document.getElementById( "manufacturer" ).value;
			var intGroup = document.getElementById( "application" ).value;
			if( strArticleid == strRecentSearch )
				return;
			
			strRecentSearch = strArticleid;
			showElement( "searchanim" );
			action = "search";
			var strRequest = '?action=article&articlestring=' + strArticleid + '&manufacturer=' + intManufacturer + '&productgroup=' + intGroup + '&lang=' + lang;
			strRecentSearch = strArticleid;
			strRequestParam = sendRequest( DATA_SOURCE, strRequest );
		} // end else
		
	} // end function
	
	
	// creates array with articleid's
	function createArrayFromXML( xmlDocument )
	{
		var arrArticles = new Array();
		var arrArticlesTitle = new Array();
		intResultLen = getValues( xmlDocument, "TotalResults" );
		
		for( var i = 0; i < intResultLen; i++ )
		{
			arrArticles[i] = new Object();
			arrArticlesTitle[i] = new Object();
			
			var strTempArticleName = getValues( xmlDocument, "articleid" + i );
			var strTempArticleTitle = getValues( xmlDocument, "nameid" + i );
			
			arrArticles[i]["ArticleName"] = strTempArticleName;
			arrArticlesTitle[i]["ArticleTitle"] = strTempArticleTitle;
		}
		updateResult(arrArticles, arrArticlesTitle);
	}
	
	// recursive function deletes all options
	function deleteAllDropOptions(appDropdown) {
		
		var intCurrentOptionCount = document.quicksearch.application.length;
		
		// remove Old options
		for(i = 0; i < intCurrentOptionCount; i++)
		{
			appDropdown.options[ i ] = null;
		}
		
		if(document.quicksearch.application.length > 0) {
			deleteAllDropOptions(appDropdown);
		}
		
	} // end function
	
	// recursive function deletes all optgroups
	function deleteAllDropOptgroups(appDropdown) {
	
		appDropdown.removeChild(appDropdown.getElementsByTagName("optgroup")[0]);
		
		var intCountOptgroups = appDropdown.getElementsByTagName("optgroup").length;
		
		if(intCountOptgroups != 0) {
			deleteAllDropOptgroups(appDropdown);
		}
				
	} // end function
	
	
	 function replaceIt(string,suchen,ersetzen) {
	 
		ausgabe = "" + string;
		
		while (ausgabe.indexOf(suchen)>-1) {
		
			pos= ausgabe.indexOf(suchen);
			ausgabe = "" + (ausgabe.substring(0, pos) + ersetzen +
			ausgabe.substring((pos + suchen.length), ausgabe.length));
			
		}
		
		return ausgabe;
		
	} // end function
	
	
	// creates string with dropdown
	function createDropdownFromXML( xmlDocument )
	{
		// set var with drop direction
		var appDropdown = document.quicksearch.application;
				
		// start delete-functions & cleanup drop
		if(appDropdown.getElementsByTagName("option").length > 0) { deleteAllDropOptions(appDropdown); }
		if(appDropdown.getElementsByTagName("optgroup").length > 0) { deleteAllDropOptgroups(appDropdown); }
		
		// replace space entities with ordinary spache chars
		var content = xmlDocument.getElementsByTagName("option")[0].firstChild.nodeValue;		
		// creates new option element
		newOptionElement = new Option(content, 999, false, true);		
		// add the new option element
  		document.quicksearch.application.options[document.quicksearch.application.length] = newOptionElement;
		
		// count option length
		var intCountOptions = xmlDocument.getElementsByTagName("option").length;
		// count optgroups length
		var intCountOptgroups = xmlDocument.getElementsByTagName("optgroup").length;
		
		var intCountOptgroupFor = 0;
		
		for(i = 0; intCountOptgroupFor < intCountOptgroups; i++) {
		
			// get current optgroup
			var strOptgroup	    	= xmlDocument.getElementsByTagName("optgroup")[ intCountOptgroupFor ];
			var strOptgroupLabel	= strOptgroup.getAttribute("label")
			
			var newOptgroup = document.createElement('optgroup');
				newOptgroup.label = strOptgroupLabel;
			
			appDropdown.appendChild(newOptgroup);
			
			// get suboptions count
			var intCountOptions = strOptgroup.childNodes.length;
			
			// insert options
			for(i = 0; i < intCountOptions; i++)
			{
				var strTempOptionTitle = strOptgroup.childNodes[ i ].firstChild.nodeValue;
				var strTempOptionValue = strOptgroup.childNodes[ i ].getAttribute("value")
				
				// replace space entities with ordinary spache chars
				strTempOptionTitle = replaceIt(strTempOptionTitle, '#', ' ');
								
				// creates new option element
				newOptionElement = new Option(strTempOptionTitle, strTempOptionValue, false, false);
				
				// add the new option element
  				document.quicksearch.application.options[document.quicksearch.application.length] = newOptionElement;

			} // end option for
			
			intCountOptgroupFor = intCountOptgroupFor + 1;
			
		} // end optgroup for
		
	} // end createDropdownFromXML
	
	
	// add data table to document or update data
	function updateResult( arr, arrArticlesTitle )
	{
		if( !intResultLen )
		{
			// no articles found
			return;
		}
		
		
		if (document.getElementById( "articleresult" )) {
			
			var eLength = document.getElementById( "articleresult" ).getElementsByTagName( "p" ).length;
		
			for (i = 0; i < eLength; i++) {
				// alert ( i + "\n" + eLength + "\n" + document.getElementById( "articleresult" ).getElementsByTagName( "p" ).length );
				document.getElementById( "articleresult" ).removeChild(document.getElementById( "articleresult" ).getElementsByTagName( "p" )[0]);
			}

			var eObj = document.getElementById( "articleresult" ).parentNode;
			eObj.removeChild ( document.getElementById( "articleresult" ) ); 
			
		}
		
   	    
		// add data table using dom methods
		if( !document.getElementById( "articleresult" ) && arr.length > 0 )
		{
			var myArticleResult = document.createElement("div");			
			var myArticleResultId = document.createAttribute("id");
				myArticleResultId.nodeValue = "articleresult";

			myArticleResult.setAttributeNode(myArticleResultId);
			
			// show the first 10 entrys of the result
			
			var count = arr.length;
			if ( count > 10 ) {
				count = 10;
			}
			
			for( i = 0; i < count; i++ )
			{
			
				// Article ID
				var myArticlePtag = document.createElement("p");				
				var myArticleLink = document.createElement("a");
				var myArticleLinkUrl = document.createAttribute("href");
					myArticleLinkUrl.nodeValue = "javascript:setArticleFieldContent('" + arr[i]["ArticleName"] + "')";
				
				myArticleLink.setAttributeNode(myArticleLinkUrl); // ready a tag
				
				// Article Title
				var myArticleTitle = document.createElement("span");
				var myArticleTitleId = document.createAttribute("id");
					myArticleTitleId.nodeValue = "title";
				
				myArticleTitle.setAttributeNode(myArticleTitleId); // ready p tag
				
				
				var myArticleContent = document.createTextNode(arr[i]["ArticleName"]);
				var myArticleContentTitle = document.createTextNode(arrArticlesTitle[i]["ArticleTitle"]);
				
				myArticleTitle.appendChild(myArticleContentTitle);
				
				
				myArticleLink.appendChild(myArticleContent);
				myArticlePtag.appendChild(myArticleLink);
				myArticlePtag.appendChild(myArticleTitle);
				myArticleResult.appendChild(myArticlePtag);
			}
			var myOutput = document.getElementById("rightcontent");
			myOutput.appendChild(myArticleResult);
		
		
		}		
	}	
	/** end real application functions **/	
	
	/* some common helper functions */
	function setArticleFieldContent(ArticleName) {
		document.quicksearch.articleid.value = ArticleName;
		var RightcontentDIV = document.getElementById("rightcontent");
		var ArticleResultDIV = document.getElementById("articleresult");
		RightcontentDIV.removeChild(ArticleResultDIV);
		var quicksearchForm = document.getElementById("quicksearch");
		document.getElementById('quicksearch').submit();
	}
	
	// retrieve data from dom tree
	function getValues( xmlDocument, strTagName )
	{
		var xmlTags;
		if( strTagName )
			xmlTags =  xmlDocument.getElementsByTagName( strTagName );
		else
			xmlTags =  xmlDocument.childNodes;
			
		var intLen = xmlTags.length;
		if( !intLen )
			return null;
		else if( intLen == 1 )
		{
			return xmlTags[ 0 ].firstChild.nodeValue;
		}
		else
		{
			var arrValues = new Array( );
			for( var i = 0; i < intLen; i++ )
			{
				arrValues[ i ] = xmlTags[ i ].firstChild.nodeValue;
			}			
			return arrValues;
		}
	}	
	
	// retrieve data from dom tree
	function getAttributes( xmlDocument, strTagName, Attribute )
	{
		var xmlTags;
		if( strTagName )
			xmlTags =  xmlDocument.getElementsByTagName( strTagName );
		else
			xmlTags =  xmlDocument.childNodes;
			
		var intLen = xmlTags.length;
		if( !intLen )
			return null;
		else if( intLen == 1 )
		{
			return xmlTags[ 0 ].firstChild.nodeValue;
		}
		else
		{
			var arrValues = new Array( );

			for( var i = 0; i < intLen; i++ )
			{
				// arrValues[ i ] = xmlDocument.childNodes[i].getAttributeNode( "value" );
				arrValues[ i ] = xmlDocument.getElementsByTagName(strTagName)[ i ].getAttributeNode('value');
			}			
			return arrValues;
		}
	}
	
	// register an event handler to an element
	function setEvent( xmlNode, strName, strFunction )
	{
		strName = strName.substr( 0, 2 ) == "on" ? strName.substr( 2, strName.length ) : strName;

		// w3c compatible style, not supported by internet explorer yet
		if( document.addEventListener )
			xmlNode.addEventListener( strName, new Function( "event", "event.preventDefault( ); " + strFunction ), true );
		// Internet Explorer
		else if( document.attachEvent )
			xmlNode.attachEvent( "on" + strName, new Function( "event", strFunction ) );
		// old style (tag.onclick)
		else
			xmlNode[ "on" + strName ] = new Function( "event", strFunction );
	}
	
	
	// hide an element
	function hideElement( strID, blnUseDisplay )
	{
		var xmlNode = document.getElementById( strID );
		if( xmlNode )
			blnUseDisplay ? xmlNode.style.display = "none" : xmlNode.style.visibility = "hidden"; 
	}
	
	// makes an element visible
	function showElement( strID, blnUseDisplay )
	{
		var xmlNode = document.getElementById( strID );
		if( xmlNode )
			blnUseDisplay ? xmlNode.style.display = "block" : xmlNode.style.visibility = "visible"; 
	}