// get site root path without trailing slash
var ROOT_PATH = GetMetaVar("ROOT_PATH");
var place_search_history = new Array();

if(ROOT_PATH.match(/^(.*)\/$/))
{
    ROOT_PATH = RegExp.$1;
}

function GetMetaVar(name)
{
    var meta_list = document.getElementsByTagName("meta");
    for(var i = 0; i < meta_list.length; i++)
    {
        if(meta_list[i].name.match(new RegExp("^"+name+"$")))
        {
            return meta_list[i].content;
        }
    }
    return null;
}


/**
* @brief menu controller object
*/
var Menu = new function()
{
    /**
    * @brief holds the current open menu node
    */
    var current_menu = null;
    var current_timeout = null;
    var was_inside;


    /**
    * @brief open menu or sub-menu and close last menu, if it is not a parent menu
    */
    this.open = function(node)
    {
        // if invalid type, just return
        if(!node || typeof node != "object" || !node.className || !node.className.match(/\bmenu\b/))
        {
            return;
        }

        // make sure to clear timeout on any valid open
        if(current_timeout)
        {
            window.clearTimeout(current_timeout);
            current_timeout = null;
        }

        // check if element is what we want
        if(current_menu)
        {
            current_menu.style.display = "none";
            current_menu = null;
        }
        node.style.display = "block";
        current_menu = node;
        was_inside = false;

        // install event listeners
        document.addEventListener("mousedown", this.mouse_click, false);
        document.addEventListener("mousemove", this.mouse_move, false);
    }  // method open()


    /**
    * @brief close the current menu, including its sub-menus
    */
    this.close = function()
    {
        if(current_menu && current_timeout)
        {
            // remove menu and remove event listeners
            current_menu.style.display = "none";
            current_menu = null;
            document.removeEventListener("mousedown", this.mouse_click, false);
            document.removeEventListener("mousemove", this.mouse_move, false);
        }
    }  // method close()


    /*
    * @brief process a click event, check where it happened and close menu if needed
    */
    this.mouse_click = function(event)
    {
        // cancel if no menu open
        if(current_menu == null)
        {
            return;
        }

        // ie compatibility
        if(event == null)
        {
            event = window.event;
        }
        var target = event.target != null ? event.target : event.srcElement;

        // if triggered by event, check if the click was inside the menu
        if(target != null)
        {
            while(target.parentNode)
            {
                if(target == current_menu)
                {
                    return;
                }
                target = target.parentNode;
            }
        }

        // remove menu and remove event listeners
        current_menu.style.display = "none";
        current_menu = null;
        document.removeEventListener("mousedown", this.mouse_click, false);
        document.removeEventListener("mousemove", this.mouse_move, false);
    }  // method mouse_click()


    /**
    * @brief process a mouse move, check where it happened and close menu if needed
    */
    this.mouse_move = function(event)
    {
        // cancel if no menu open
        if(current_menu == null)
        {
            return;
        }

        // ie compatibility
        if(event == null)
        {
            event = window.event;
        }
        var target = event.target != null ? event.target : event.srcElement;

        // check if the mouse is above the menu
        while(target.parentNode)
        {
            // mouse is above the menu
            if(target == current_menu)
            {
                if(current_timeout)
                {
                    window.clearTimeout(current_timeout);
                    current_timeout = null;
                }
                if(was_inside == false)
                {
                    was_inside = true;
                }
                return;
            }
            target = target.parentNode;
        }

        // mouse is outside the menu
        if(was_inside == true)
        {
            current_timeout = window.setTimeout("Menu.close();", 400);
        }
    }  // method mouse_move()

}  // object Menu


/**
* @brief popup controller object
*/
var Popup = new function()
{
    var current_id = null;

    this.show = function(id)
    {
        // hide already open popup
        this.hide();

        // return if popup doesn't exist
        if(!document.getElementById("popup_"+id))
        {
            return;
        }

        // display new popup
        document.getElementById("popup_"+id).style.display = "block";
        current_id = id;

        // install event listeners
        document.addEventListener("mousedown", this.check_inside, false);
    }

    this.hide = function()
    {
        // cancel if no popup open
        if(!current_id)
        {
            return;
        }

        // close popup and remove event listener
        document.getElementById("popup_"+current_id).style.display = "none";
        current_id = null;
        document.removeEventListener("mousedown", this.check_inside, false);
    }

    this.check_inside = function(event)
    {
        // cancel if no popup open
        if(!current_id)
        {
            return;
        }

        // ie compatibility
        if(event == null)
        {
            if(window.event)
            {
                event = window.event;
            }
        }
        if(event)
        {
            var target = event.target != null ? event.target : event.srcElement;
        }

        // if triggered by event, check if the click was inside the popup
        while(target.parentNode)
        {
            if(target == document.getElementById("popup_"+current_id))
            {
                return;
            }
            target = target.parentNode;
        }

        // close popup and remove event listener
        document.getElementById("popup_"+current_id).style.display = "none";
        current_id = null;
        document.removeEventListener("mousedown", this.check_inside, false);
    }
}  // object Popup()


