//--------------------- about this script -------------------------
DCMeta.prototype.meta = {
"@prefix": "<http://purl.org/net/ns/doas#>",
"@about": "<http://www.kanzaki.com/docs/sw/dc.js>", a: ":Javascript",
 title: "Medatada generator",
 shortdesc: "Generates Dublin Core metadata with HTML form .",
 created: "2004-10-06", release: {revision: "1.0.2", created: "2005-07-15"},
 author: {name: "KANZAKI, Masahide", homepage: "<http://www.kanzaki.com/>"},
 license: "<http://creativecommons.org/licenses/GPL/2.0/>",
 dependencies: "/parts/std.js for ge.* object"};
//-----------------------------------------------------------------

// instanciate dc class
var dc = new DCMeta();
// constants
var TAB = String.fromCharCode(9), SEP = String.fromCharCode(17);

/**
 * DCMeta class (object) constructor.
 */
function DCMeta(){
	this.pfxCount = [];
	this.nsUris = [];
	this.msg = {};
	this.vocab = {};
	this.xtitle, this.nodeElt, this.escEnt;
	this.lang = ge.docLang;
	this.aBuri, this.lenBuriArray;
	this.i = {'rdf': 0, 'xhtml': 1, 'pfx': 0, 'lname': 1, 'uriref': 1};
	this.dcdef = {Language:"ja", Format:"text/html", Type:"dct:Text"};
}

/**
 * Initializes input form and some variables. Also restores fields
 * which were deleted on leaving the form document.
 */
DCMeta.prototype.initForm = function(){
	this.fmeta = document.getElementById("metadata");
	this.savef = document.getElementById("save-form").saver;
	var uritds, q;
	var uritr = document.getElementById('nsuri-tb').getElementsByTagName('tr');
	for(var i=0;i<uritr.length;i++){
		uritds = uritr.item(i).getElementsByTagName('td');
		this.nsUris[uritds.item(1).firstChild.data] = uritds.item(2).firstChild.data;
		this.pfxCount[uritds.item(1).firstChild.data] = 0;
	}
	this.pfxCount['rdf'] = 1;
	if(location.search.substring(0,3)=='?u='){
		q = location.search.substring(3).match(/(.*?)&xh=(.*)/);
		//alert(RegExp.$1+','+RegExp.$2);
		this.parseHtml(unescape(RegExp.$2),unescape(RegExp.$1));
	}else{
		if(this.fmeta.fMmbox.value) this.showMboxfld();
		if(this.savef.value) document.getElementById('rtrvBtn').style.display = 'inline';
	}
}

//--------------- metadata generator functions --------------------

/**
 * Generates RDF/XML from the form data.
 * @access	public
 */
DCMeta.prototype.genRDF = function(){
	var metadata = new Array(2);
	this.nodeElt = "rdf:Description";
	this.escEnt = this.fmeta.escEntity.checked;

	metadata = this.genMetadata(this.fmeta);

	document.getElementById("rdf-form").RDF.value = 
		"<rdf:RDF\n" + this.genNSdecl() + ">\n" +
		" <" + this.nodeElt + " rdf:about='" + this.checkValue(this.fmeta.fMuri.value) +"'>\n" +
		metadata[this.i.rdf] + 
		" </" + this.nodeElt + ">\n" +
		"</rdf:RDF>";

	document.getElementById("meta-xhtml").xmeta.value = 
		"<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='" + 
			this.lang + "' lang='" + this.lang + "'>\n" +
		"<head profile='http://www.w3.org/2003/g/data-view'>\n" +
		" <title>" + this.xtitle + "</title>\n" +
		" <link rel='transformation' href='http://www.w3.org/2000/06/dc-extract/dc-extract.xsl' />\n" +
		this.genSchemaLink() + metadata[this.i.xhtml] + 
		"</head>\n" +
		"<body>\n<!-- your XHTML comes here -->\n" +
		"</body>\n</html>";

	this.saveFlds();
	location = "#rdf-form";
}

