/*
 * Copyright (c) 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
 * You may copy and modify this script as long as the above copyright notice,
 * this condition and the following disclaimer is left intact.
 * This software is provided by the author "AS IS" and no warranties are
 * implied, including fitness for a particular purpose. In no event shall
 * the author be liable for any damages arising in any way out of the use
 * of this software, even if advised of the possibility of such damage.
 */

if(!document.body) alert("No file:// URLs please; make it a real web page!");

if(!window.$JCA) var $JCA = [];

new JSCC();	/* JavaScript Comment Class */

function JSCC() {
	/* Find the target DIV for all the blog comments */
	this.jcaIndex = $JCA.length;
	$JCA.push(this);
	this.get = function(id) { return document.getElementById(id); }
	this.cr = function(tag) { return document.createElement(tag); }
	this.labelHTML = "Leave a comment";
	this.uri = 'http://js-kit.com/comment';
	this.fieldDfl = {};
	this.TC = {};
	this.tmpID = 0;
	this.pathOverride = "";
	var idName = "js-kit-comments";

	if(arguments.length) {
		var target = arguments[0];
	} else {
		var target = this.get(idName);
	}

	if(target) {
		var label = target.getAttribute("label");
		if(label) this.labelHTML = label;
		var path = target.getAttribute("path");
		if(path) {
			this.pathOverride = String(path).replace(/^([^\/]+)/,
				window.location.pathname + "/$1");
		}
		var template = String(target.innerHTML);
		if(template.match(/js-singleComment/))
			this.userCommentTemplate = template;
		target.innerHTML = "";
		target.style.visibility = "visible";
	} else {
		var els = document.body.getElementsByTagName(idName);
		if(els.length) {
			$JCA.shift();
			for(var i = 0; i < els.length; i++)
				new JSCC(els[i]);
			return;
		} else {
			document.write('<div id="'+idName+'"></div>');
			target = this.get(idName);
		}
	}
	target.className = "js-kit-comments";
	target.id = "";
	this.target = target;
	this.cmtById = {};
	try {
		/* User can override translation function */
		this.trans = JSCC_Translate;
	} catch(e) {
		this.trans = function(text) { return text; }
	}
	this.server = function(ext, data) {
		var wl = window.location;
		var co = this.target;
		var sc = this.cr("script");
		sc.setAttribute("charset", "utf-8");
		sc.src = this.uri + ext + this.pathOverride
			+ "?ref="
			+ encodeURIComponent(
	wl.protocol + "//" + wl.host
	+ (this.pathOverride.length ? "/" : wl.pathname))
			+ "&" + data;
		co.appendChild(sc);
	}
	/* Initiate data transfer */
	this.server("s-data.js", "jx=" + this.jcaIndex);
}

JSCC.prototype.addChild = function(to, what) {
	try { what.parent = to; } catch(e) { ; }
	to.appendChild(what);
}
JSCC.prototype.html = function() {
	var div = this.cr("div");
	for(var text = '', i = 0; i < arguments.length; i++)
		text += arguments[i];
	div.innerHTML += text;
	var ch = div.firstChild;
	div = null;
	return ch;
}

JSCC.prototype.div = function(id) {
	var div = this.cr("div");
	for(var i = 1; i < arguments.length; i++) {
		var arg = arguments[i];
		switch(typeof(arg)) {
		case "string":
			this.addChild(div, document.createTextNode(arg));
			break;
		case "undefined":
			break;
		default:
		case "object":
			if(!arg) break;
			this.addChild(div, arg);
			break;
		}
	}
	if(id) {
		div.className = id;
		var idText = String(id);
		if(idText.charCodeAt(3) < 91)
			this.TC[idText] = div;
	}
	return div;
}

JSCC.prototype.defaultCommentTemplate
 = '<div class="js-singleComment">'
 + '<div class="js-singleCommentBg">'
 + '<div class="js-singleCommentINFO">'
   + '<div class="js-singleCommentName">{Name}</div>'
   + '<div class="js-singleCommentDate">{Date}</div>'
   + '<div class="js-singleCommentControls">'
     + '[<a class="js-singleCommentReply">{Label:reply}</a>]'
     + '<span class="js-singleCommentDeletable"> [<a class="js-singleCommentDelete">{Label:delete}</a>]</span>'
     + '<span class="js-singleCommentSpam"> [<a class="js-singleCommentNotSpam">{Label:not spam}</a>]</span>'
   + '</div>'
 + '</div>'
 + '<div class="js-singleCommentText">{Text}</div>'
 + '<div style="clear: both"></div>'
 + '</div>'
 + '</div>'
;