/**
* @brief set the sub title of the current document
*/
function SetSubTitle(title)
{
    if(document.title.match(/\|/))  // already has sub title
    {
        if(!title)
        {
            document.title.replace(/\.+$/, "");
        }
        else
        {
            document.title.replace(/\|.+$/, "| "+title);
        }
    }
    else  // no sub title
    {
        if(title)
        {
            document.title += " | "+title;
        }
    }
}  // function SetSubTitle()


function ScrollMarquee()
{
    var node_list = document.getElementsByClassName("extra_bottom_ticker_marquee");
    for(var i = 0; i < node_list.length; i++)
    {
       while(node_list[i].firstChild.data.length < 64)  // should be high enough
        {
            node_list[i].firstChild.data += node_list[i].firstChild.data;
        }
        if(node_list[i].firstChild.data.match(/^(.)(.+)$/))
        {
            node_list[i].firstChild.data = RegExp.$2 + RegExp.$1;
        }
    }
}  // function ScrollMarquee()
function SetupMarquee()
{
    setInterval("ScrollMarquee();", 250);
}  // function SetupMarquee()
document.addEventListener("DOMContentLoaded", SetupMarquee, false);


function ExpandList(list)
{
    for(var i = 0; i < list.childNodes.length; i++)
    {
        if(list.childNodes[i].nodeType == 1)
        {
            list.childNodes[i].style.display = "list-item";
        }
    }
}  // function ExpandList()


function CollapseList(list)
{
    for(var i = 0; i < list.childNodes.length; i++)
    {
        if((list.childNodes[i].nodeType == 1) && !list.childNodes[i].className.match(/\bselected\b/))
        {
            list.childNodes[i].style.display = "none";
        }
    }
}  // function CollapseList()


/**
* @brief save my preferences for the main module in a cookie
* @param key - string - the type of preference to set
* @param value - string - the new value for the preference
*/
function SaveModule(type, name)
{
    alert(type+" SET TO "+name);
    return true;
}  // function SaveModule()


/**
* @brief remove the given module and save this in my cookie preferences
*/
function RemoveModule(type, module_name)
{
    alert(type+" REMOVED: "+module_name);
    return true;
}  // function RemoveModule()


/**
* @brief remove the given module and save this in my cookie preferences
*/
function ChangeFavorite(type, name)
{
    alert("changing favorite module "+name+" ...");
    return true;
}  // function EditModule()


/*
* @brief opens popup menu specified by an event handler
*/
function OpenMainMenu(event)
{
    // ie compatibility
    if(event == null)
    {
        event = window.event;
    }
    var node = event.target != null ? event.target : event.srcElement;

    // check if we have the node we want
    if(node.nodeName.match(/^a$/i) && node.parentNode.nodeName.match(/^li$/i))
    {
        for(var i = 0; i < node.parentNode.childNodes.length; i++)
        {
            var elem = node.parentNode.childNodes[i];
            if(elem.nodeName.match(/^ul$/i) && elem.className.match(/\bmenu\b/))
            {
                Menu.open(elem);
                return;
            }
        }
    }
}  // function OpenMainMenu()
document.addEventListener("mouseover", OpenMainMenu, false);


/**
* @brief check whether all form elements that have the required attribute set are filled
*/
function CheckRequired(form_elem)
{
    for(var i = 0; i < form_elem.elements.length; i++)
    {
        if(
        form_elem.elements[i].getAttribute("required")
        &&
        form_elem.elements[i].getAttribute("required").match(/\brequired\b/)
        &&
        (!form_elem.elements[i].value || form_elem.elements[i].value.match(/^\s*$/))
        )
        {
            form_elem.elements[i].focus();
            showMsgBox("msg_box_required_fail");
            return false;
        }
    }
    return true;
}  // function CheckRequired()


/**
* @brief shows an ancestor element of the given class and hides all siblings with the same class
* @param className - string - a class name
* @param elem - node - the element node to start looking upward from
*/
function ShowFromSiblings(element_id,type)
{
	var data_elements = document.getElementsByClassName(element_id+"_data");
	for(var i = 0; i < data_elements.length; i++)
	{
		data_elements[i].className = remove_class_name(data_elements[i].className,"selected");
	}
	
	var h5_elements = document.getElementsByClassName(element_id+"_h5");
	for(var i = 0; i < h5_elements.length; i++)
	{
		h5_elements[i].className = remove_class_name(h5_elements[i].className,"selected");
	}
	
	var data_element = document.getElementById(element_id+"_data_"+type);
	var h5_element = document.getElementById(element_id+"_h5_"+type);
	h5_element.className = add_class_name(h5_element.className,"selected");
    data_element.className = add_class_name(data_element.className,"selected");
    return;
}