/**
 * Parses input fields and returns metadata array (rdf, xhtml).
 * To be called from genRDF().
 */
DCMeta.prototype.genMetadata = function(f){
	var i, rdfres='', metares='', eltname, val;
	var qn = new Array(2);
	for(i=1;i<f.length;i++){
		eltname = f.elements[i].name; //DOM0
		qn = eltname.split(":"); // to Pfx and localname
		//relevant fields have name e.g. 'dc:date', excludes buttons etc.
		if(qn.length>1){
			if(eltname == 'rdf:type'){
				rdfres = this.procType(f.elements[i].value) + rdfres;
			}else{
				val = this.checkValue(f.elements[i].value);
				if(eltname == 'dc:creator' && f.fMmbox.value != ''){
					var rm = new Array(2);
					rm = this.genStructCreator(val,f.fMmbox.value);
					rdfres += rm[this.i.rdf];
					metares += rm[this.i.xhtml];
				}else if(val){
					this.pfxCount[qn[this.i.pfx]]++;
					if(eltname == 'dc:title') this.xtitle = val; // for XHTML
					else if(eltname == 'dc:language') this.lang = val;
					rdfres += this.genPropElt(eltname, val);
					metares += this.genXhtmlTags(qn[this.i.pfx], qn[this.i.lname], val);
				}
			}
		}

	}

	return [rdfres, metares];
}

/**
 * test for typed node element
 * to be called from genMetadata()
 */
DCMeta.prototype.procType = function(val){
	if(val == '') return '';
	if(this.nodeElt != 'rdf:Description') // if already has typed element
		return this.genPropElt('rdf:type', this.checkValue(val));
	var nsar = this.getNsPair(val);
	if(nsar[this.i.pfx]){ // if the first rdf:type and has pfx map
		this.nodeElt = val;
		this.pfxCount[nsar[this.i.pfx]]++;
		return ''; // no property element
	}
	return this.genPropElt('rdf:type', val); // if no pfx map
}

/**
 * Generates structured dc:creator
 */
DCMeta.prototype.genStructCreator = function(uname,mbox){
	var foafname = '', metaname = '';
	mbox = (mbox.substr(0,7) == 'mailto:') ? mbox : 'mailto:' + mbox;
	this.pfxCount['foaf']++; this.pfxCount['dc']++;
	if(uname){
		foafname = "    <foaf:name>" + uname + "</foaf:name>\n";
		metaname = " <meta name='DC.creator' content='" + uname + "' />\n";
	}
	return [
		"  <dc:creator>\n" +
		"   <foaf:Person>\n" + foafname +
		"    <foaf:mbox rdf:resource='" + mbox + "'/>\n" +
		"   </foaf:Person>\n" +
		"  </dc:creator>\n"
		,
		metaname + " <link rev='made' href='" + mbox + "' />\n"
	];
}

/**
 * Generates RDF/XML property element. If val begins with
 * (http|urn|mailto|tag):, then assume rdf:resource, othewise
 * literal value.
 */
DCMeta.prototype.genPropElt = function(elt, val){
	if(val.match(/^(http|urn|mailto|tag):/) && elt != 'dc:identifier'){
		return "  <" + elt + " rdf:resource='" + val + "'/>\n";
	}else{
		return "  <" + elt + ">" + val + "</" + elt + ">\n";
	}
}

/** Generates XHTML meta tag */
DCMeta.prototype.genXhtmlTags = function(pfx,lname,val){
	return " <meta name='" + pfx.toUpperCase() + "." + lname + "' content='" + val + "' />\n";
}

/** Generates XHTML link tag for schema declaration */
DCMeta.prototype.genSchemaLink = function(){
	var pfx, link = "";
	for(pfx in this.nsUris){
		if(this.pfxCount[pfx]) link += " <link rel='schema." + pfx.toUpperCase() + "' href='" + this.nsUris[pfx] + "' />\n";
	}
	return link;
}


