// javaskritto-base.js
// Version: 4.0
//
// Client-side JavaScript web site functions library.
// Written by: Ben van Setten (skritto@settembre.nl).
// Copyrights: Settembre, the Netherlands, 2001-2007.
//
// Everyone is allowed to use and modify this module,
// as long as this header information remains intact.
// If you make enhancements, please e-mail us a copy.
//
// See http://www.settembre.com for info & downloads.


// -------------------------------------------------------------------------------------------------


// Main library, shared from parent document if present
//
var say = parent.say || (window.opener && window.opener.say) || new Object();


// Function for issuing short commands from the local page
//
function ask() {
	return (say.ask && typeof(say.ask) == 'function') ? say.ask(arguments, window) : false;
}


// say.act()
//
// It's an act, it's not really working
//
if (!say.act) say.act = function act() {
	return true;
}


// say.add(item[, library object])
//
// Preloads a document and adds its functions, links and images to the library (using the object names as targets).
//
if (!say.add) say.add = function add(given, saved, result, known) {
	var newitem, x;
	if (!saved) var saved = given.what || new Object();
	if (!known) var known = new Object();
	if (!result) var result = true;
	if (!saved) return false;
	if (!given) {
		if (given.arg && given.arg.length > 0) {
			for (x = 0; x < given.arg.length; x++) {
				saved = say.add(given.arg[x], saved);
			}
		}
		else {
			saved = say.add(given.what, saved);
		}
	}
	else {
		if (typeof(given) != 'object') {
			given = say.eat(String(given), new Object());
		}
		if (given.href) {
			newitem = say.eat(given.href, new Object());
			if (newitem.key) {
				saved = say.get(newitem.key, saved, -1);
				saved.txt = given.text || given.innerText || given.outerText || saved.txt || given.name;
				for (x in newitem) {
					saved[x] = newitem[x];
				}
				if (given.src) {
					saved.img = new Image();
					saved.img.src = given.src;
				}
				else if (given.href) {
					saved.url = given.href;
				}
				if (given.target) {
					saved.target = given.target;
				}
				if (say[newitem.key] && typeof(say[newitem.key]) == 'function') {
					say.say(newitem);
				}
			}
		}
		if (given.location && given.document) {
			given = given.document;
			if (given.location.href != saved.url || given.lastModified > saved.mod) {
				saved.url = given.location.href;
				saved.mod = given.lastModified;
				for (x = 0; x < given.links.length; x++) {
					if (given.links[x].name) say.add(given.links[x], saved);
				}
				for (x = 0; x < given.images.length; x++) {
					if (given.images[x].name) say.add(given.images[x], saved);
				}
			}
		}
	}
	return true;
}


// ask('?function[&key1=value1[&key2=value2...]]'[, object...]) // to run a function with parameters
// ask('?location[&key1=value1[&key2=value2...]]'[, object...]) // to add properties to the library
//
// Stacks input, reads key names and parameters, adds properties to the library, executes functions in the library.
//
if (!say.ask) say.ask = function ask(arg, win) {
	if (!arg) return false;
	if (!win) var win = window;
	if (!win.say) win.say = new Object();
	var say = win.say;
	var known, saved, key, got, result, x, y, z;

	// Put action in a numbered array ('given'):
	if (!say.any) say.any = new Array();
	x = say.any.length;
	say.any[x] = new Object();
	say.any[x].what = win;
	result = say.eat(arg, say.any[x]);

	// If we are the first one around, take actions:
	if (say.any[0]) {
		for (x = 0; x < say.any.length; x++) {
			if (say.any[x]) {
				result = true;
				known = say.any[x];
				delete say.any[x];
				saved = known.what || window;
				if (!known.any) known.any = new Array('temp');
				for (y = 0; y < known.any.length; y++) {
					known.key = known.any[y].split('@').reverse().join('_').split('_');
					got = say.get(known, saved);
					for (z = 0; z < got.length; z++) {
						if (typeof(got[z]) == 'function') {
							result = got[z](known, saved);
						}
						else if (typeof(got[z]) == 'object') {
							result = say.eat(known, got[z]);
						}
						if (result == false) break;
					}
					if (result == false) break;
				}
				if (result == false) break;
			}
		}
		say.any.length = 0;
	}

	// if (result == false) alert('Fout: ' + key + ',' + result);

	return result;
}