/**
* @brief check whether a username already exists in the database
*/
function CheckUsername(username)
{
    if(!username.match(/^\s*$/))
    {
        // prepare xhr object
        var xhr = new XMLHttpRequest;
        xhr.open("GET", ROOT_PATH+"/get/check_username.php?username="+encodeURIComponent(username), true);
        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");  // for identifying ajax call

        // define the function that is called when readystate changes
        xhr.onreadystatechange = function()
        {
            if(xhr.readyState == 4)  // if request was completed
            {
                if((xhr.status >= 200) && (xhr.status <= 299) && (xhr.getResponseHeader("Content-Type") == "application/json") && xhr.responseText)  // ok
                {
                    var json = JSON.parse(xhr.responseText);  // parse response text as json, use json2.js
                    if(json && json.is_valid && json.is_valid == true)
                    {
                        return true;
                    }
                    else
                    {
                        showMsgBox("msg_box_username_double");
                        return false;
                    }
                }
                else if(xhr.status == 404)
                {
                    showMsgBox("msg_box_ajax_error_404");
                    return false;
                }
                else if(xhr.status == 400)
                {
                    showMsgBox("msg_box_ajax_error_400");
                    return false;
                }
            }
        };

        // finally send http request
        xhr.send(null);
        return true;
    }
    return false;
}


function CheckRetype(password1, password2)
{
    if(password1.value != password2.value)
    {
        password1.focus();
        showMsgBox("msg_box_password_fail");
        return false;
    }
    return true;
}


/*
* @brief opens popup menu specified by an event handler
*/
function OpenMenu(event)
{
    // ie compatibility
    if(event == null)
    {
        event = window.event;
    }
    var node = event.target != null ? event.target : event.srcElement;

    // check if we have the node we want
    if(node.nodeName.match(/^a$/i) && node.parentNode.nodeName.match(/^li$/i))
    {
        for(var i = 0; i < node.parentNode.childNodes.length; i++)
        {
            var elem = node.parentNode.childNodes[i];
            if(elem.nodeName.match(/^ul$/i) && elem.className.match(/\bmenu\b/))
            {
                Menu.open(elem);
                return;
            }
        }
    }
}  // function OpenMenu()
document.addEventListener("mouseover", OpenMenu, false);