// namespace related functions

/**
 * Expnds QNames to abs uri, and escapes &<>...
 * Uri can be input as qname in form field for easy typing.
 */
DCMeta.prototype.checkValue = function(val){
	if(val == '') return '';
	var nsar = this.getNsPair(val);
	if(nsar[1] == 'http') return nsar[1] + ':' + this.escEntVal(nsar[2]);
	else if(nsar[this.i.pfx]) return val.replace(nsar[this.i.pfx] + ':',nsar[this.i.uriref]);
	else return this.escEntVal(val);
}

/**
 * Find pair of nsuri and local name from qname-style (aaa:bbb) input.
 * If input val begins with http:, then returns special array,
 * if pfx is registered as standard, then returns [nsuri, localname],
 * otherwise returns empty string.
 */
DCMeta.prototype.getNsPair = function(val){
	var nsuri, uriar;
	if(val.substr(0,5) == 'http:') return ['','http', val.substr(5)];
	//pfx = String(val.match(/^[a-z]+:/)); //Safari doesn't work ?
	uriar = (val.substr(0,8)).split(':');
	if(uriar.length > 1 && (nsuri = this.nsUris[uriar[this.i.pfx]]))
		return new Array(uriar[this.i.pfx],nsuri);
	return '';
}

/** generates xmlns attributes */
DCMeta.prototype.genNSdecl = function(){
	//var ns = "  xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'\n";
	var pfx, ns = '';
	for(pfx in this.nsUris){
		if(this.pfxCount[pfx]) ns += "  xmlns:" + pfx + "='" + this.nsUris[pfx] + "'\n";
	}
	return ns;
}

/** Escapes &, <, > */
DCMeta.prototype.escEntVal = function(val){
	if(this.escEnt) return ((val.replace(/&/g,'&amp;')).replace(/</g,'&lt;')).replace(/>/g,'&gt;');
	else return val;
}

/**
 * Checks date format, and suggest if necessary. msg should be
 * defined in calling XHTML document according to its language.
 */
DCMeta.prototype.dateCheck = function(d){
	if(! d.value.match(/^\d{4}-\d{2}-\d{2}/)){
		alert(this.msg['dateAlert']);
		d.focus(); d.select();
	}
}



//--------------- input form generation on XHTML page


DCMeta.prototype.addFlds = function(type){
	if(type =='auto')
		if(! this.fmeta.autoAddFld.checked) return;
	var val = this.fmeta.dcflds.value;
	if(val=='') return;
	if(val.charAt(0) == '@'){
		var pfx = val.substr(1);
		var i, vocab = this.vocab[pfx];
		var varray = vocab.split(':');
		for(i=0;i<varray.length;i++){
			this.addOne("tb2",pfx + ':' + varray[i]);
		}
	}else{
		this.addOne("tb2",val,'');
	}
}

DCMeta.prototype.addOne = function(tblId, fld, defval){
	var iQname=0, iDesc=1, iRange=2, iDefval=3;
	var fldar = fld.split(';');
	var tbl = document.getElementById(tblId);
	var elt = fldar[iQname];
	var desc = fldar[iRange] ? fldar[iDesc] + this.msg['range'] + fldar[iRange] : 
		( fldar[iDesc] ? fldar[iDesc] : " ");
	var tr = document.createElement("tr");
	var td1 = document.createElement("td");
	td1.appendChild(document.createTextNode(elt + ':'));
	var infld = document.createElement("input");
	infld.className = tblId;
	//alert("index:"+elt.indexOf(':',0));
	if(elt.indexOf(':',0)>0){
		infld.setAttribute("name",elt);
	}else if(elt.charCodeAt(0) > 96){
		infld.setAttribute("name","dcq:" + elt);
	}else{
		infld.setAttribute("name","dc:" + elt.toLowerCase());
	}
	infld.setAttribute("size","40");
	if(defval){
		infld.setAttribute("value",defval);
	}else if(elt == 'Identifier' && this.fmeta.fMuri.value){
		infld.setAttribute("value",this.fmeta.fMuri.value);
	}else if(this.dcdef[elt]){
		infld.setAttribute("value",this.dcdef[elt]);
	}else if(fldar[iDefval]){
		infld.setAttribute("value",fldar[iDefval]);
	}else if(fldar[iRange]){
		infld.setAttribute("value","http://");
	}
	var td2 = document.createElement("td");
	td2.appendChild(infld);
	var td3 = document.createElement("td");
	td3.className = "expl";
	td3.appendChild(document.createTextNode(desc));
	tr.appendChild(td1);
	tr.appendChild(td2);
	tr.appendChild(td3);
	tbl.appendChild(tr);
	infld.focus();
	infld.select();
	return false;
}

