// 2007-08-10

/*

    fss (Free Software Signature)
    version 1.0 Copyright (C) 2006-2007 Tagata Akira

    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., 51 Franklin St, Fifth Floor, Boston, MA
    02110-1301 USA

*/

// update history
// 1.0g: 2006-11-26 bug fix
// 1.0h: 2006-12-07 wild card for searchClass()
// 1.0i: 2006-12-07 parseClass()
// 1.0j: 2007-02-04 setStyleSheetData(), makeAnimated()
// 1.0k: 2007-02-05 concatenateTextNode(), concatenateTextNodeById(), removeTextNode()
// 1.0k2: 2007-03-07 Safari requires \s for spaces
// 1.0k3: 2007-03-14 Bug fix
// 1.0l: 2007-02-18 innerSize(),scrollSize
// 1.0m: 2007-02-25 _fss.prototype.makeAnimated has been moved into _vadi.js
// 1.0m: 2007-02-25 findContainingBlockInInlineStyle(),elementXY()
// 1.0n: 2007-03-02 _fss.prototype.xxxxx -> _fss.xxxxx
// 1.0o: 2007-03-18 _fss.prototype..*Cookie -> _fss..*Cookie
// 1.0p: 2007-04-08 _fss.prototype.elementIdentified -> _fss.elementIdentified
// 1.0q: 2007-04-08 added some functions
// 1.0r: 2007-04-09 element search functions
// 1.0s: 2007-04-19 changed copyObject()
// 1.0t: 2007-04-19 changed mergeObject()
// 1.0u: 2007-05-21 added _fss.tag(), _fss.bePatient(), _fss.patchClass()
// 1.0v: 2007-07-17 merged core
// 1.0w: 2007-07-23 changed _fss.prototype._installDirectory to _fss.installUriPath
// 1.0x: 2007-08-02 divided into core and the others


// 1.1a: 2007-08-09 new version number 1.1

// *** obsolete ***
_fss.prototype._log = function () { }; // dummy

_fss.prototype._fss = _fss;

_fss.prototype._fss('fss','Free Software Signature','1.1a','2006-2007 Tagata Akira','http://www.tagata.org/software/');

function _fss(name,desc,ver,copy,web,contact) {

	_fssObj.prototype = {
		name:	'n/a',
		desc:	'n/a',
		ver:	'n/a',
		copy:	'n/a',
		web:	'n/a',
		contact:'n/a'
	}
	function _fssObj() { }

	this._fssObj = new _fssObj;
	if (name)
		this._fssObj.name = name;
	if (desc)
		this._fssObj.desc = desc;
	if (ver)
		this._fssObj.ver = ver;
	if (copy)
		this._fssObj.copy = copy;
	if (web)
		this._fssObj.web = web;
	if (contact)
		this._fssObj.contact = contact;

}

_fss.prototype._fssName = function () { return this._fssObj.name }
_fss.prototype._fssDesc = function () { return this._fssObj.desc }
_fss.prototype._fssVer = function () { return this._fssObj.ver }
_fss.prototype._fssCopy = function () { return this._fssObj.copy }
_fss.prototype._fssWeb = function () { return this._fssObj.web }
_fss.prototype._fssContact = function () { return this._fssObj.contact }