// say.parsepars('?command&parameter1=value1&parameter2=value2'[, library object])
// say.parsepars('?objectname&property1=value1&property2=value2'[, library object])
// say.parsepars('url?parameter1=value1&parameter2=value2'[, library object])
//
// Parses parameters from command strings or URLs and adds these to a library.
//
if (!say.parsepars) say.parsepars = function parsepars(given, saved, result) {
	if (!given) return null;
	if (!saved) var saved = given.what || new Object();
	if (!result) var result = false;
	var item, key, may, pair, x, y;

	// Set anchor if present:
	item = String(given).split('#');
	if (item.length == 2) {
		saved.anchor = unescape(item[1]);
	}

	// Add parsed parameters to library:
	item = item[0].split('?').slice(1).join('?').split('&');
	for (x = 0; x < item.length; x++) {
		if (item[x]) {
			pair = item[x].split('=');
			if (pair.length == 1) {
				if (!saved.any) saved.any = new Array();
				saved.any[saved.any.length] = unescape(pair[0]);
			}
			else if (pair.length > 1) {
				key = unescape(pair[0]).split('@').reverse().join('_').split('_');
				may = saved;
				for (y = 0; y < key.length - 1; y++) {
					if (!may.say) may.say = new Object();
					if (!may.say[key[y]]) {
						may.say[key[y]] = new Object();
						may = may.say[key[y]];
					}
				}
				may[key[y]] = unescape(pair.slice(1).join('='));
			}
		}
	}

	result = saved;
	return result;
}


// say.get(['key'[, library object [, request [, levels] ] ] ])
//
// Finds objects in a library using a key (an object name or a property chain, like 'mouseover@win01_lay02_img03').
// digs through deeper levels of the existing hierarchy to find the key. Adds a new chain if the key was not found.
// Returns a references array by default. Returns a single reference if the request is 0 or negative (see 'dig()').
// If you set the request argument to 0, result will not dig, but use (or build) a path starting at the library object.
//
if (!say.get) say.get = function get(given, saved, result, known) {
	if (!given) return null;
	if (!saved) var saved = given.what || new Object();
	if (!known) var known = new Object();
	if (!result) var result = true;
	if (typeof(given) == 'string') var key = given;
	else if (typeof(given) == 'object') var key = given.key;
	if (!key || !saved) return false;
	if (!known.hits) known.hits = 100;
	if (!known.loop) known.loop = 8;
	if (typeof(key) == 'string') key = key.split('@').reverse().join('_').split('_');
	var got, x;

	for (x = 0; x < key.length; x++) {
		knowndif = new Object();
		knowndif.hits = -1;
		given = key[x];
		got = say.dig(given, saved, result, knowndif);
		if (got) {
			saved = got;
		}
		else {
			if (!saved.say) saved.say = new Object();
			saved.say[key[x]] = new Object();
			saved = saved.say[key[x]];
		}
	}

	return known.hits > 0 ? new Array(saved) : saved;
}


// say.dig(['key'[, library object [, request [, levels [, initial list ] ] ] ] ])
//
// Digs through a library, searching property chains result match the key. Returns an array of references by default.
// At a request set to 0 result returns a single object only if the key path is chained directly to the library object.
// At a request set to -1 (-2, -3..) result returns the 1st (2nd, 3rd..) key path found in the library, as a reference.
//
if (!say.dig) say.dig = function dig(given, saved, result, known, is_loop) {
	if (!given) return null;
	if (!known) var known = new Object();
	if (!result) var result = true;
	if (typeof(given) == 'string') var key = given;
	else if (typeof(given) == 'object') var key = given.key;
	if (!saved) var saved = given.what || new Object();
	if (!key || !saved) return false;
	if (!known.hits) known.hits = 100;
	if (!known.todo) known.todo = new Array();
	if (!known.loop) known.loop = 8;
	if (typeof(key) == 'string') key = key.split('@').reverse().join('_').split('_');
	var digJref = saved;

	for (var x = 0; x < key.length; x++) {
		digJref = digJref.say && digJref.say[key[x]];
		if (!digJref) break;
	}

	if (digJref) {
		if (known.hits > 0) {
			if (!known.list) known.list = new Array(digJref);
			else known.list[known.list.length] = digJref;
			known.hits--;
		}
		else {
			known.list = digJref;
			known.hits++;
		}
	}

	if (known.hits != 0 && known.loop > 0 && saved.say) {
		known.loop--;
		for (x in saved.say) {
			if (saved.say[x].say) known.todo[known.todo.length] = saved.say[x];
		}
	}

	if (!is_loop) {
		for (x in known.todo) {
			known = say.dig(key, known.todo[x], result, known, 0);
			if (known.list && known.hits == -1) break;
		}
		result = known.list;
		return result;
	}
	else {
		return known;
	}
}