DCMeta.prototype.saveFlds = function(){
	var tbs = new Array('tb1', 'tb2'), mdata;
	var x, tgname, saveres = '';
	for(i=0;i<tbs.length;i++){
		mdata = (document.getElementById(tbs[i])).getElementsByTagName("input");
		for(j=0;j<mdata.length;j++){
			x = mdata.item(j);
			tgname = x.name;
			if(tgname.substr(0,3) == 'dc:'){
				tgname = tgname.substr(3);
				tgname = this.ucFirst(tgname);
			}else if(tgname.substr(0,4) == 'dcq:')
				tgname = tgname.substr(4);
			saveres += tbs[i] + TAB + tgname + TAB + x.value + SEP;
		}
	}
	this.savef.value = saveres;
}

DCMeta.prototype.restoreFlds = function(){
	var saveres = this.savef.value, tmp = new Array(3);
	var flds = saveres.split(SEP);
	for(var i=0; i<flds.length; i++){
		tmp = flds[i].split(TAB);
		if(tmp[1]) this.addOne(tmp[0], tmp[1], tmp[2]);
	}
	this.disableDemo();
}

DCMeta.prototype.ucFirst = function(str){
	return String.fromCharCode(str.charCodeAt(0) - 32) + str.substr(1);
}

DCMeta.prototype.showMboxfld = function(){
	document.getElementById('mbox-expl').style.display = 'none';
	document.getElementById('mbox-fld').style.display = 'inline';
	this.fmeta.fMmbox.focus();
	this.fmeta.fMmbox.select();
}

DCMeta.prototype.demo = function(){
	this.fmeta.fMuri.value = "http://www.kanzaki.com/docs/dc-a-matic";
	document.getElementById('fMtitle').value = this.getTagVal('title',0);
	document.getElementById('fMcreator').value = "Masahide Kanzaki";
	document.getElementById('fMmbox').value = "webmaster@kanzaki.com";
	this.showMboxfld();
	document.getElementById('fMcreated').value = this.getIdVal('metaCrDate');
	document.getElementById('fMmodified').value = this.getIdVal('metaModDate');
	document.getElementById('fMsubject').value = this.getTagVal('dfn',0);
	document.getElementById('fMdescr').value = this.getIdVal('metaDesc');
	this.addOne('tb1','Subject',this.getTagVal('dfn',1));
	this.addOne('tb1','Subject',this.getTagVal('dfn',2));
	this.addOne('tb2','rdf:type','foaf:Document');
	this.addOne('tb2','rdf:type','wn:Program');
	this.addOne('tb2','isPartOf','http://www.kanzaki.com/');
	this.disableDemo();
}

DCMeta.prototype.disableDemo = function(){
	document.getElementById('demoBtn').disabled = "disabled";
	document.getElementById('demo-expl').style.color = "silver";
	document.getElementById('rtrvBtn').style.display = 'none';
}

DCMeta.prototype.getIdVal = function(myid){
	return ge.nodeText(document.getElementById(myid)); //std.js
}
DCMeta.prototype.getTagVal = function(tagname,ord){
	return ge.nodeText(document.getElementsByTagName(tagname).item(ord));
}



