/**
 * (c) 2007-8 Diedrich Vorberg <diedrich@tux4web.de>
 *
 *
 * Changelog
 * ---------
 * $Log: t4lib.js,v $
 * Revision 1.4  2008-04-15 02:40:41  t4w00-diedrich
 * - Added GMap user interface
 * - Substantial changes to t4lib.js and uses thereof
 * - Minor changes, mostly related to the new map function
 * 
 *
 */


/*
The t4lib 'namespace' (Harhar) contains a number of functions as well as one
class object: onload_manager, whoes methods are described below. 
*/
function _t4lib()
{
	this.onload_manager = new this._onload_manager();
};


/*
onload_manager
 
The onload manager maintains a list of javascript functions which are
by the <body> tag's onload= event. When registering a function with
the register() method you may optionally specify a timeout after the
onload event when to call the handler.
*/

function _onload_manager()
{
	this.handlers = Array();
}

_onload_manager.prototype.register = function(f, timeout)
{
	this.handlers.push(Array(f, timeout));
}

_onload_manager.prototype.handle_onload_event = function ()
{
	for (var a = 0; a < this.handlers.length; a++)
	{
		var f = this.handlers[a][0];
		var timeout = this.handlers[a][1];
		
		if ( timeout )
		{
			setTimeout("t4lib.onload_manager.call_handler(" + a + ")", timeout);
		}
		else
		{
			f();
		}
	}
}
	
_onload_manager.prototype.call_handler = function(index)
{
	var f = this.handlers[index][0];
	f();
}

_t4lib.prototype._onload_manager = _onload_manager;

/**********************************************************************/
/* URL                                                                */
/**********************************************************************/

/**
 * Return an Array of Array as in
 * 
 *  Array(Array(name0, value0),
 *        Array(name1, value1),
 *        ...)
 *
 *  The URL param may be either a complete URL (of which the part before
 *  the ? will be discarded) or just the parameter part after the ?.
 */
function param_array_from_url(url)
{
    var parts;
    var rest;

    parts = url.split("?");

    // No '?' present? 
    if (parts.length != 2)
    {
        rest = url;        
    }
    else
    {
        rest = parts[1];
    }

    if (rest == "")
    {
        return Array();
    }
    else
    {
        // Split the parameter list
        var ret = Array();
        
        parts = rest.split("&");
        
        for (var a = 0; a < parts.length; a++)
        {
            var part = parts[a];
            var pair = part.split("=");
            
            if (pair.length == 2)
            {
                var name = pair[0];
                var value = pair[1];
                
                ret.push(Array(name, value));
            }
        }
        
        return ret;
    }
}

_t4lib.prototype.param_array_from_url = param_array_from_url;

/* Return an associative array as param_name: value to a url param string
 */
function url_params(values)
{
    var params = Array();
    for (var name in values)
    {
        var value = values[name];
        value = encodeURI(value);
        value = value.replace("&", "%26");
        value = value.replace("+", "%2B");
        
        params.push(name + "=" + value);
    }

    var url_params = params.join("&");

    return url_params;
}

_t4lib.prototype.url_params = url_params;


/**
 * Split URL in a url and a parameter part. Always returns a two element
 * array of strings.
 */
function split_url(url)
{
    var ret = url.split("?");

    // Make sure the array we return as two elements.
    if (ret.length != 2)
    {
        ret.push("");
    }

    return ret;
}

_t4lib.prototype.split_url = split_url;

/**
 * Return a copy of PARAM_ARRAY width PARAM set to VALUE.
 */
function set_param_in_array(param_array, param, new_value)
{
    var new_param_array = Array();
    for(var a = 0; a < param_array.length; a++)
    {
        var name = param_array[a][0];
        var value = param_array[a][1];
            
        if ( name != param && value != null)
        {
            new_param_array.push(param_array[a]);
        }
    }

    if (new_value != null)
    {
        new_param_array.push(Array(param, "" + new_value));
    }
    
    return new_param_array;
}

_t4lib.prototype.set_param_in_array = set_param_in_array;