/**
* @brief change the selected param to the given param; makes use of ".param_selector" and ".param_data" classes
* @param type - string - the requested data type to show
*/
function SelectParam(type, module)
{
    // get list of selectable parameters (selector: ".param_selector > ul > li") in param_list
    var param_selector = document.getElementById("nav_param_selector_tr").childNodes;
    var param_list = [];
    for(var i = 0; i < param_selector.length; i++)
    {
        if(param_selector[i].nodeType == 1 && param_selector[i].nodeName.match(/^td$/i))
        {
            for(j = 0; j < param_selector[i].childNodes.length; j++)
            {
                if(param_selector[i].childNodes[j].nodeType == 1 && param_selector[i].childNodes[j].nodeName.match(/^a$/i))
                {
                    param_list.push(param_selector[i].childNodes[j]);
                }
            }
        }
    }

    // now remove selection for all but the selected param
    for(var i = 0; i < param_list.length; i++)
    {
    	param_list[i].className = remove_class_name(param_list[i].className,"selected");
        if(param_list[i].id.match(type))
        {
        	param_list[i].className = add_class_name(param_list[i].className,"selected");
        }
    }

    // iterate over every ".param_data" add ".selected" class if it should be selected
    var param_data = document.getElementsByClassName("main_"+module+"_param_data");
    for(var i = 0; i < param_data.length; i++)
    {
    	param_data[i].className = remove_class_name(param_data[i].className,"selected");
        if(param_data[i].id.match(type))
        {
        	param_data[i].className = add_class_name(param_data[i].className,"selected");
        }
    }
    
    var param_data = document.getElementsByClassName("main_"+module+"_param_data_leg_desc");
    for(var i = 0; i < param_data.length; i++)
    {
    	param_data[i].className = remove_class_name(param_data[i].className,"selected");
        if(param_data[i].id.match(type))
        {
        	param_data[i].className = add_class_name(param_data[i].className,"selected");
        }
    }

    // change all the hyperlinks of ".time_selector"
    var ts = document.getElementsByClassName("time_selector");
    for(var i = 0; i < ts.length; i++)
    {
        var anchors = ts[i].getElementsByTagName("a");
        for(var j = 0; j < anchors.length; j++)
        {
            anchors[j].href = anchors[j].href.replace(/#.*$/, "") + "#" + type;
//             anchors[j].href += ;
        }
    }
}  // function SelectParam()


function SetupParam()
{
    // if there is an url hash, select this param
    if(location.hash.match(/^#(\w+)$/))
    {
// alert("test");
        var param = RegExp.$1;
        SelectParam(param, "map");  // quick hack
        SelectParam(param, "hitlists");  // quick hack
    }
}  // function SetupParam()
document.addEventListener("DOMContentLoaded", SetupParam, false);


function remove_class_name(string,string_to_remove)
{
	old_array = string.split(" ");
	new_string = '';
	for(var i=0;i<old_array.length;i++)
	{
		if(string_to_remove!=old_array[i])
		{
			new_string = new_string + " " + old_array[i];
		}
	}
	return new_string;
}

function check_class_name(string,string_to_check)
{
	if(!string || string.length==0)
	{
		return false;
	}
	array = string.split(" ");
	for(var i=0;i<array.length;i++)
	{
		if(string_to_check==array[i])
		{
			return true;
		}
	}
	return false;
}

function add_class_name(string,string_to_add)
{
	
	return string + " " + string_to_add;
}


/**
* @brief searches for a place, using a name string or the zip code
* @param form - node - the form node object
* @return true .. ok; false .. error
*/
/*
function PlaceSearch(form,action,place,lang,profile,pref,profile)
{	
	showMsgBoxes = true;
	
	if(action==1)
	{
		showMsgBoxes = false;
	}
	if(form)
	{
	    if(form.elements["PLACE"].value.match(/^\s*$/))
	    {
	        form.elements["PLACE"].value = "";
	        form.elements["PLACE"].focus();
	        if(showMsgBoxes)
	        {
	        	showMsgBox("msg_box_search_no_term");
	        }
	        return false;
	    }
	    
	    var search_term = form.elements["PLACE"].value;
	    var language = form.elements["LANG"].value;
	    var prefix = form.elements["prefix"].value;
	    
	    if(form.elements["PROFILE"])
	    {
	        var type = form.elements["PROFILE"].value;
	    }
	}
	else
	{
	    if(place.match(/^\s*$/))
	    {
	    	if(showMsgBoxes)
	    	{
	    		showMsgBox("msg_box_search_no_term");
	    	}
		    return false;
	    }
	    
	    var search_term = place;
	    var language = lang;
	    var prefix = pref;
	    
	    if(profile)
	    {
	        var type = profile;
	    }
	}
	
    var url = ROOT_PATH+"/get/place_search.php?PLACE="+encodeURIComponent(search_term)+"&LANG="+encodeURIComponent(language);
    
    if(type)
    {
        url += "&PROFILE="+encodeURIComponent(type);
    }
    var xhr = new XMLHttpRequest;
    xhr.open("GET", url, true);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");  // for identifying ajax call

    var result_list=new Array();
    
    // define the function that is called when readystate changes
    xhr.onreadystatechange = function()
    {
        if(xhr.readyState == 4)  // if request was completed
        {
            if((xhr.status >= 200) && (xhr.status <= 299) && (xhr.getResponseHeader("Content-Type") == "application/json") && xhr.responseText)  // ok
            {
                result_list = JSON.parse(xhr.responseText);  // parse response text as json, use json2.js
                if(result_list.length == 1)
                {
            		location.href = prefix+"/"+result_list[0].link_name;  // if single result, jump to this
                }
                else if(result_list.length == 0)
                {
        	    	if(showMsgBoxes)
        	    	{
        	    		showMsgBox("msg_box_search_no_results");  // if no result, report to user
        	    	}
                }
                else
                {
        	    	if(showMsgBoxes)
        	    	{
        	    		DisplayResults(result_list, prefix);  // if 2 or more results, show result box
        	    	}
                }
        		form.submit();
            }
            else if(xhr.status == 404)
            {
    	    	if(showMsgBoxes)
    	    	{
	    			showMsgBox("msg_box_ajax_error_404");
    	    	}
                return false;
            }
            else if(xhr.status == 400)
            {
    	    	if(showMsgBoxes)
    	    	{
    	    		showMsgBox("msg_box_ajax_error_400");
    	    	}
                return false;
            }
            else
            {
    	    	if(showMsgBoxes)
    	    	{
    	    		showMsgBox("msg_box_ajax_error_json");
    	    	}
                return false;
            }
        }
    };

    
    // finally send http request
    xhr.send(null);
    
}  // function PlaceSearch()*/


/**
* @brief searches for a place, using a name string or the zip code
* @param form - node - the form node object
* @return true .. ok; false .. error
*/
function PlaceSearch(form,action,place,lang,profile,pref,profile)
{
	showMsgBoxes = true;
	makeRedirect = true;
	if(action==1)
	{
		showMsgBoxes = false;
		makeRedirect = false;
	}
	if(action==2)
	{
		showMsgBoxes = false;
		makeRedirect = true;
	}
	if(form)
	{
	    if(form.elements["PLACE"].value.match(/^\s*$/))
	    {
	        form.elements["PLACE"].value = "";
	        form.elements["PLACE"].focus();
	        if(showMsgBoxes)
	        {
	        	showMsgBox("msg_box_search_no_term");
	        }
	        return false;
	    }
	    
	    var search_term = form.elements["PLACE"].value;
	    var language = form.elements["LANG"].value;
	    var prefix = form.elements["prefix"].value;
	    
	    if(form.elements["PROFILE"])
	    {
	        var type = form.elements["PROFILE"].value;
	    }
	}
	else
	{
	    if(place.match(/^\s*$/))
	    {
	    	if(showMsgBoxes)
	    	{
	    		showMsgBox("msg_box_search_no_term");
	    	}
		    return false;
	    }
	    
	    var search_term = place;
	    var language = lang;
	    var prefix = pref;
	    
	    if(profile)
	    {
	        var type = profile;
	    }
	}
	if(place_search_history[encodeURIComponent(search_term)+encodeURIComponent(language)])
	{
		displaySearchResults(place_search_history[encodeURIComponent(search_term)+encodeURIComponent(language)]);
	}
	else
	{
	    var url = ROOT_PATH+"/get/place_search.php?PLACE="+encodeURIComponent(search_term)+"&LANG="+encodeURIComponent(language);
	    if(type)
	    {
	        url += "&PROFILE="+encodeURIComponent(type);
	    }
	    var xhr = new XMLHttpRequest;
	    xhr.open("GET", url, true);
	    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");  // for identifying ajax call
	
	    // define the function that is called when readystate changes
	    xhr.onreadystatechange = function()
	    {
	        if(xhr.readyState == 4)  // if request was completed
	        {
	            if((xhr.status >= 200) && (xhr.status <= 299) && (xhr.getResponseHeader("Content-Type") == "application/json") && xhr.responseText)  // ok
	            {
	                var result_list = JSON.parse(xhr.responseText);  // parse response text as json, use json2.js
	            	if(result_list.length == 1)
	                {
	                	if(makeRedirect)
	                	{
	                		location.href = prefix+"/"+result_list[0].link_name;  // if single result, jump to this
	                
	                	}
	                }
	            	else
	            	{
	            		displaySearchResults(result_list,prefix);
	            	}
	                place_search_history[encodeURIComponent(search_term)+encodeURIComponent(language)] = result_list;
	            }
	            else if(xhr.status == 404)
	            {
	            	if(showMsgBoxes)
	    	    	{
	            		showMsgBox("msg_box_ajax_error_404");
	    	    	}
	                return false;
	            }
	            else if(xhr.status == 400)
	            {
	            	if(showMsgBoxes)
	    	    	{
	            		showMsgBox("msg_box_ajax_error_400");
	    	    	}
	                return false;
	            }
	            else
	            {
	            	if(showMsgBoxes)
	    	    	{
	            		showMsgBox("msg_box_ajax_error_json");
	    	    	}
	                return false;
	            }
	        }
	    };
	    // finally send http request
	    xhr.send(null);
    }

}  // function PlaceSearch()


function displaySearchResults(result_list,prefix)
{
    if(result_list.length == 0)
    {
    	if(showMsgBoxes)
    	{
    		showMsgBox("msg_box_search_no_results");  // if no result, report to user
    	}
    }
    else
    {
    	if(showMsgBoxes)
    	{
    		DisplayResults(result_list, prefix);  // if 2 or more results, show result box
    	}
    }
}


/**
* @brief searches for a place, using a name string or the zip code
* @param form - node - the form node object
* @return true .. ok; false .. error
*/
function PlaceSuggest(form)
{
    var search_term = form.elements["PLACE"].value.trim();
    if(search_term.length < 3)
    {
        document.getElementById("suggestion_box").style.display = "none";
        return false;
    }
    var language = form.elements[1].value;
    var prefix = form.elements[2].value;
    if(form.elements[3])
    {
        var type = form.elements[3].value;
    }

    var url = ROOT_PATH+"/get/place_search.php?PLACE="+encodeURIComponent(search_term)+"&LANG="+encodeURIComponent(language);
    if(type)
    {
        url += "&PROFILE="+encodeURIComponent(type);
    }

    var xhr = new XMLHttpRequest;
    xhr.open("GET", url, true);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");  // for identifying ajax call

    // define the function that is called when readystate changes
    xhr.onreadystatechange = function()
    {
        if(xhr.readyState == 4)  // if request was completed
        {
            if((xhr.status >= 200) && (xhr.status <= 299) && (xhr.getResponseHeader("Content-Type") == "application/json") && xhr.responseText)  // ok
            {
                var result_list = JSON.parse(xhr.responseText);  // parse response text as json, use json2.js
                if(result_list.length == 0)
                {
                    document.getElementById("suggestion_box").style.display = "none";
                    return false;
                }
                else
                {
                    document.getElementById("suggestion_box").style.display = "block";
                    while(document.getElementById("suggestion_box").hasChildNodes())
                    {
                        document.getElementById("suggestion_box").removeChild(document.getElementById("suggestion_box").lastChild);
                    }

                    // create list with links and append to div
                    var ul = document.createElement("ul");
                    for(var i = 0; i < result_list.length; i++)
                    {
                        var li = document.createElement("li");
                        var a = document.createElement("a");
                        a.href = prefix+"/"+result_list[i].link_name;

                        if(result_list[i].name.match(new RegExp("(.*)("+search_term+")(.*)", "i")))
                        {
                            var head = document.createTextNode(RegExp.$1);
                            var tail = document.createTextNode(RegExp.$3);
                            var found = document.createElement("strong");
                            found.appendChild(document.createTextNode(RegExp.$2));
                            a.appendChild(head);
                            a.appendChild(found);
                            a.appendChild(tail);
                        }
                        else
                        {
                            a.appendChild(document.createTextNode(result_list[i].name));
                        }
                        li.appendChild(a);
                        ul.appendChild(li);
                    }
                    document.getElementById("suggestion_box").appendChild(ul);

                    return true;
                }
            }
            else
            {
                document.getElementById("suggestion_box").style.display = "none";
                return false;
            }
        }
    };

    xhr.send();
    return true;
}  // function PlaceSuggest()


function DisplayResults(result, prefix)
{
    showMsgBox("msg_box_search_results");
    
	// remove already existing search hits (if any)
    if(document.getElementById("search_hits").hasChildNodes())
    {
        document.getElementById("search_hits").removeChild(document.getElementById("search_hits").firstChild);
    }
    document.getElementById("search_hits").appendChild(document.createTextNode(result.length));

    // sort array of objects
//     result.sort(function(a, b) { return a.name > b.name; });

    // display search results in a link list
    var typed_ul = {};
    for(var i = 0; i < result.length; i++)
    {
        // create anchor element
        var a = document.createElement("a");
        a.href = prefix+"/"+result[i].link_name;
        a.appendChild(document.createTextNode(result[i].name));
        if(result[i].zip)
        {
            a.appendChild(document.createTextNode(" ("+result[i].zip.join(", ") + ")"));
        }

        // create list item element
        var li = document.createElement("li");
        li.appendChild(a);

        // create typed ul if it does not exist yet
        if(typed_ul[result[i].type] == undefined)
        {
            typed_ul[result[i].type] = document.createElement("ul");
        }

        // append list item to typed ul
        typed_ul[result[i].type].appendChild(li);
    }

    // remove any previous search results (if any)
    while(document.getElementById("search_result_list").hasChildNodes())
    {
        document.getElementById("search_result_list").removeChild(document.getElementById("search_result_list").lastChild);
    }

    // add new search results, grouped by type
    for(place_type in typed_ul)
    {
        // print place type as h4
        var h4 = document.createElement("h4");
        h4.appendChild(document.createTextNode(place_type));
        document.getElementById("search_result_list").appendChild(h4);

        // output list with the types
        document.getElementById("search_result_list").appendChild(typed_ul[place_type]);
    }

}  // function DisplayResults()


function MapPopup(place_id)
{
    elem = document.getElementsByClassName("place_"+place_id)[0];
    Menu.open(elem);
}  // function MapPopup()


/**
* @brief browse through all child elements of the given "list" element using the "how" method
* @param list - object - a DOM object
* @param how - string - currently either "forward" or "backward"
*/
function BrowseList(list, how)
{
    // init vars
    var li_list = [];
    var iteration = 1;

    // get (reverse) list item list
    switch(how)
    {
    case "forward":
        // check if we are already at end of list
        var li = list.lastChild;
        while(li)
        {
            if(li.nodeType == 1 && li.nodeName.match(/^li$/i))
            {
                if(li.style.display != "none" && iteration == 1)
                {
                    return;  // don't do anything
                }
                iteration++;
            }
            li = li.previousSibling;
        }

        // get list item list
        for(var i = 0; i < list.childNodes.length; i++)
        {
            if(list.childNodes[i].nodeType == 1 && list.childNodes[i].nodeName.match(/^li$/i))
            {
                li_list.push(list.childNodes[i]);
            }
        }

        break;
    case "backward":
        // check if we are already at start of list
        var li = list.firstChild;
        while(li)
        {
            if(li.nodeType == 1 && li.nodeName.match(/^li$/i))
            {
                if(li.style.display != "none" && iteration == 1)
                {
                    return;  // don't do anything
                }
                iteration++;
            }
            li = li.nextSibling;
        }

        // get list item list
        for(var i = list.childNodes.length-1; i >= 0 ; i-=1)
        {
            if(list.childNodes[i].nodeType == 1 && list.childNodes[i].nodeName.match(/^li$/i))
            {
                li_list.push(list.childNodes[i]);
            }
        }

        break;
    }

    // iterate every valid given list item
    var previous_state = "none";
    for(var i = 0; i < li_list.length; i++)
    {
        // shortcut for easier handling
        var li = li_list[i];

        // save last state of list item
        var last_state = li.style.display;

        // if current is not "none" && previous state is "none"
        if(
            (li.style.display != "none")
            &&
            (previous_state == "none")
        )
        {
            li.style.display = "none";
        }
        else if(
            (li.style.display == "none")
            &&
            (previous_state != "none")
        )
        {
            li.style.display = "";

        }

        // save last state for next iteration
        previous_state = last_state;
    }

    return;
}


/**
* @brief submit the given form, but not with normal request, but XMLHttpRequest
* @param form - object - the form to submit
* @param callback - function - the callback function to execute
* @param true .. success; false .. error
*/
function AjaxSubmit(form, callback)
{
    // check all required fields of the form
    for(var i = 0; i < form.elements.length; i++)
    {
        if(
        form.elements[i].getAttribute("required")
        &&
        form.elements[i].getAttribute("required").match(/\brequired\b/)
        &&
        (!form.elements[i].value || form.elements[i].value.match(/^\s*$/))
        )
        {
            form.elements[i].focus();
            showMsgBox("msg_box_required_fail");
            return false;
        }
    }

    // get action
    var action = form.action;

    // get method
    var method = "GET";
    if( form.method.toUpperCase() == "POST" )
    {
        method = form.method.toUpperCase();
    }

    // get encoding
    var encoding = "application/x-www-form-urlencoded";
    if( method == "POST" && form.encoding == "multipart/form-data" )
    {
        encoding = form.encoding;
    }

    // collect form data, construct query string and disable collected form controls
    var query = [];
    for(var i = 0; i < form.elements.length; i++)
    {
        var elem = form.elements[i];
        if( !elem.name )
        {
            continue;
        }

        if( elem.type == "checkbox" || elem.type == "radio" )
        {
            if( elem.checked )
            {
                query.push(encodeURIComponent(elem.name) + "=" + encodeURIComponent(elem.value));
            }
        }
        else
        {
            // text, hidden
            query.push(encodeURIComponent(elem.name) + "=" + encodeURIComponent(elem.value));
        }
    } // for(var i = 0; i < form.elements.length; i++)
    query = query.join("&");

    // hide entire form from view and display throbber instead
    form.style.display = "none";
    var throbber = document.createElement("img");
    throbber.src = ROOT_PATH+"/img/design/throbber.gif";
    throbber.alt = "...";
    throbber.style.textAlign = "center";
    form.parentNode.insertBefore(throbber, form);

    // prepare http request
    var entity = null;
    var xhr = new XMLHttpRequest();
    switch(method)
    {
        case "POST":
            xhr.open(method, action, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.setRequestHeader("Accept", "application/json");
            xhr.setRequestHeader("Content-Type", encoding);
            entity = query;
            break;
        default:
            var get = action;
            if(action.match(/\?./))
            {
                get += "&"+query;
            }
            else if(action.match(/\?/))
            {
                get += query;
            }
            else
            {
                get += "?"+query;
            }
            xhr.open(method, get, true);
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
            xhr.setRequestHeader("Accept", "application/json");
            break;
    } // switch(method)

    // set up callback function
    xhr.onreadystatechange = function()
    {
        if(xhr.readyState == 4)  // if request was completed
        {
            // restore submit form
            form.style.display = "block";
            form.parentNode.removeChild(throbber);

            // also reset form on success and only on POST method
            if((xhr.status >= 200) && (xhr.status <= 299) && method == "POST")
            {
                form.reset();
            }
            else if(xhr.status == 404)
            {
                showMsgBox("msg_box_ajax_error_404");
                return false;
            }
            else if(xhr.status >= 500 && xhr.status <= 599)
            {
                showMsgBox("msg_box_ajax_error_5xx");
                return false;
            }

            // get json if possible
            var json = {};
            if((xhr.getResponseHeader("Content-Type") == "application/json") && xhr.responseText)
            {
                json = JSON.parse(xhr.responseText);  // parse response text as json, use json2.js
                if(!json)
                {
                    showMsgBox("msg_box_ajax_error_json");
                    return false;
                }
            }

            // default errors
            if(callback)
            {
                json.ACTION = action;  // must always be present on callback function
                callback(xhr.status, json);
            }
            else  // fallback to alert()
            {
                if((xhr.status < 200) || (xhr.status > 299))
                {
                    alert("HTTP "+method+" Status "+xhr.status);
                    if(xhr.responseText && xhr.getResponseHeader("Content-Type").match(/text|xml/))
                    {
                        alert(xhr.responseText.substr(0, 80));
                    }
                }
            }
        } // if(xhr.readyState == 4)
    }; // xhr.onreadystatechange = function()

    xhr.send(entity);
    return true;
}  // function AjaxSubmit()


function CallbackResetPassword(status, json)
{
    if(status >= 200 && status <= 299)
    {
        showMsgBox("msg_box_reset_password_ok");
        return true;
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_reset_password_fail");
        return false;
    }
}


function CallbackSetPassword(status, json)
{
    if(status >= 200 && status <= 299)
    {
        showMsgBox("msg_box_new_password_ok");
        return true;
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_new_password_fail");
        return false;
    }
}


function CallbackSetEmail(status, json)
{
    if(status >= 200 && status <= 299)
    {
        showMsgBox("msg_box_new_email_ok");
        return true;
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_new_email_fail");
        return false;
    }
}


function CallbackRegister(status, json)
{
    if(status >= 200 && status <= 299)
    {
        showMsgBox("msg_box_register_ok");
        return true;
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_register_fail");
        return false;
    }
}


function CallbackLogin(status, json)
{
    if(status >= 200 && status <= 299)
    {
        location.reload();
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_login_fail");
        return false;
    }
}


function CallbackDelPhoto(status, json)
{
    if(status >= 200 && status <= 299)
    {
        location.reload();
    }
    else if(status >= 400 && status <= 499)
    {
        showMsgBox("msg_box_photo_delete_fail");
        return false;
    }
}


function ExchangeFormat(radio)
{
    if(radio.name != "image_format")
    {
        return false;
    }

    var new_format = radio.value;

    var rows = document.getElementsByClassName("widget_code");

    for(var i = 0; i < rows.length; i++)
    {
        // change img src
        var img = rows[i].firstChild.firstChild.firstChild;  // the <img> element
        var new_src = img.src.replace(/\.(png|jpe?g|gif)$/i, "."+new_format);
        if(new_src == img.src)
        {
            // no change to image
            return false;
        }
        img.src = new_src;

        // change embed code
        var textarea = rows[i].lastChild.firstChild;  // the <textarea> element
        textarea.value = textarea.value.replace(/\.(png|jpe?g|gif)" alt="/i, "."+new_format+"\" alt=\"");
    }

    return true;
}

function focusInputValue(def_val, type, input_number, sender) 
{
	//if the value is the default-text
    if (sender.value == def_val)
    {
    	var input = document.createElement("input");
    	input.setAttribute("id",sender.getAttribute("id"));
    	input.setAttribute("onfocus",sender.getAttribute("onfocus"));
    	input.setAttribute("onblur",sender.getAttribute("onblur"));
    	input.setAttribute("value","");
    	input.setAttribute("name",sender.getAttribute("name"));
    	input.setAttribute("type",type);
        input.style.color="#005588";
    	sender.parentNode.replaceChild(input,sender);
    	var name = input.getAttribute("name");
    	document.forms["login_form"].elements[input_number].focus();
    }
}

function blurInputValue(def_val, type, input_number, sender) 
{
    if (sender.value == "")
    {
    	var input = document.createElement("input");
    	input.setAttribute("id",sender.getAttribute("id"));
    	input.setAttribute("onfocus",sender.getAttribute("onfocus"));
    	input.setAttribute("onblur",sender.getAttribute("onblur"));
    	input.setAttribute("value",def_val);
    	input.setAttribute("name",sender.getAttribute("name"));
    	input.setAttribute("type","text");
        input.style.color="#D6D6D6";
    	sender.parentNode.replaceChild(input,sender);
    }
}

function toggleAgreement(sender)
{
	if(sender.checked)
	{
		document.getElementById("widget_not_accept").style.visibility="hidden";
		document.getElementById("widget_table").style.visibility="visible";
	}
	else
	{
		document.getElementById("widget_table").style.visibility="hidden";
		document.getElementById("widget_not_accept").style.visibility="visible";
	}
}