// Extracts metadata from (X)HTML head element
DCMeta.prototype.parseHtml = function(xh,baseUri){
	var i, j, propName, propVal, aTemp, linkType, tmpHtmlDiv, tmp, dummy;
	var patMod, tx, res;
	var dcSubject = 0, tmpType, relUri = 0;
	var aEltnm = {head:"div",title:"title",link:"link",meta:"meta",base:"base"};
	
	//prepare input HTML form field
	tmpHtmlDiv = document.getElementById('temp-html');
	if(xh){
		document.getElementById('htmlextractor').xmeta.value = xh;
		//return;
	}else{
		xh = document.getElementById('htmlextractor').xmeta.value;
	}
	dummy = (xh).replace(/<(\/?)head/i,'<$1div');
	if(ge.isIE || ge.isSafari){
		//IE doesn't allow to have link, meta, title in a div element
		aEltnm['title'] = 'h6'; aEltnm['link'] = 'br'; aEltnm['meta'] = 'hr'; aEltnm['base'] = 'area';
		dummy = (((dummy.replace(/<link/ig,'<'+aEltnm['link'])).replace(/<meta/ig,'<'+aEltnm['meta'])).replace(/(<\/?)title/ig,'$1'+aEltnm['title'])).replace(/<base/ig,'<'+aEltnm['base']);
	}
	tmpHtmlDiv.innerHTML = dummy;
	//alert(tmpHtmlDiv.innerHTML);
	//set base URI
	tmp = tmpHtmlDiv.getElementsByTagName(aEltnm['base']);
	if(! baseUri) {
		baseUri = (tmp.length > 0) ? tmp.item(0).getAttribute('href') : document.getElementById('fMuri').value;
		baseUri = prompt(this.msg['baseUri'],baseUri);
	}
	this.setBaseUri(baseUri);
	
	//clean up form
	if(! ge.isOpera && ! ge.isMacIE) this.fmeta.resetFMeta.click(); //Opera behaves odd
	this.removeChilds('tb1');this.removeChilds('tb2');
	
	location = '#metadata';
	
	// parse data and fill input form
	document.getElementById('fMuri').value = baseUri;
	tmp = tmpHtmlDiv.getElementsByTagName(aEltnm['title']);
	if(tmp.length > 0)
		document.getElementById('fMtitle').value = tmp.item(0).firstChild.data;
	
	tmp = tmpHtmlDiv.getElementsByTagName(aEltnm['head']).item(0);
	var link = tmp.getElementsByTagName(aEltnm['link']);
	var meta = tmp.getElementsByTagName(aEltnm['meta']);
	var addr = tmpHtmlDiv.getElementsByTagName('address');

	// proc address
	patMod = new RegExp("(modified" + this.msg['modDate'] + "):?\\s*(\\\$Date: )?([\\d\\/:\\w -]+)","i");
	patCopy = new RegExp("(Copyright|&copy;|\\xA9|\\(c\\)):?\s?(.*)","i");
	for(i=0;i<addr.length;i++){
		tx = ge.nodeText(addr.item(i));
		if(tx.match(patMod))
			document.getElementById('fMmodified').value = RegExp.$3;
		if(tx.match(patCopy))
			this.addOne('tb2','Rights',RegExp.$2);
		tmp = addr.item(i).getElementsByTagName('a');
		for(j=0;j<tmp.length;j++){
			res = tmp.item(j).getAttribute('href');
			if(res.substr(0,7)=='mailto:'){
				document.getElementById('fMmbox').value = res;
				this.showMboxfld();
				res = ge.nodeText(tmp.item(j));
				if(res.indexOf('@') == -1)
					document.getElementById('fMcreator').value = res;
			}
		}
	}
	
	// proc link elements
	for(i=0;i<link.length;i++){
		if(!(propVal = link.item(i).getAttribute('href'))) continue;
		linkType = link.item(i).getAttribute('rel') || link.item(i).getAttribute('rev');
		switch(linkType.toLowerCase()){
			case 'made':
				document.getElementById('fMmbox').value = propVal;
				this.showMboxfld(); break;
			case 'meta':
				this.addOne('tb2','rdfs:seeAlso',this.resolveRelUri(propVal)); break;
			case 'alternate':
				if((tmpType = link.item(i).getAttribute('type'))
					&& tmpType.indexOf('xml') != -1){
						this.addOne('tb2','rdfs:seeAlso',this.resolveRelUri(propVal));
				}
				break;
			case 'copyright':
				this.addOne('tb2','Rights',this.resolveRelUri(propVal)); break;
		}
	}
	
	// proc meta elements
	for(i=0;i<meta.length;i++){
		if(!(propVal = meta.item(i).getAttribute('content'))) continue;
		propName = meta.item(i).getAttribute('name') || meta.item(i).getAttribute('http-equiv');
		propName = propName.toLowerCase();
		if(propName.substr(0,3) == 'dc.') propName = propName.substring(3);
		switch(propName){
			case 'author':
			case 'creator':
				document.getElementById('fMcreator').value = propVal; break;
			case 'keywords':
			case 'subject':
				aTemp = propVal.split(/[;,]/); 
				for(j=0;j<aTemp.length;j++){
					aTemp[j] = aTemp[j].replace(/^\s+/,'');
					if(dcSubject++ > 0)
						this.addOne('tb1','Subject',aTemp[j]);
					else
						document.getElementById('fMsubject').value = aTemp[j];
				}
				break;
			case 'description' :
			case 'abstract' :
				document.getElementById('fMdescr').value = propVal; break;
			case 'content-type' :
				this.addOne('tb2','Format',propVal); break;
			case 'content-language' :
				this.addOne('tb2','Language',propVal); break;
			case 'date':
				document.getElementById('fMdate').value = propVal; break;
			case 'last-modified':
			case 'wwwc':
				document.getElementById('fMmodified').value = propVal; break;
			case 'copyright':
			case 'rights':
				this.addOne('tb2','Rights',propVal); break;
			case 'format':
			case 'contributor':
			case 'language':
			case 'coverage':
			case 'relation':
			case 'source':
			case 'type':
				this.addOne('tb2',this.ucFirst(propName),propVal); break;
		}
	}
	tmpHtmlDiv.innerHTML = '';
	this.disableDemo();
	
}