JSCC.prototype.mapClass2Object = function(ctl, obj) {
	if(obj.className) ctl[obj.className] = obj;
	if(obj.hasChildNodes && obj.hasChildNodes()) {
		var children = obj.childNodes;
		var clen = children.length;
		for(var i = 0; i < clen; i++) {
			this.mapClass2Object(ctl, children[i]);
		}
	}
	return ctl;
}
JSCC.prototype.localTime = function(t) {
	if(!t) return "";
	var d = new Date(t * 1000);
	return d.toLocaleDateString();
}
JSCC.prototype.applyTemplate = function(t, obj) {
	var self = this;
	var lowercase = function(a, m) { return String(m).toLowerCase(); }
	t = t.replace(/^[^<]*(<.*>)[^>].*$/m, "$1");
	t = t.replace(/(<[\/]?[A-Z]+)/g, lowercase);
	t = t.replace(/{Label:([^}]*)}/g,function(a,m){return self.trans(m);});
	t = t.replace(/{Name}/g, obj.Name ? obj.Name : '');
	t = t.replace(/{Email}/g, obj.Email ? obj.Email : '');
	t = t.replace(/{Date}/g, self.localTime(obj.TS));
	var text = String(obj.Text).replace(/^[ \s]+|[ \s]+$/, '');
	text = text.replace(/\n/g, '&nbsp;<br />');
	text = text.replace(/([^&<>]{15})([^&<>]{15})/g, '$1<wbr />$2');
	t = t.replace(/{Text}/g, text);
	return t;
}
JSCC.prototype.createSingleComment = function(obj) {
	if(!obj.ID || !obj.Text) return undefined;

	var self = this;
	var tmpl = this.applyTemplate(this.userCommentTemplate
			|| this.defaultCommentTemplate, obj);

	var odiv = this.cr("div");
	odiv.innerHTML = tmpl;
	var cmt = odiv.firstChild;
	odiv.removeChild(cmt);
	odiv = null;

	cmt.id = obj.ID;
	this.cmtById[cmt.id] = cmt;

	switch(obj.status) {
	case 'D': cmt.style.display = "none"; break;
	case 'S': cmt.style.backgroundColor = '#fff0f0';
	}

	var ctls = this.mapClass2Object({}, cmt);

	if(obj.isEmbryonic) {
		/* Waiting for permanent ID */
		var msgControls = ctls["js-singleCommentControls"];
		if(msgControls) {
			msgControls.style.visibility = "hidden";
			cmt.assignPermanentID = function(msgId) {
				cmt.assignPermanentID = null;
				self.cmtById[cmt.id] = null;
				cmt.id = msgId;
				self.cmtById[cmt.id] = cmt;
				msgControls.style.visibility = "";
			}
		}
	}

	var replCtl = ctls["js-singleCommentReply"];
	if(replCtl) {
		replCtl.href = "";
		replCtl.onclick = function() {
			return self.ShowCommentDialog(cmt.id); }
	}
	var delCtl = ctls["js-singleCommentDelete"];
	if(delCtl) {
		delCtl.href = "";
		delCtl.onclick = function() {
			var msg = self.get(cmt.id);
			if(!msg) return false;
			var spam = false;
			if(window.location.hostname == "js-kit.com")
				spam = confirm("Is it SPAM?");
			msg.style.display = "none";
			/* Kick in message delete */
			self.server('.del', 'id=' + cmt.id
				+ (spam ? "&spam=yes" : ""));
			return false;
		}
	}
	var hideCtl = ctls["js-singleCommentDeletable"];
	if(hideCtl && !obj.yours)
		hideCtl.style.display = "none";

	var spamCtl = ctls["js-singleCommentSpam"];
	if(spamCtl && obj.status != 'S')
		spamCtl.style.display = "none";
	var unSpamCtl = ctls["js-singleCommentNotSpam"];
	if(unSpamCtl) {
		unSpamCtl.href = "";
		unSpamCtl.onclick = function() {
			var msg = self.get(cmt.id);
			if(!msg) return false;
			cmt.style.backgroundColor = '';
			obj.status = 'A';
			if(spamCtl) spamCtl.style.visibility = "hidden";
			self.server('.del', 'id=' + cmt.id + "&spam=no");
			return false;
		}
	}

	ctls = null;
	var cmtThr = this.div("js-commentThread", cmt);
	return cmtThr;
}

JSCC.prototype.cmtInDiv = function(div, obj) {
	var cmt = this.createSingleComment(obj);
	if(cmt) {
		if(obj.ParentID) {
			var prn = this.cmtById[obj.ParentID];
			if(prn && (prn = prn.parent)) {
				cmt.style.marginLeft = "10px";
				this.addChild(prn, cmt);
				return cmt;
			}
		}
		this.addChild(div, cmt);
	}
	return cmt;
}