_fss.prototype._fssHtml = '_fss.html';
_fss.prototype._fssUrlStyle = 'padding-left: 1ex; font-size: smaller;';
_fss.prototype._fssUrlMargin = '0 0 0 1ex';
_fss.prototype._fssUrlFont = 'smaller serif';
_fss.prototype._fssElementIdToBeInserted = 'fss-siglink-box';
_fss.prototype._fssTagNameToBeInserted = 'div';
_fss.prototype._fssInsertedSig = {};
_fss.prototype._fssInsertUrl = function (eltId) {
	if ('name' in this._fssObj) {
		var elementId = this._fssElementIdToBeInserted;
		if (eltId) {
			elementId = eltId;
		}
//		var elementToBeInserted = this.elementIdentified(elementId,this._fssTagNameToBeInserted);
		var elementToBeInserted = _fss.elementIdentified(elementId,this._fssTagNameToBeInserted);
// 1.0k3: 2007-03-14 Bug fix
		if (elementToBeInserted._fssGenerated && !elementToBeInserted._fssGeneratedEver) {
			document.body.appendChild(elementToBeInserted);
		}

		if (this._fssObj['name'] in _fss.prototype._fssInsertedSig)
			return;
		_fss.prototype._fssInsertedSig[this._fssObj['name']] = true;

		// insert signature of myself only the first ime
		_fss.prototype._fssInsertUrl();

		var url = this._fssUriElement(this._fssObj);
//		url.setAttribute('style',this._fssUrlStyle);
		url.style.margin = this._fssUrlMargin;
		url.style.font = this._fssUrlFont;
		elementToBeInserted.appendChild(url);
	}
}
_fss.prototype._fssUriElement = function (fssObj) {
	ret = document.createElement('a');
	ret.appendChild(document.createTextNode(fssObj.name));
	function objectToQuery(o) {
		var query = '';
		for (var p in o) {
			if (query != '')
				query += '&amp;';
			query += p+'='+o[p];
		}
		return query;
	}
//	var href = encodeURI(this._prependInstallDirectory(this._fssHtml)+'?'+objectToQuery(fssObj));
	var href = encodeURI(_fss.installUriPath+this._fssHtml+'?'+objectToQuery(fssObj));
	var title = 'what is '+fssObj.name+'?';
	ret.setAttribute('href',href);
	ret.setAttribute('title',title);
	return ret;
}
//-fxref-// _fss: _fss.elementIdentified

////////////////////////////////////////////////////////////////
// core start
////////////////////////////////////////////////////////////////

_fss.isLocal = /^file:/i.test(document.URL);
//-fxref-// _fss.isLocal:

_fss.XMLHttp = function() {

	if (window.XMLHttpRequest) { // Mozilla, Safari, ...
		this.req = new window.XMLHttpRequest();
		if (this.req.overrideMimeType) {
			this.req.overrideMimeType('text/xml');
		}
	} 
	else if (window.ActiveXObject) { // IE

		for (var i = 0; i < this.ieArg.length; i++) {
			try {
				this.req = new window.ActiveXObject(this.ieArg[i]);
			}
			catch (e) {
				this.e = e;
				continue;
			}
			break;
		}
	}
}
//-fxref-// _fss.XMLHttp:

_fss.XMLHttp.prototype.ieArg = [
	"Msxml2.XMLHTTP",
	"Msxml3.XMLHTTP",
	"Microsoft.XMLHTTP"
];

_fss.createXMLHTTPObject = function () { return new _fss.XMLHttp; };
//-fxref-// _fss.createXMLHTTPObject: _fss.XMLHttp


_fss.XMLHttp.prototype.getAsyn = function(url,callback) {
if (0) { // this does not work
	if (!this.req) return;

	this.req.open('GET',url,true); // asynchronous
	this.req.setRequestHeader('User-Agent','XMLHTTP/1.0');
xxx = this.req;
	this.req.onreadystatechange = function (e) {
//alert('this.readyState:'+this.readyState);
//		if (this.readyState != 4) return;
//		if (this.status != 200 && this.status != 304) {
//			alert('HTTP error ' + this.status);
//			return;
//		}
//		callback(this);
//alert('xxx.readyState:'+xxx.readyState+', xxx.status:'+xxx.status);
		if (xxx.readyState != 4) return;
		if (xxx.status != 200 && xxx.status != 304) {
			alert('HTTP error ' + xxx.status);
			return;
		}
		callback(xxx);
	}
	if (this.req.readyState == 4) return;
	this.req.send(null);
}
}

_fss.XMLHttp.prototype.getSyn = function(url) {
	if (!this.req) return;
//alert('url:'+url);
	try {
		this.req.open('GET', url, false); // synchronous
		this.req.send(null);

		if (this.req.status == 0 || this.req.status == 200) {
		// Safari returns 200 on local
//		var statusCode = _fss.isLocal? 0: 200;
//		if (this.req.status == statusCode) {
//			alert('status:'+this.req.status); //// temp ////
			return this.req.responseText;
		}
		else {
//			alert('status:'+this.req.status); //// temp ////
			return null;
		}
	}
	catch (e) {
		this.e = e;
//		alert('status:'+this.req.status+', e:'+e); //// temp ////
		return null;
	}
}