DCMeta.prototype.removeChilds = function(target){
	//IE doesn't allow innerHTML for table constructs
	var tg = document.getElementById(target);
	while(tg.childNodes.length > 0){
		tg.removeChild(tg.lastChild);
	}
}


DCMeta.prototype.setBaseUri = function(bUri){
	bUri = bUri.substr(7);
	this.aBuri = bUri.split('/');
	this.lenBuriArray = this.aBuri.length;
}


DCMeta.prototype.resolveRelUri = function(relUri){
	if(relUri.substr(0,5) == 'http:') return relUri;
	if(relUri.charAt(0)=='/') return 'http://' + this.aBuri[0] + relUri;
	var aRelUri = relUri.split('/');
	var len = this.lenBuriArray;
	var st=0;//st = (relUri.charAt(relUri.length-1)=='/') ? 0 : 1;
	var absUri = 'http://';
	for(var i=0;i<aRelUri.length;i++){
		if(aRelUri[i] == '..'){
			len--; st++;
		}else if(aRelUri[i] == '.'){
			st++; break;
		}else if(aRelUri[i].charAt(0) == '#'){
			aRelUri[i] = this.aBuri[len-1] + aRelUri[i] ; break;
		}else
			break;
	}
	for(i=0; i<len-1; i++)
		absUri += this.aBuri[i] + '/';
	for(i=st; i<aRelUri.length-1;i++)
		absUri += aRelUri[i] + '/';
	return absUri + aRelUri[aRelUri.length-1];
}