JSCC.prototype.setOpacity = function(div, val) {
	div.style.opacity = val;
	div.style.filter = 'alpha(opacity: ' + Math.round(val * 100) + ')';
}

JSCC.prototype.flash = function(cmt) {
	var self = this;
	var bg = cmt.firstChild.firstChild;

	try {
		bg.style.backgroundColor = "#ffff00";
		self.setOpacity(bg, 0);
	} catch(e) { return; }

	cmt.cntDown = 3.14 / 2;
	cmt.cntMode = 0;

	cmt.intvl = setInterval(function() {
		cmt.cntDown -= cmt.cntMode ? 0.5 : 0.3;
		if(cmt.cntDown > 0) {
			if(cmt.cntMode)
				var c = Math.sin(cmt.cntDown);
			else
				var c = Math.cos(cmt.cntDown);
			self.setOpacity(bg, c);
		} else if(cmt.cntMode) {
			clearInterval(cmt.intvl);
			cmt.intvl = null;
			bg.style.backgroundColor = "";
			self.setOpacity(bg, 1);
		} else {
			cmt.cntMode = 1;
			cmt.cntDown = 3.14 / 2;
		}
	}, 100);
}

JSCC.prototype.collectFields = function (node, cmtObj, tagName) {
	var fields = node.getElementsByTagName(tagName);
	var message = '';
	for(var i = 0; i < fields.length; i++) {
		var field = fields[i];
		var name = String(field.getAttribute("NAME"));
		if(!name.match(/^js-Cmt[A-Za-z0-9]+$/)) continue;
		message += "&" + name + "=" + encodeURIComponent(field.value);
		var shortName = name.replace(/^js-Cmt/, '');
		var text = String(field.value);
		text = text.replace(/&/g, "&amp;");
		text = text.replace(/</g, "&lt;");
		text = text.replace(/>/g, "&gt;");
		text = text.replace(/\n/g, "<br />");
		cmtObj[shortName] = text;
	}
	return message;
}

JSCC.prototype.cmtInPlace = function(cobj) {
	var div = this.TC["js-OldComments"];
	this.tmpID++;
	cobj.ID = "jst-" + this.tmpID;
	cobj.isEmbryonic = true;
	var d = new Date();
	cobj.TS = Math.round(d.valueOf() / 1000);
	var cmt = this.cmtInDiv(div, cobj);
	this.flash(cmt);
	return cmt;
}

JSCC.prototype.setDefaultField = function(name, value) {
	this.fieldDfl[name] = value;
}

document.write('<style type="text/css">'
+ ".js-LeaveComment { margin-top: 0.5em; }"
+ ".js-CreateComment { display: none; margin: 1em; padding: 0.5em; border: solid 1px #FFFFFF; text-align: left; }"
+ ".js-commentFieldSubject { font-weight: bold; padding-bottom: 5pt; }"
+ ".js-commentFieldNote { font-size: 7pt; color: #FFFFFF; }"
+ ".js-singleComment { font-size: 8pt; font-family: Verdana, Helvetica; border: solid 1px #FFFFFF; text-align: left; margin-bottom: -1px; }"
+ ".js-singleCommentBg { padding: 0.3em; }"
+ ".js-singleCommentTEXT { }"
+ ".js-singleCommentINFO { text-shadow: #FFFFFF 0px 2px 4px; color: #FFFFFF; float: right; padding: 3px; padding-left: 2em; text-align: right; }"
+ ".js-singleCommentName { }"
+ ".js-singleCommentDate { font-size: 8pt; }"
+ ".js-PoweredBy { margin-left: 1em; float: right; color: #FFFFFF; font-size: 7pt; font-family: Verdana, Helvetica; }"
+ ".js-PoweredBy A { text-decoration: none; color: #FFFFFF }"
+ "</style>");
(function(v){v=parseFloat(v.split("MSIE")[1]);
if(v>=5.5)document.write('<style>.js-singleCommentBg{zoom:1.0;}</style>');})
(navigator.appVersion);

JSCC.prototype.ShowCommentDialog = function(msgId) {

	this.forMsgID = msgId;

	var cct = this.TC["js-LeaveComment"];
	var ccd = this.TC["js-CreateComment"];

	/* Remove dialog from sight */
	this.CommentCancelled();
	if(msgId) {
		var nthr = this.get(msgId);
		if(nthr && (nthr = nthr.parent)) {
			/* Reposition dialog */
			ccd.parent.removeChild(ccd);
			this.addChild(nthr, ccd);
		}
	}

	cct.style.display = "none";
	ccd.style.display = "block";
	try {
		var sub = this.TC["js-CmtSubmit"];
		var email = this.TC["js-CmtEmail"];
		var name = this.TC["js-CmtName"];
		var text = this.TC["js-CmtText"];

		if(sub) sub.focus();
		if(email && !email.value.length)
			email.value = this.fieldDfl["Email"];
		if(name && !name.value.length)
			name.value = this.fieldDfl["Name"];
		if(name && name.value.length) {
			if(email && email.value.length) {
				text.focus();
			} else if(email) {
				email.focus();
			}
		} else if(name) {
			name.focus();
		}
	} catch(e) { ; }
	return false;
}