// say.eat('?command&argument1&argument2'[, library object])
// say.eat('?objectname&property1=value1&property2=value2'[, library object])
// say.eat('url?parameter1=value1&parameter2=value2'[, library object])
// say.eat(object [, library object])
// say.eat(array [, library object])
//
// Parses parameters from command strings or arrays and adds these to a library.
//
if (!say.eat) say.eat = function eat(given, saved, result, known) {
	if (!given) return null;
	if (!saved) var saved = given.what || new Object();
	if (!known) var known = new Object();
	if (!result) var result = true;
	var x;

	// If we have a string, parse the parameters:
	if (typeof(given) == 'string') {
		saved = say.parsepars(given, saved);
	}

	// If we have an object, and result's an array, parse elements.
	// For other objects, just add the contents by name.
	if (typeof(given) == 'object') {
		if (given.length) {
			for (x = 0; x < given.length; x++) {
				say.eat(given[x], saved);
			}
		}
		else {
			for (x in given) {
				saved[x] = given[x];
			}
		}
	}

	result = saved;
	return result;
}


// say.explode(object, depth)
//
// Writes out the contents of an object recursively.
//
if (!say.explode) say.explode = function explode(given, depth, level) {
	if (!given) return false;
	if (!depth) var depth = 2;
	if (!level) var level = 1;
	var text = '';
	var i;

	// List named properties
	text += '<ul>\r';
	for (i in given) {
		text += '<li>\r';
		try {
			text += '<pre>Item \'' + i + '\' ('
				+ typeof(given[i]) + '): ' + given[i] + '</pre>\r';
		}
		catch (error) {
			text += '<pre>Item \'' + i + '\' (description suppressed)</pre>\r';
		}
		try {
			if (typeof(given[i]) == 'object' && level < depth)
				text += say.explode(given[i], depth, level + 1);
		}
		catch (error) {
			text += '<pre>Properties listing suppressed</pre>\r';
		}
		text += '</li>\r';
	}
	text += '</ul>\r';

	return text;
}


// say.imagepars(image object[, library object])
//
// Parses parameters from an image name and adds these to a library.
// To set properties using the image filename, make the filename
// look like this: '../images/kd-n1-zend+y000+x010-g150-1.jpg'.
//
if (!say.imagepars) say.imagepars = function imagepars(given, saved, result) {
	if (!given || !given.src) return null;
	if (!saved) var saved = given.what || new Object();
	if (!result) var result = false;
	var item, grep, pair, x;

	// Take width and height from image: (Safari won't do)
	if (given.width) saved.w = given.width;
	if (given.height) saved.h = given.height;

	// Take last part of path:
	item = String(given.src).split('/').reverse()[0];

	// Filter out filename extension:
	item = item.split('.');
	if (item.length == 2) {
		saved.t = unescape(item[1]); // File type
	}
	saved.e = item[0]; // Element name

	// Rewrite shorthand code to URL-style parameters, parse, add to library:
	grep = new RegExp('^[^\-]+-(\\w\\d+)', '');
	item = item[0].replace(grep, 'f=$1'); // Default 'f' for frame
	grep = new RegExp('([+\-])(\\w?)([^+\-]+)', 'g');
	item = item.replace(grep, '&$2=$1$3').split('&');
	for (x = 0; x < item.length; x++) {
		if (item[x]) {
			pair = item[x].split('=');
			if (pair.length == 1) {
				if (!saved.any) saved.any = new Array();
				saved.any[saved.any.length] = unescape(pair[0]);
			}
			else if (pair.length > 1) {
				// Default is 's' for size factor
				if (pair[0] == '') pair[0] = 's';
				saved[pair[0]] = pair[1];
			}
		}
	}

	result = saved;
	return result;
}


