/*   L I S T   #################################################################################### */
/**
 *	List object.
 */
function ArrayList() {
	this.array = new Array();
	
	
	/**
	 * Adds a new element to the list.
	 * 
	 * @param element
	 * 			the new element
	 */
	this.add = function(element) {
		this.array.push(element);
	};
	
	
	/**
	 * Returns an element at a certain index.
	 * 
	 * @param index
	 * 			the index in the list
	 * @return an element of the list
	 */
	this.get = function(index) {
		return this.array[index];
	};
	
	
	/**
	 * Removes all elements of the list.
	 */
	this.removeAll = function() {
		while (this.array.length > 0) {
			this.array.pop();
		}
	};
	
	
	/**
	 * Returns the size of the list.
	 */
	this.size = function() {
		return this.array.length;
	};
	
	
	/**
	 * Fills the list with an array.
	 * 
	 * @param array
	 * 			the array
	 */
	this.fillWithArray = function(array) {
		for(var i = 0; i < array.length; i++) {
			this.add(array[i]);
		}
	};
	
	
	/**
	 * Adds a collection to the list
	 * 
	 * @param list
	 * 			the list
	 */
	this.addCollection = function(list) {
		for (var i = 0; i < list.size(); i++) {
			var element = list.get(i);
			
			this.add(list.get(element));
		}
	}
}

/*   M A P   ###################################################################################### */
/**
 * Object Map
 * 
 * @see java.util.Map
 */
function Map() {
	this.list = new ArrayList();
	
	/**
	 * Puts a pair of key and value into the map.
	 * 
	 * @param key
	 * 			the key of the property
	 * @param value
	 * 			the value of the property 
	 */
	this.put = function(key, value) {
		var property = new Property(key, value);
		this.list.add(property);	
	}

	
	/**
	 * Returns the value of a key, stored in the map.
	 * 
	 * @param key	
	 * 			the key
	 * 
	 * @return the value of the given key
	 */
	this.get = function(key) {
		var value = null;
		
		for (var i = 0; i < this.list.size(); i++) {
			var property = this.list.get(i);
			
			if (property.getKey() == key) {
				value = property.getValue();
				
				i = this.list.size();
			}
		}
		
		
		if (value == null) {
			alert("ERROR: Map.get(): did not find \"" + key + "\" in map");
		}
		
		return value;
	}
			

	/**
	 * Returns the size of the map.
	 * 
	 * @return the size of the map
	 */
	this.getSize = function() {
		return this.list.size();
	}
	
	
	/**
	 * Returns the size of the map.
	 * 
	 * @return the size of the map
	 */
	this.setValueOf = function(key, value) {
		var found = false;
	
		for(var i = 0; i < this.list.size(); i++) {
			var property = this.list.get(i);
			
			if (property.getKey() == key) {
				property.setValue(value);
				
				i = this.list.size();
				found = true;
			}
		}
		
		if (!found) {
			alert("ERROR: Map.get(): did not find \"" + key + "\" in map");
		}
	}
	
	
	/**
	 * Returns a property at a certain position.
	 * 
	 * @param index
	 * 			the index of the property in the array
	 * 
	 * @return a property
	 */
	this.getPropertyAt = function(index) {
		return this.list.get(index);
	}
}


/*   P R O P E R T Y   ############################################################################ */

/**
 * Object Property (needed for the map). A Property contains a field for a key and one for its value.
 */
function Property(key, value) {
	this.key = key;
	this.value = value;


	/**
	 * Returns the value.
	 * 
	 * @return the value
	 */
	this.getValue = function() {
		return this.value;
	}
	
	
	/**
	 * Sets the value.
	 * 
	 */
	this.setValue = function(value) {
		this.value = value;
	}
	
	
	/**
	 * Returns the key
	 * 
	 * @return the key
	 */
	this.getKey = function() {
		return this.key;
	}
	
	
	/**
	 * Returns the key
	 * 
	 * @return the key
	 */
	this.toString = function() {
		return this.key + ": " + this.value;
	}
}

/*   D A T E F O R M A T E R   #################################################################### */
var SEPARATOR = "%";

/**
 *	Object definition
 */
