/*
 * This file is part of the RProducts CMFPlone Product collection. 
 * 
 * Copyright 2007-8 by Diedrich Vorberg <diedrich@tux4web.de>
 * 
 * All Rights Reserved
 * 
 * For more Information on orm see the README file.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 * I have added a copy of the GPL in the file COPYING
 * 
 * The parts of this file dealing with cookies have been taken from
 *
 *   http://techpatterns.com/downloads/javascript_cookies.php
 *
 * and are in the public domain. 
 *
 * $Log: t4lib.js,v $
 * Revision 1.5  2009-01-26 23:23:39  t4w00-diedrich
 * User this. instead of t4lib. for internal references (why didn't I do
 * this before?) and fixed set_param().
 *
 * Revision 1.4  2009-01-04 14:23:02  t4w00-diedrich
 * Installed Plone Fork on the Production Server. Minor changes pretty much everywhere.
 *
 * Revision 1.3  2008-08-26 10:10:27  t4w00-diedrich
 * Added strip()
 *
 * Revision 1.2  2008-08-25 20:17:50  t4w00-diedrich
 * User the time-tested get_response_text() in load_xml_from_url() rather
 * than its own logic.
 *
 * Revision 1.1.1.1  2008-08-22 14:29:45  t4w00-diedrich
 * Initial import
 *
 *
 */


/*
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
activated by calling t4lib.onload_manager.handle_onload_event() in the
<body> tag's onload= event (attribute). 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(function_, timeout)
{
	this.handlers.push(Array(function_, 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;

/**********************************************************************/
/* URLs                                                               */
/**********************************************************************/

/**
 * 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 ?.
 */
_t4lib.prototype.param_array_from_url = function(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;
    }
}

/**
 * Convert an associative array as param_name: value to a url param
 * string.
 */
_t4lib.prototype.url_params = function(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;
}

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

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

    return ret;
}

/**
 * Return a copy of PARAM_ARRAY width PARAM set to VALUE.
 */
_t4lib.prototype.set_param_in_array = function(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;
}



/**
 * Take BASE (url part without params) and a PARAM_ARRAY and return
 * a complete url. No parameter escaping is performed.
 */
_t4lib.prototype.url_from_param_array = function(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("");
}




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

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

    return this.url_from_param_array(base, param_array);
}




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

/**
 * Return a HTMLRequest object suitable for AJAX operations
 */  
_t4lib.prototype.xml_request = function()
{
	if ( window.XMLHttpRequest && (!window.ActiveXObject))
	{
		return new XMLHttpRequest();
	}
	else
	{
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
}

/**
 * Make a GET request with a webserver and return as a string what it 
 * had to say. This always requires a callback.
 */
_t4lib.prototype.get_response_text = function( url, callback )
{
    var xmlhttp = this.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. */
				callback(xmlhttp.responseText); 
			}
			else
			{
				alert( "HTTP ERROR!! " + xmlhttp.status + " " + url );
			}
        }
	}
		
	xmlhttp.send("");
}
	


/**
 * Make a GET request to a webserver, which is expected to return HTML
 * and replace a DOM element's content with that HTML.
 */
_t4lib.prototype.replace_element_content_from_url = function(element, url,
                                                             async, callback)
{
    var xmlhttp = this.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();
	}			
}



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

/**
 * Load the XML file, parse it and call CALLBACK with the parsed
 * representation as only parameter.
 */
 

_t4lib.prototype.load_xml_from_url = function( url, callback )
{    
    this.get_response_text( url,
                             function ( xml )
                             {
                                 var xml_document = t4lib.xml_from_string (
                                     xml );
                                 callback( xml_document );
                             }
                           );
}

/**
 * Parse a string into a DOM tree.
 */

_t4lib.prototype.xml_from_string = function(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;	
}




/**********************************************************************/
/* DOM tree and <form> functions                                      */
/**********************************************************************/

/**
 * Return the first element whose name= attribute is set to a specific
 * value.
 */
_t4lib.prototype.first_element_by_name = function(input_name)
{
	var result = document.getElementsByName(input_name);
	
	if ( result.length == 0 ) {
		alert("Cannot find " + input_name);
	}
	else
	{
		return result[0];
	}
}

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

_t4lib.prototype.get_attribute = function(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.has_attribute = function(element, attr_name)
{
	for ( var a = 0; a < element.attributes.length; a++)
	{
		if ( element.attributes[a].nodeName == attr_name )
		{
			return true;
		}
	}

	return false;
}

/**
 * This returns the text content of an XML element's child element with
 * a specified tag name.
 */
_t4lib.prototype.get_child_content = function(element, tag_name, default_)
{
	if ( !default_ )
	{
		default_ = null;
	}
	
	var result = element.getElementsByTagName(tag_name);	

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

/**
 * Get all the plain text from a DOM (sub-)tree
 */

_t4lib.prototype.text_content = function( 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 + this.text_content ( node );
			}
		}

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

/**
 * Like first_element_by_name() above, but takes a parent element as second
 * argument
 */

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

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

	return null;
}


/**
 * Like document.getElementById() except that it takes the parent
 * element instead the whole document.
 */
_t4lib.prototype.element_by_id_in = function(input_name, parent)
{
	var result = parent.getElementsByTagName("*");

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


_t4lib.prototype.get_input_value = function(input_name) {
	input = this.first_element_by_name(input_name);
	return input.value;
}



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



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



_t4lib.prototype.get_checked = function(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_radio = function(radiobox_name) {
    var result = document.getElementsByName(radiobox_name);

    for ( var a = 0; a < result.length; a++ )
    {
        var radiobox = result[a];

        if ( radiobox.checked )
        {
            return radiobox.value;
        }
    }

    return null;
}


        
/**
 * Ask, if the user wants to follow a link or not. Goes into the link's
 * href= tag with a javascript: type url:
 *
 *   <a href="javascript:ask_link('Sure??', '/cgi-bin/total_descruction.cgi')>
 *     Kill everything
 *   </a>
 *
 */
_t4lib.prototype.ask_link = function(question, href)
{
    if (window.confirm(question))
    {
		window.location.href = href;
    }
}


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

_t4lib.prototype.set_cookie = function ( 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 + "=" );
_t4lib.prototype.get_cookie = function( 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 = '';
	}
    
	return null;
}

// this deletes the cookie when called
_t4lib.prototype.delete_cookie = function( 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";
}


/* Misc functions this bullshit JavaScript API doesn't include. */

/**
 * Strips leading and trailing whitespace off of a string.
 */
_t4lib.prototype.strip = function(s)
{
    return s.replace(/^\s+|\s+$/g, '') ;
}

var t4lib = new _t4lib();