JSCC.prototype.CommentCancelled = function() {
	var lct = this.TC["js-LeaveComment"];
	var ccd = this.TC["js-CreateComment"];
	var car = this.TC["js-CommentsArea"];
	lct.style.display = "";
	ccd.style.display = "";
	if(car && ccd.parent != car) {
		ccd.parent.removeChild(ccd);
		this.addChild(car, ccd);
	}
	return false;
}

JSCC.prototype.CommentSubmitted = function() {
	var form = this.TC["js-CreateComment"];
	var cmtObj = {};
	cmtObj.yours = true;
	var message = this.collectFields(form, cmtObj, "input")
		+ this.collectFields(form, cmtObj, "textarea");
	message = message.replace(/^&/, '');
	if(!cmtObj.Text || !cmtObj.Text.length) {
		alert(this.trans("Your message is too short"));
		return false;
	}
	if(cmtObj.Text.length > 1000) {
		alert(this.trans("Message size should not exceed 1000 bytes for this site"));
		return false;
	}
	cmtObj.ParentID = this.forMsgID;
	this.CommentCancelled();
	/* Attach message */
	this.cmtInPlace(cmtObj);
	/* Kick in message submission */
	var puturl = message + '&tid=' + cmtObj.ID
	  + (cmtObj.ParentID ? ('&js-CmtParentID=' + cmtObj.ParentID) : '');
	this.server('.put', puturl);
	return false;
}

function JSReplyMSGId(tmpid, msgid) {
	try {
		var tcmt = document.getElementById(tmpid);
		tcmt.assignPermanentID(msgid);
	} catch(e) { ; }
}

JSCC.prototype.newData = function(arr) {

	var self = this;
	var tc = this.TC;

	var div = this.div("js-OldComments");
	for(var i = 0; i < arr.length; i++)
		this.cmtInDiv(div, arr[i]);

	var cmtDialogHref = this.html('<a href="" onclick="return false;">'
		+ this.trans(this.labelHTML) + '</a>');
	cmtDialogHref.onclick = function() {
		return self.ShowCommentDialog(null); };

	tc["js-CmtSubmit"] = this.html('<input type=submit'
		+ ' id="js-SubmitComment" VALUE="'
		+ this.trans("Submit comment") + '" onclick="return false;">');
	tc["js-CmtSubmit"].onclick = function() { return self.CommentSubmitted(); }

	tc["js-CmtCancel"] = this.html('<input type=reset VALUE="'
		+ this.trans("Cancel") + '" onclick="return false;">');
	tc["js-CmtCancel"].onclick = function() { return self.CommentCancelled(); }

	tc["js-CmtName"] = this.html('<input NAME="js-CmtName" SIZE=40 />');
	tc["js-CmtEmail"] = this.html('<input NAME="js-CmtEmail" SIZE=40 />');
	tc["js-CmtText"] = this.html('<textarea NAME="js-CmtText" ROWS=4 COLS=40></TEXTAREA>');

	this.div("js-CreateComment",
	    this.div("js-commentFieldSubject", this.trans(this.labelHTML)),
	    this.div("js-commentFieldLabel", this.trans('Your name:')),
	    this.div(undefined,
		this.html('<input type=hidden NAME="js-Cmthidden" VALUE="о" />'),
		tc["js-CmtName"]
	    ),
	    this.div("js-commentFieldLabel",
			this.trans('Send replies to email:'),
			this.html('<div class="js-commentFieldNote">(email will never be displayed or shared)</span>')
	    ),
	    tc["js-CmtEmail"],
	    this.div("js-commentFieldLabel", this.trans('Comment:')),
	    this.div(undefined, tc["js-CmtText"]),
	    this.div(undefined, tc["js-CmtSubmit"], tc["js-CmtCancel"])
	);

	this.div("js-LeaveComment",
		//this.html('<div id="js-PoweredBy">(powered by <a href="http://js-kit.com/" class="js-PoweredBy">js-kit.com</a>)</div>'),
		cmtDialogHref
	);

	this.div("js-CommentsArea",
		tc["js-OldComments"],
		tc["js-LeaveComment"],
		tc["js-CreateComment"]
	);

	this.addChild(this.target, tc["js-CommentsArea"]);
}