_fss.XMLHttp.prototype.postAsyn = function(url,data,callback) {
	if (!this.req) return;

	this.req.open('POST',url,true);
	this.req.setRequestHeader('User-Agent','XMLHTTP/1.0');
	this.req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
	this.req.onreadystatechange = function () {
		if (this.req.readyState != 4) return;
		if (this.req.status != 200 && this.req.status != 304) {
//			alert('HTTP error ' + this.req.status);
			return;
		}
		callback(this.req);
	}
	if (this.req.readyState == 4) return;
	this.req.send(data);
}

_fss.XMLHttp.prototype.postSyn = function(url,data) {
}

////////////////////////////////////////////////////////////////
_fss.libol = function (libs) {
// lib on line
	var ret = new Array;
//	var ret = new Object;
	if (libs instanceof Array) {
		for (var i = 0; i < libs.length; i++) {
			var xho = new _fss.XMLHttp;
			ret[i] = xho.getSyn(libs[i]);
		}
//		ret.length = libs.length;
	}
	else {
		var xho = new _fss.XMLHttp;
		ret[0] = xho.getSyn(libs);
//		ret.length = 0;
	}
	return ret;
};
//-fxref-// _fss.libol: _fss.XMLHttp

_fss.loadpre = function (targets) {
// load prerequisites of the target

	function getRequiredFilenames(target,files) {
		var colonIndex = target.indexOf(':');
		var lastSlashIndex = target.lastIndexOf('/');

		var searchPath; // array
		var filename; // string
		if (colonIndex != -1) {
			// absolute
			if (colonIndex < target.indexOf('/')) {
				searchPath = [target.substring(0,lastSlashIndex+1)];
				filename = target.substring(lastSlashIndex+1);
			}
			else {
//				continue; // error
				return;
			}
		}
		else if (lastSlashIndex == -1) {
			// relative and without slashes
			searchPath = [_fss.baseDir, _fss.installUriPath];
			filename = target;
		}
		else {
			// relatvie and with slash
			searchPath = [_fss.baseDir+target.substring(0,lastSlashIndex+1)];
			filename = target.substring(lastSlashIndex+1);
		}


		// _fss.fxref.* maintenance

		var fxrFilename = filename.replace(/\.[^.]+$/,_fss.fxref.suffix);
		for (j = 0; j < searchPath.length; j++) {
			var fileAbsolute = searchPath[j]+filename;
			if (fileAbsolute in  _fss.fxref.funcname) { // found
//alert(fileAbsolute+' found');
				break;
			}
			else { // not found
				var fxrAbsolute = searchPath[j]+fxrFilename;
				var xho = new _fss.XMLHttp;
				var text;
				if (text =  xho.getSyn(fxrAbsolute)) {
//					_fss.analyzeFxref(text.replace(/^/gm,fileAbsolute+': '),'');
//alert('searchPath['+j+']:'+searchPath[j]+', text:'+text);
					_fss.analyzeFxref(text,searchPath[j]);
					break;
				}
				else {
//alert(fxrAbsolute+' not found');
				}
			}
		}


		if (j < searchPath.length && fileAbsolute in _fss.fxref.funcname) {
			for (var func in _fss.fxref.funcname[fileAbsolute]) {
				for (var ref in _fss.fxref.funcname[fileAbsolute][func]) {
					if (ref in _fss.fxref.filename) {
						// filename of function ref is known
						if (_fss.fxref.filename[ref] == fileAbsolute || _fss.fxref.filename[ref] in files) {
							// bypass
//alert(_fss.fxref.filename[ref]+' already processed');
						}
						else {
//alert('getRequiredFilenames() '+_fss.fxref.filename[ref]);
//							files[_fss.fxref.filename[ref]]  = true;
							getRequiredFilenames(_fss.fxref.filename[ref],files);
						}
					}
					else {
//alert('give up '+ref);
						// give up...
					}
				}
			}
			files[fileAbsolute] = true;
		}
		else {  // not found fxrAbsolute
//alert('Not found '+fxrAbsolute);
			if (searchPath.length == 1)
				files[searchPath[0]+filename] = true;
			else 
				files[target] = true;
		}
	} // end of getRequiredFilenames()



	var targetFiles =
		(targets instanceof Array)? targets: targets.split(/\s+/);
	var files = new Object;
	for (var i = 0; i < targetFiles.length; i++) {
		if (!targetFiles[i])
			continue;
		getRequiredFilenames(targetFiles[i],files);
	}
	var fnarray = new Array;
	for (var fn in files) {
		if (fn == _fss.installUriPath+'_fss.core.js') {
			// bypass myself
		}
		else {
//alert('fn:'+fn);
			fnarray.push(fn);
		}
	}
//alert('targets:'+targets+', fnarray.length:'+fnarray.length);
	return _fss.libol(fnarray);
}
//-fxref-// _fss.loadpre: _fss.libol