/**
 * Take BASE (url part without params) and a PARAM_ARRAY and return
 * a complete url. No parameter escaping is performed.
 */
function url_from_param_array(base, param_array)
{
    ret = Array();

    ret.push(base);
    
    var params = Array();
    for (var a = 0; a < param_array.length; a++)
    {
        if (param_array[a][1] != null)
        {    
            var param = param_array[a].join("=");
            params.push(param);
        }
    }

    if (params.length > 0)
    {
        ret.push("?");
        ret.push(params.join("&"));
    }

    return ret.join("");
}


_t4lib.prototype.url_from_param_array = url_from_param_array;

/**
 * Set PARAM to VALUE in url and return the new url.
 */
function set_param(url, param, value)
{
    var parts = split_url(url);    
    var base = parts[0];

    var param_array = t4lib.param_array_from_url(parts[1]);
    param_array = t4lib.set_param_in_array(param_array, param, value);

    return t4lib.url_from_param_array(base, param_array);
}

_t4lib.prototype.set_param = set_param;


/**********************************************************************/
/* Some basic AJAX stuff                                              */
/**********************************************************************/

function xml_request()
{
	if ( window.XMLHttpRequest && (!window.ActiveXObject))
	{
		return new XMLHttpRequest();
	}
	else
	{
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}

_t4lib.prototype.xml_request = xml_request;

function get_response_text( url, callback )
{
    var xmlhttp = xml_request();

    xmlhttp.open("GET", url, true);
    
    /* Send the POST request */
    xmlhttp.setRequestHeader( 'Content-Type',
                              'application/x-www-form-urlencoded' );
	
	xmlhttp.onreadystatechange = function() {
		if ( xmlhttp.readyState == 4 ) {
			if ( xmlhttp.status == 200 )
			{
				/* For Mozilla it's important that the CGI that
				   serves the HTML sets the ContentType to
				   text/html, rather than text/xml or
				   something. text/plain won't work at all.
				   Safari is more flexible and just works. */
				if (typeof callback != "undefined") callback(xmlhttp.responseText); 
			}
			else
			{
				alert( "HTTP ERROR!! " + xmlhttp.status + " " + url );
			}
        }
	}
		
	xmlhttp.send("");
}
	

_t4lib.prototype.get_response_text = get_response_text;

function replace_element_content_from_url(element, url, async, callback)
{
    var xmlhttp = t4lib.xml_request();
    xmlhttp.open("GET", url, async);

	if ( async )
	{
		/* The callback function */
		xmlhttp.onreadystatechange = function() {
			if (xmlhttp.readyState == 4) {
				if (xmlhttp.status == 200)
				{
					/* For Mozilla it's important that the CGI that
					   serves the HTML sets the ContentType to
					   text/html, rather than text/xml or
					   something. text/plain won't work at all.
					   Safari is more flexible and just works. */
					element.innerHTML = xmlhttp.responseText;					
					if (callback != null) callback(); 
				}
				else
				{
					alert("HTTP ERROR!! " + xmlhttp.status + " " + url);
				}
			}			
        }		
    }
    
    /* Send the POST request */
    xmlhttp.setRequestHeader('Content-Type',
                             'application/x-www-form-urlencoded');
    xmlhttp.send(null);

	if ( !async )
	{
		/* The same stuff applies as for the innerHTML assignment above. */
		element.innerHTML = xmlhttp.responseText;						
		if (callback != null) callback();
	}
			
}

_t4lib.prototype.replace_element_content_from_url = replace_element_content_from_url;

/**********************************************************************/
/* XML                                                                */
/**********************************************************************/

/**
 * Load the XML file, parse it and call CALLBACK with the parsed
 * representation as only parameter.
 */
 
function load_xml_from_url( url, callback )
{
	var xmlDoc;

	if ( document.implementation && document.implementation.createDocument )
	{
		xmlDoc = document.implementation.createDocument("", "", null);
		xmlDoc.onload = function () {
			callback(xmlDoc);
		}
	}
	else if ( window.ActiveXObject )
	{
		xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
		xmlDoc.onreadystatechange = function () {
			if (xmlDoc.readyState == 4)
			{
				callback(xmlDoc);
			}
		};
 	}
	else
	{
		alert("Your browser can't handle this script");
		return;
	}
}

_t4lib.prototype.load_xml_from_url = load_xml_from_url;

function xml_from_string(s)
{
	var xmlDoc;

	if (document.implementation && document.implementation.createDocument)
	{
		parser = new DOMParser();
		xmlDoc = parser.parseFromString(s, "text/xml");
	}
	else if (window.ActiveXObject)
	{
		xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.loadXML(s);
 	}
	else
	{
		alert("Your browser can't handle this script");
		return;
	}

	return xmlDoc;	
}

_t4lib.prototype.xml_from_string = xml_from_string;


/**********************************************************************/
/* Form functions                                                     */
/**********************************************************************/

function first_element_by_name(input_name)
{
	var result = document.getElementsByName(input_name);
	
	if ( result.length == 0 ) {
		alert("Cannot find " + input_name);
	}
	else
	{
		return result[0];
	}
}

_t4lib.prototype.first_element_by_name = first_element_by_name;


/* I can't believe I have to implement this. Who came up with the
crappy JavaScript runtime library?? */

function getAttribute(element, attr_name)
{
	for ( var a = 0; a < element.attributes.length; a++)
	{
		if ( element.attributes[a].nodeName == attr_name )
		{
			return element.attributes[a].nodeValue;
		}
	}

	return null;
}

_t4lib.prototype.getAttribute = getAttribute;
_t4lib.prototype.get_attribute = getAttribute;

function hasAttribute(element, attr_name)
{
	for ( var a = 0; a < element.attributes.length; a++)
	{
		if ( element.attributes[a].nodeName == attr_name )
		{
			return true;
		}
	}

	return false;
}

_t4lib.prototype.hasAttribute = hasAttribute;
_t4lib.prototype.has_attribute = hasAttribute;

function getChildContent(element, tag_name, default_)
{
	if ( !default_ )
	{
		default_ = null;
	}
	
	var result = element.getElementsByTagName(tag_name);	

	if ( result.length == 0 )
	{
		return default_;
	}
	else
	{
		return textContent(result[0]);
	}
}

_t4lib.prototype.getChildContent = getChildContent;
_t4lib.prototype.get_child_content = getChildContent;

function textContent( parent )
{
	if ( parent.hasChildNodes() )
	{
		var ret = "";

		for ( var a = 0; a < parent.childNodes.length; a++ )
		{
			var node = parent.childNodes[a];
			if ( node.nodeType == 3 )
			{
				ret = ret + node.data;
			}
			else
			{
				ret = ret + t4lib.textContent ( node );
			}
		}

		return ret;
	}
	else
	{
		return "";
	}
}

_t4lib.prototype.textContent = textContent;
_t4lib.prototype.text_content = textContent;


function first_element_by_name_in(input_name, parent)
{
	var result = parent.getElementsByTagName("*");

	for( var a = 0; a < result.length; a++)
	{
		if ( t4lib.hasAttribute(result[a], "name") &&			 
			 t4lib.getAttribute(result[a], "name") == input_name )
		{
			return result[a];
		}
	}

	return null;
}

_t4lib.prototype.first_element_by_name_in = first_element_by_name_in;

function element_by_id_in(input_name, parent)
{
	var result = parent.getElementsByTagName("*");

	for( var a = 0; a < result.length; a++)
	{
		if ( t4lib.hasAttribute(result[a], "id") &&
			 t4lib.getAttribute(result[a], "id") == input_name )
		{
			return result[a];
		}
	}
	alert("Cannot find " + input_name);
}

_t4lib.prototype.element_by_id_in = element_by_id_in;

function get_input_value(input_name) {
	input = t4lib.first_element_by_name(input_name);
	return input.value;
}

_t4lib.prototype.get_input_value = get_input_value;

function get_selected(select_name) {
	var select = t4lib.first_element_by_name(select_name);
	return select.options[select.selectedIndex].value;
}

_t4lib.prototype.get_selected = get_selected;

function get_selected_content(select_name) {
	var select = t4lib.first_element_by_name(select_name);
	return select.options[select.selectedIndex].innerHTML;
}

_t4lib.prototype.get_selected_content = get_selected_content;

function get_checked(checkbox_name) {
	var result = document.getElementsByName(checkbox_name);
	var ret = Array();

	for ( var a = 0; a < result.length; a++ )
	{
		var checkbox = result[a];
		
		if ( checkbox.checked )
		{
			ret.push( checkbox.value );
		}
	}

	return ret;
}

_t4lib.prototype.get_checked = get_checked;

/**********************************************************************/
/* Misc                                                               */
/**********************************************************************/

function ask_link(question, href)
{
    if (window.confirm(question))
    {
		window.location.href = href;
    }
}

_t4lib.prototype.ask_link = ask_link;

var t4lib = new _t4lib();

/**********************************************************************/
/* (Google Map -) Coordinates                                         */
/**********************************************************************/
_t4lib.prototype.coordinates2latlng = function ( coordinates )
{
	if ( coordinates == "" )
	{
		return null;
	}
	else
	{
		var result = coordinates.split(",");
		if ( result.length != 2 )
		{
			alert("Illegal coordinates '" + coordinates + "'");
		}
		else
		{
			return new GLatLng(result[0], result[1]);
		}
	}
}

_t4lib.prototype.latlng2coordinates = function (latlng)
{
	return latlng.lat() + "," + latlng.lng();
}


/* Cookies */

// Source: http://techpatterns.com/downloads/javascript_cookies.php

function set_cookie( name, value, expires, path, domain, secure ) 
{
	// set time, it's in milliseconds
	var today = new Date();
	today.setTime( today.getTime() );
	
	/* if the expires variable is set, make the correct expires time,
	the current script below will set it for x number of days, to make
	it for hours, delete * 24, for minutes, delete * 60 * 24 */
	
	if ( expires )
	{
		expires = expires * 1000 * 60 * 60 * 24;
	}
	var expires_date = new Date( today.getTime() + (expires) );
	
	document.cookie = name + "=" +escape( value ) +
		( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
		( ( path ) ? ";path=" + path : "" ) + 
		( ( domain ) ? ";domain=" + domain : "" ) +
		( ( secure ) ? ";secure" : "" );
}
	
		

// this fixes an issue with the old method, ambiguous values 
// with this test document.cookie.indexOf( name + "=" );
function get_cookie( check_name ) {
	// first we'll split this cookie up into name/value pairs
	// note: document.cookie only returns name=value, not the other components
	var a_all_cookies = document.cookie.split( ';' );
	var a_temp_cookie = '';
	var cookie_name = '';
	var cookie_value = '';
	var b_cookie_found = false; // set boolean t/f default f
	
	for ( i = 0; i < a_all_cookies.length; i++ )
	{
		// now we'll split apart each name=value pair
		a_temp_cookie = a_all_cookies[i].split( '=' );
		
		
		// and trim left/right whitespace while we're at it
		cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
		
		// if the extracted name matches passed check_name
		if ( cookie_name == check_name )
		{
			b_cookie_found = true;
			// we need to handle case where cookie has no value but exists (no = sign, that is):
			if ( a_temp_cookie.length > 1 )
			{
				cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
			}
			// note that in cases where cookie is initialized but no value, null is returned
			return cookie_value;
			break;
		}
		a_temp_cookie = null;
		cookie_name = '';
	}
	if ( !b_cookie_found )
	{
		return null;
	}
}

// this deletes the cookie when called
function delete_cookie( name, path, domain ) {
	if ( Get_Cookie( name ) ) document.cookie = name + "=" +
		( ( path ) ? ";path=" + path : "") +
		( ( domain ) ? ";domain=" + domain : "" ) +
		";expires=Thu, 01-Jan-1970 00:00:01 GMT";
}

_t4lib.prototype.set_cookie = set_cookie;
_t4lib.prototype.get_cookie = get_cookie;
_t4lib.prototype.delete_cookie = delete_cookie;