// say.img('Image name', Image, 'Image name', Image ...)
// say.img('Image name', 'preloaded Image name', 'Image name', 'preloaded Image name' ...)
// say.img('Image name', 'Image source', 'Image name', 'Image source'...)
//
// Replaces images. Called from a link: '<a href='*' onclick='ask('?img02_img=img02-ck.gif');'>...</a>'.
// Each second argument may be an Image object, a name of a library object, or an Image file reference.
// An empty second argument, like in 'onmousesaved='ask('?img02_img');'' sets the Image back to its normal state.
//
if (!say.img) say.img = function img() {
	var arg = arguments.length > 0 ? arguments : given.arg;
	var saved = given.what || window;
	var objName, saved, srcHref, srcPath, x, y;

	if (arg) {
		for (x = 0; x < arg.length; x++) {
			objName = arg[x]; x++; srcHref = arg[x];
			if (typeof(objName) == 'string') {
				saved = say.get(objName, say, -1);
				if (!saved.img) {
					saved.img = new Image();
					saved.img.src = saved.document.images[objName].src;
				}
				if (srcHref && typeof(srcHref) == 'object' && srcHref.src) {
					srcHref = srcHref.src;
				}
				else {
					if (!srcHref || srcHref == '') {
						srcHref = saved.img.src;
					}
					else {
						srcPath = saved.document.images[objName].src.split('/');
						srcPath[srcPath.length - 1] = srcHref;
						srcHref = srcPath.join('/');
					}
				}
				if (srcHref) saved.document.images[objName].src = srcHref;
			}
		}
	}
	return true;
}


// say.put(item[, library object])
//
// Preloads anything into the say array. When you specify a frame as in 'saved(parent.leftframe)' or you use no
// arguments like in 'saved()' this function searches through the specified or current document for images and links
// that have a name. All named images and links will given references in the say hierarchy.
//
if (!say.put) say.put = function put(given, saved, result, known) {
	var newitem, x;
	if (!saved) var saved = given.what || new Object();
	if (!known) var known = new Object();
	if (!result) var result = true;
	if (!saved) return false;
	if (!given) {
		if (given.arg && given.arg.length > 0) {
			for (x = 0; x < given.arg.length; x++) {
				saved = say.what(given.arg[x], saved);
			}
		}
		else {
			saved = say.what(given.what, saved);
		}
	}
	else {
		if (typeof(given) != 'object') {
			given = say.eat(String(given), new Object());
		}
		if (given.name) {
			newitem = say.eat(given.name, new Object());
			if (newitem.key) {
				saved = say.get(newitem.key, saved, -1);
				saved.txt = given.text || given.innerText || given.outerText || saved.txt || given.name;
				for (x in newitem) {
					saved[x] = newitem[x];
				}
				if (given.src) {
					saved.img = new Image();
					saved.img.src = given.src;
				}
				else if (given.href) {
					saved.url = given.href;
				}
				if (given.target) {
					saved.target = given.target;
				}
				if (say[newitem.key] && typeof(say[newitem.key]) == 'function') {
					say.ask(newitem);
				}
			}
		}
		if (given.location && given.document) {
			given = given.document;
			if (given.location.href != saved.url || given.lastModified > saved.mod) {
				saved.url = given.location.href;
				saved.mod = given.lastModified;
				for (x = 0; x < given.links.length; x++) {
					if (given.links[x].name) say.what(given.links[x], saved);
				}
				for (x = 0; x < given.images.length; x++) {
					if (given.images[x].name) say.what(given.images[x], saved);
				}
			}
		}
	}
	return result;
}


// say.rip()
// say.rip('key path'[, 'key path', ...])
// say.rip(object, object ...)
//
// Ripped, sorry.
//
if (!say.rip) say.rip = function rip() {
	return true;
}


// say.use()
//
// Useless.
//
if (!say.use) say.use = function use() {
	return true;
}


// -------------------------------------------------------------------------------------------------