////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////

_fss.substitutionPattern = function () {
	this.patternObject = new Object;
	for (var i = 0; i < arguments.length; i += 2) {
		this.patternObject[arguments[i]] =
			(i == arguments.length - 1)? '': arguments[i+1];
	}
	this.substitute = function(str) {
		if (!this.re) {
			var pattern = '(';
			for (var from in this.patternObject) {
				if (pattern != '(')
					pattern += '|';
				pattern += from;
			}
			pattern += ')';
			this.re = new RegExp(pattern,'g');
		}
		var patternObject = this.patternObject;
		return str.replace(this.re,function(from) {
			return (from in patternObject)? patternObject[from]: '';
		});
	}
}
//-fxref-// _fss.substitutionPattern:

_fss.standardEscapePattern = new _fss.substitutionPattern(
		'<','&lt;',
		'>', '&gt;',
		'&', '&amp;',
		'"', '&quot;'
		);
//-fxref-// _fss.standardEscapePattern: _fss.substitutionPattern

_fss.getBaseUri = function (w) {
	var win = w || window;

	var baseUri;
	var bases = win.document.getElementsByTagName('base');

	for (var i = bases.length - 1; 0 <= i; i--) {
		// get the last href from base elements
		if (bases[i].href) {
			baseUri = bases[i].href;
			break;
		}
	}
	if (baseUri == undefined && win.document && win.document.URL) {
		// get default uri from win.document.URL
		baseUri = win.document.URL;
	}
	return baseUri; // maybe undefined
};
//-fxref-// _fss.getBaseUri:

_fss.getJavaScriptUris = function (w) {
	var win = w || window;
	var scripts = win.document.getElementsByTagName('script');
	var uris = new Array;
	for (var i = 0; i < scripts.length; i++) {
		if (scripts[i].src && scripts[i].type == 'text/javascript') {
			uris.push(scripts[i].src);
		}
	}
	return uris;
};
//-fxref-// _fss.getJavaScriptUris:
//var testCount=0;
_fss.analyzeFxref = function (fxrefText,baseDir) {
	var match;
//	while (match = /^([_a-z][_a-z0-9\.]*):\s+([_a-z][_a-z0-9\.]*):(\s+[_a-z][_a-z0-9\.]*)*$/gim.exec(fxrefText)) {
//	while (match = /^([_a-z][_a-z0-9\.]*):\s+([_a-z][_a-z0-9\.]*):((\s+[_a-z][_a-z0-9\.]*)*)$/gim.exec(fxrefText)) {
	var oneLineRe = /^([_a-z][\w\.]*):\s+([_a-z][\w\.]*):((\s+[_a-z][\w\.]*)*)$/gm;
	while (match = oneLineRe.exec(fxrefText)) {
//if (testCount++ < 5) { alert('oneLineRe.lastIndex:'+oneLineRe.lastIndex+', match[1]:'+match[1]); }
		var filename = baseDir+match[1];
		var funcname = match[2];
		_fss.fxref.filename[funcname] = filename;
		if (match[3]) {
			if (!(filename in _fss.fxref.funcname))
				_fss.fxref.funcname[filename] = new Object;
			if (!(funcname in _fss.fxref.funcname[filename]))
				_fss.fxref.funcname[filename][funcname] = new Object;
			var refnames = match[3].split(/\s+/);
			for (var i = 0; i < refnames.length; i++) {
//if (funcname == '_fss.bePatient') alert('refnames['+i+']: '+refnames[i]);
				if (refnames[i] != '') {
					_fss.fxref.funcname[filename][funcname][refnames[i]] = true;
				}
			}
		}
	}
}
//-fxref-// _fss.analyzeFxref:

_fss.mandatory = function() {
	function dirname(uri) {
		var lastIndex = uri.lastIndexOf('/');
		if (lastIndex != -1) {
			return uri.substring(0,lastIndex+1);
		}
		return '';
	}

	_fss.gpl = new Object;

	var pathObject = new Object;
	var javaScriptFullPath;
	var path;

	// base when src is relative
	_fss.baseDir = dirname(_fss.getBaseUri());

	// get all javaScript file names when starting up
	var startUpUris = _fss.getJavaScriptUris();
	for (var i = 0; i < startUpUris.length; i++) {
		// if no scheme and relative (RFC1630)
		if (startUpUris[i].indexOf(':') == -1 && startUpUris[i].charAt(0) != '/') {
			// prepend base when without scheme and relative
			javaScriptFullPath = _fss.baseDir+startUpUris[i];
		}
		else { // absolute URI assumed (has scheme or start with '/')
			javaScriptFullPath = startUpUris[i];
		}
		path = dirname(javaScriptFullPath);
		if (path != '')
			pathObject[path] = true;
	}

	for (path in pathObject) {
//alert('path:'+path);
		// path surely ends with '/'
		_fss.gpl.xho = new _fss.XMLHttp;
		if (_fss.gpl.text = _fss.gpl.xho.getSyn(path+'gpl.txt')) {
			_fss.installUriPath = path;
			break;
		}
	}
	if (_fss.gpl.text) {
//alert(_fss.installUriPath);
		_fss.gpl.textEscaped = _fss.standardEscapePattern.substitute(_fss.gpl.text);

		// _xref
		_fss.fxref = new Object;
		_fss.fxref.filename = new Object;
		_fss.fxref.funcname = new Object;
		_fss.fxref.suffix = '.fxr';
		_fss.fxref.fxref = '_fxref';
		_fss.fxref.xho = new _fss.XMLHttp;
		if (_fss.fxref.text =  _fss.fxref.xho.getSyn(_fss.installUriPath+_fss.fxref.fxref)) {

			_fss.analyzeFxref(_fss.fxref.text,_fss.installUriPath);
		}
	}

	return _fss.gpl.text? true: false;
}
//-fxref-// _fss.mandatory: _fss.getBaseUri _fss.getJavaScriptUris
//-fxref-// _fss.installUriPath:
//-fxref-// _fss.baseDir:
//-fxref-// _fss.gpl:
//-fxref-// _fss.gpl.text: _fss.XMLHttp
//-fxref-// _fss.gpl.textEscaped: _fss.standardEscapePattern

if (!_fss.mandatory())
	alert(_fss.gpl.xho.e+'\nInstallation incompleted.');
//else {
////	alert(_fss.fxref.text);
////	var funcname;
//	var msg = '';
////	for (var funcname in _fss.fxref.filename) {
////		msg += funcname+' in '+_fss.fxref.filename[funcname]+'\n';
////	}
////	msg += '\n';
//	for (var filename in _fss.fxref.funcname) {
//		msg += 'In '+filename+'\n';
//		for (var func in _fss.fxref.funcname[filename]) {
//			msg += func + ' defined; reffers:';
//			for (var ref in _fss.fxref.funcname[filename][func]) {
//				msg += ' '+ref;
//			}
//			msg += '\n';
//		}
//	}
//	alert(msg);
//}

////////////////////////////////////////////////////////////////
// core end
////////////////////////////////////////////////////////////////