var DateFormatter = {
	/**
	 *	static method: formats a date to a give format
	 *
	 *	@param date
	 *		the date
	 *	@param format
	 *		the format for the string (e.g. %dd%.%mm%.%yyyy%)
	 *			implemented keys:
	 *				- d		the day (0 - 31)
	 *				- dd	the day (00 - 31)
	 *				- m		the month (1 - 12)
	 *				- mm	the month (01 - 12)
	 *				- b		the short name of the month (Jan - Dez)
	 *				- B		the long name of the month (Januar - Dezember)
	 *				- yyyy	the year (2006)
	 *				- a		the short name of the day (Mo - So)
	 *				- A		the long name of the day (Montag - Sonntag)
	 *				- HH	the hour (00 - 23)
	 *				- MM	the minute (00 - 59)
	 *				- SS	the second (00 - 59)
	 *
	 *	@return a string
	 */
	format : function(date, format) {
		dateAsString = "";
		var map = new Map();
		map.put("d", date.getDate());
		map.put("dd", ((date.getDate() < 10) ? "0" : "") + date.getDate());
		map.put("m", date.getMonth());
		map.put("mm", (((date.getMonth() + 1) < 10) ? "0" : "") + (date.getMonth() + 1));
		map.put("b", shortNamesOfMonths[date.getMonth()]);
		map.put("B", longNamesOfMonths[date.getMonth()]);
		map.put("yyyy", date.getFullYear());
		map.put("a", shortNamesOfDays[date.getDay()]);
		map.put("A", longNamesOfDays[date.getDay()]);
		map.put("HH", ((date.getHours() < 10) ? "0" : "") + date.getHours());
		map.put("MM", ((date.getMinutes() < 10) ? "0" : "") + date.getMinutes());
		map.put("SS", ((date.getSeconds() < 10) ? "0" : "") + date.getSeconds());
		
	
		var orginalFormat = format;
		var pos = 0;
		var part = null;
		var exit = false;
		while ((pos < orginalFormat.length) && (!exit)) {
			
			indexOfNextPart = format.indexOf(SEPARATOR);
			if (indexOfNextPart < 0) {
				dateAsString += format;
				exit = true;
			} else {
				pos += indexOfNextPart;
				
				dateAsString += format.substring(0, indexOfNextPart);
				format = format.substring(indexOfNextPart);
				
				nextPart = this.getNextPart(format);
				
				pos += nextPart.length + 2;
				format = format.substring(nextPart.length + 2);
				
				dateAsString += map.get(nextPart);
			}
		}
		
		return dateAsString;
	},
	
	/**
	 *	static helper function: returns the next part (%..%) in the format string.
	 *
	 *	@param format
	 *		the format string
	 *
	 *	@returns the next part
	 */
	getNextPart : function(format) {
		var nextPart = "";
		
		var firstPos = format.indexOf(SEPARATOR);
		var secondPos = 0;
		
		if (firstPos >= 0) {
			format = format.substring(firstPos + 1);
			secondPos = format.indexOf(SEPARATOR);
			
			if (secondPos >= 0) {
				nextPart = format.substring(0, secondPos);
			} else {
				alert("error: getNextPart(): didn't find belonging SEPARATOR (" + SEPARATOR + ") in \"" + format + "\"");
			}
		}
		
		return nextPart;
	}
};

/* PARENT - CHILD ################################################################################# */
function Parent() {
	this.parent = null;
	this.children = new ArrayList();
	
	
	/* getter and setter ========================================================================== */
	
	/**
	 * Returns the children.
	 * 
	 * @return the  children
	 */
	this.getChildren = function() {
		return this. children;
	}
	
	
	/**
	 * Sets newChildren to type.
	 * 
	 * @param newChildren
	 *            The new  children to set.
	 */
	this.setChildren = function(newChildren) {
		this. children = newChildren;
	}
	
	
	/**
	 * Returns the parent.
	 * 
	 * @return the  parent
	 */
	this.getParent = function() {
		return this. parent;
	}
	
	
	/**
	 * Sets newParent to type.
	 * 
	 * @param newParent
	 *            The new  parent to set.
	 */
	this.setParent = function(newParent) {
		this. parent = newParent;
	}
}

/* UTITLITY ####################################################################################### */
var Utility = {
	/**
	 * Removes all children recursively from a certain node.
	 * 
	 * @param node
	 * 		the node, that shall be clean out
	 */
	removeAllChildrenOf : function(node) {
		while(node.childNodes.length > 0) {
			var child = node.childNodes[0];
			if (child.childNodes.length > 0) {
				removeAllChildrenOf(child);
			}
			
			node.removeChild(child);
		}
	},
	
	getRandomNumber : function(max, min) {
		var number = 0;
		
		number = (max - min) * Math.random() + min;
		
		return number;
	}
	
}

/* CLOUDS ######################################################################################### */
function GroupOfClouds(max, min) {
	this.listOfClouds = new ArrayList();
	this.max = max;
	this.min = min;
	
	this.addCloud = function(cloud) {
		this.listOfClouds.add(cloud);
	}
	
	this.insertInto = function(elementName) {
		var element = $(elementName);
		
		for (var i = 0; i < this.listOfClouds.size(); i++) {
			var cloud = this.listOfClouds.get(i);
			
			if (i > 0) {
				element.appendChild(document.createTextNode(" "));
			}
			
			element.appendChild(cloud.getAsHTML(Utility.getRandomNumber(max, min)));
		}
	}
}

function Cloud(description, link) {
	this.description = description;
	this.link = link;
	
	this.getAsHTML = function(size) {
		var element;
		
		if (link != null) {
			element = new Element("a", {"style" : "font-size: " + size + "em;"}).update(this.description);
			element.href = link;	
		} else {
			element = new Element("span", {"style" : "font-size: " + size + "em;"}).update(this.description);	
		}
		
		return element;
	}
	
	/* getter and setter ========================================================================== */
	
	/**
	 * Returns the description.
	 * 
	 * @return the  description
	 */
	this.getDescription = function() {
		return this. description;
	}
	
	/**
	 * Sets newDescription to type.
	 * 
	 * @param newDescription
	 *            The new  description to set.
	 */
	this.setDescription = function(newDescription) {
		this. description = newDescription;
	}
	
	/**
	 * Returns the link.
	 * 
	 * @return the  link
	 */
	this.getLink = function() {
		return this. link;
	}
	
	/**
	 * Sets newLink to type.
	 * 
	 * @param newLink
	 *            The new  link to set.
	 */
	this.setLink = function(newLink) {
		this. link = newLink;
	}	
}


