/* Common Class Library for nicovideo.jp */
// requires prototype.js
// requires swfobject.js

if (typeof Nico == "undefined") Nico = { };

Nico.debug = false;
Nico.log = function (msg) {
	if (Nico.debug) {
		if (typeof console != "undefined") {
			console.log(msg);
		} else {
			alert(msg);
		}
	}
};

//
// DOM ready event
//

Nico.isReady = function () { return false; };
Nico.onReady = function (fn) {
	if (Nico.isReady()) {
		try {
			fn();
		} catch (e) {
			Nico.log("Error on Nico onReady: " + (e.message || e));
		}
		return;
	} else {
		if (!Nico.onReady.functions) Nico.onReady.functions = [];
		Nico.onReady.functions.push(fn);
	}
};
Nico.__getReady = function () {
	if (Nico.isReady()) return false;
	Nico.isReady = function () { return true; };
	if (Nico.onReady.functions) {
		Nico.onReady.functions.each(function (fn) {
			try {
				fn();
			} catch (e) {
				Nico.log("Error on Nico getReady: " + (e.message || e));
			}
		});
		delete Nico.onReady.functions;
	}
	return true;
};

//
// Cookie  (requires cookie.swf)
//

Nico.Cookie = {
	get: function (name, defaultValue) {
		var re = new RegExp("(?:^|;\\s*)" + escape(name) + "\\s*=\\s*([^;]*)");
		return re.test(document.cookie) ? unescape(RegExp.$1) : defaultValue;
	},
	set: function (name, value, expires, domain, path, secure) {
		var s = escape(name) + "=" + escape(value);
		if (expires !== undefined) {
			if (!(expires instanceof Date)) {
				var dt = new Date();
				dt.setTime(dt.getTime() + expires);
				expires = dt;
			}
			s += "; expires=" + expires.toGMTString();
		}
		if (domain !== undefined) s += "; domain=" + domain;
		if (path !== undefined) s += "; path=" + path;
		if (secure) s += "; secure";
		return document.cookie = s;
	},
	remove: function (name, domain, path, secure) {
		this.set(name, "", -1, domain, path, secure);
	}
};
Cookie = Nico.Cookie;

Nico.FlashCookie = Class.create();
Nico.FlashCookie.SWF_PATH = "swf/cookie.swf?20081024";
Nico.FlashCookie.instances = [];
Nico.FlashCookie.prototype = {
	initialize: function (id) {
		this.id = id;
		this.element = null;
		this.ready = false;
		Nico.FlashCookie.instances[id] = this;
	},
	write: function (container) {
		if (this.element) return false;
		var so = new SWFObject(Nico.FlashCookie.SWF_PATH, this.id, "1", "1");
		so.addParam("allowScriptAccess", "always");
		so.addVariable("storage", this.id);
		so.setAttribute("style", "margin-left:-1000px");
		so.write(container);
		return this;
	},
	onReady: function (fn) {
		if (this.ready) {
			try {
				fn.call(this, this);
			} catch(e) {
				Nico.log("Error on FlashCookie onReady: " + (e.message || e));
			}
		} else {
			if (!this.functions) this.functions = [];
			this.functions.push(fn);
		}
		return fn;
	},
	__getReady: function () {
		if (this.ready) return;
		this.ready = true;
		if (this.functions) {
			this.functions.each(function (fn) {
				try {
					fn.call(this, this);
				} catch(e) {
					Nico.log("Error on FlashCookie getReady: " + (e.message || e));
				}
			}.bind(this));
			delete this.functions;
		}
	},

	set: function (key, value) {
		return this.element.setCookie(key, value);
	},
	get: function (key, defaultValue) {
		return this.element.getCookie(key, defaultValue);
	},
	remove: function (key) {
		this.element.removeCookie(key);
	},
	update: function (obj) {
		for (var key in obj) {
			this.element.setCookie(key, obj[key]);
		}
	}
};
FlashCookie = Nico.FlashCookie;

// called from cookie.swf
FlashCookie.readyFromSWF = function (id) {
	var instance = Nico.FlashCookie.instances[id];
	if (instance) {
		(function () {
			if (!instance.element) {
				var el;
				try { el = document.getElementById(id); } catch (e) {}
				if (!el) {
					setTimeout(arguments.callee, 100);
					return;
				}
				instance.element = el;
			}
			try {
				instance.get("init");
			} catch (e) {
				setTimeout(arguments.callee, 100);
				return;
			}
			instance.__getReady();
		})();
	}
};

// global flashCookie instance
var flashCookie = new Nico.FlashCookie("external_flashcookie");

//
// UI Components
//

Nico.UI = {};

/* MessageBalloon */

Nico.UI.MessageBalloon = Class.create();
Nico.UI.MessageBalloon.prototype = {
	initialize: function (pointElement, message, options) {
		this.pointElement = $(pointElement);
		this.options = Object.extend({
			align: "LT",
			className: "balloon",
			timer: 10000,
			clickable: true
		}, options || {});
		this.element = this.__createElement(message);
		this.elementInDocument = false;
		this.hideTimer = null;
		this.clickHandler = null;
	},
	__createElement: function (message) {
		var el = $(document.createElement("div"));
		el.setStyle({ "display": "none", "position": "absolute" });
		el.className = (this.options.className || "");
		el.update('<p>' + message + '</p>');
		return el;
	},
	setMessage: function (message) {
		this.element.update('<p>' + message + '</p>');
	},
	show: function () {
		if (!this.elementInDocument) {
			document.body.appendChild(this.element);
			this.elementInDocument = true;
		}
		this.element.show();
		this.updateElementPosition();

		if (this.hideTimer) {
			clearTimeout(this.hideTimer);
			this.hideTimer = null;
		}
		if (this.options.timer > 0) {
			this.hideTimer = setTimeout(function () {
				this.hideTimer = null;
				this.hide();
			}.bind(this), this.options.timer);
		}
		if (this.options.clickable) {
			this.clickHandler = this.hide.bind(this);
			this.element.observe("click", this.clickHandler);
		}
	},
	hide: function () {
		if (this.hideTimer) {
			clearTimeout(this.hideTimer);
			this.hideTimer = null;
		}
		if (this.clickHandler) {
			this.element.observe("click", this.clickHandler);
			this.clickHandler = null;
		}
		this.element.hide();
		if (this.elementInDocument) {
			document.body.removeChild(this.element);
			this.elementInDocument = false;
		}
	},
	updateElementPosition: function () {
		var pel = this.pointElement;
		if (!pel || !this.options.align) return;

		var rp = Position.cumulativeOffset(pel);
		var rs = pel.getDimensions();
		var es = this.element.getDimensions();
		var point = [
			rp[0] + (rs.width  / 2) - (es.width  / 2),
			rp[1] + (rs.height / 2) - (es.height / 2)
		];
		for (var i = 0; i < this.options.align.length; i++) {
			var c = this.options.align.charAt(i);
			if      (c == "L") point[0] = rp[0] - es.width;
			else if (c == "l") point[0] = rp[0] + rs.width - es.width;
			else if (c == "R") point[0] = rp[0] + rs.width;
			else if (c == "r") point[0] = rp[0];
			else if (c == "T") point[1] = rp[1] - es.height;
			else if (c == "t") point[1] = rp[1] + rs.height - es.height;
			else if (c == "B") point[1] = rp[1] + rs.height;
			else if (c == "b") point[1] = rp[1];
		}
		this.element.setStyle({
			"left": Math.ceil(point[0]) + "px",
			"top": Math.ceil(point[1]) + "px"
		});
	}
};

function balloon(pointElement, message, align) {
	if (balloon.instance) {
		balloon.instance.hide();
	}
	align = align || "LT";
	balloon.instance = new Nico.UI.MessageBalloon(pointElement, message, { "align": align });
	balloon.instance.show();
}

/* LastAction */

Nico.UI.LastAction = {
	update: function () {
		if (!$("last_action")) return;
		flashCookie.onReady(function (cookie) {
			$("last_action", "last_action_enabled", "last_action_disabled").invoke("hide");
			if (!cookie.get("lastActionEnabled")) {
				$("last_action_disabled").show();
				return;
			}

			var search = cookie.get("lastActionSearch"), el = $("last_action_search");
			if (search) {
				el.down("a").href = search.page + "/" + search.word;
				el.down("span").update(search.page == "tag" ? "タグ" : "キーワード");
				var s = decodeURIComponent(search.word);
				s = s.length > 12 ? s.substring(0, 12) + ".." : s;
				el.down("strong").update(s.escapeHTML());
				el.show();
			} else {
				el.hide();
			}

			var mylist = cookie.get("lastActionMylist"), el = $("last_action_mylist");
			if (mylist) {
				el.down("a").href = "mylist/" + mylist.id;
				el.show();
			} else {
				el.hide();
			}

			$( (search || mylist) ? "last_action" : "last_action_enabled" ).show();
		}.bind(this));
	},
	disable: function () {
		flashCookie.onReady(function (cookie) {
			cookie.set("lastActionEnabled", undefined);
			cookie.set("lastActionSearch", undefined);
			cookie.set("lastActionMylist", undefined);
			$("last_action", "last_action_enabled").invoke("hide");
			$("last_action_disabled").show();
		});
	},
	enable: function () {
		flashCookie.onReady(function (cookie) {
			cookie.set("lastActionEnabled", "1");
			$("last_action", "last_action_disabled").invoke("hide");
			$("last_action_enabled").show();
		});
	},
	setLastMylist: function (id, title) {
		var update = this.update.bind(this);
		flashCookie.onReady(function (cookie) {
			if (!cookie.get("lastActionEnabled")) return;
			title = typeof title == "string" ? encodeURIComponent(title) : "";
			cookie.set("lastActionMylist", { "id": id, "title": title });
			setTimeout(update, 500);
		});
	},
	setLastSearch: function (word) {
		var update = this.update.bind(this);
		flashCookie.onReady(function (cookie) {
			if (!cookie.get("lastActionEnabled")) return;
			word = typeof word == "string" ? encodeURIComponent(word) : "";
			cookie.set("lastActionSearch", { "word": word, "page": "search" });
			setTimeout(update, 500);
		});
	},
	setLastTag: function (tag) {
		var update = this.update.bind(this);
		flashCookie.onReady(function (cookie) {
			if (!cookie.get("lastActionEnabled")) return;
			tag = typeof tag == "string" ? encodeURIComponent(tag) : "";
			cookie.set("lastActionSearch", { "word": tag, "page": "tag" });
			setTimeout(update, 500);
		});
	}
};
LastAction = Nico.UI.LastAction;

// update on ready
Nico.onReady(LastAction.update.bind(LastAction));

//
// JSONP Loader
//

JSONP = Class.create();
JSONP.counter = 0;
JSONP.callbackPrefix = "__jsonp";
JSONP.getCallbackName = function (fn) {
	var cbname = this.callbackPrefix + "_" + (this.counter++);
	window[cbname] = function () {
		fn.apply(this, arguments);
		window[cbname] = undefined;
	};
	return cbname;
};
JSONP.prototype = {
	initialize: function (url, options) {
		this.url = url;
		this.options = Object.extend({
			parameters: {}
		}, options || {});
		this.fire();
	},
	fire: function () {
		var params;
		if (typeof this.options.parameters == "string")
			params = this.options.parameters.toQueryParams();
		else
			params = this.options.parameters || {};

		params = $H(params);
		params.each(function (pair) {
			if (typeof pair.value == "function") {
				params[pair.key] = JSONP.getCallbackName(pair.value);
			}
		}.bind(this));
		params["_"] = (new Date()).getTime();
		params = Hash.toQueryString(params);

		var url = this.url;
		if (params) {
			url += (url.indexOf("?") >= 0 ? "&" : "?") + params;
		}

		this.loadScript(url);
	},
	loadScript: function (url) {
		var elemScript = document.createElement('script');
		elemScript.setAttribute('type', 'text/javascript');
		elemScript.setAttribute('charset', 'utf-8');
	    elemScript.setAttribute('src', url);

		var elemHead = document.getElementsByTagName('head').item(0);
		elemHead.appendChild(elemScript);
	}
};


//
// Nico onReady event
//

(function () {
	var timer;
	var fire = function () {
		Nico.__getReady() && timer && window.clearInterval(timer);
	};

	if (document.addEventListener) {
		document.addEventListener("DOMContentLoaded", fire, false);
	}
	if (Prototype.Browser.IE && window == top) {
		(function () {
			if (Nico.isReady()) return;
			try {
				document.documentElement.doScroll("left");
			} catch (e) {
				setTimeout(arguments.callee, 0);
				return;
			}
			fire();
		})();
	}
	if (Prototype.Browser.WebKit) {
		var numStyles;
		(function () {
			if (Nico.isReady()) return;
			if (document.readyState != "loaded" && document.readyState != "complete") {
				setTimeout(arguments.callee, 0);
				return;
			}
			fire();
		})();
	}

	Event.observe(window, "load", fire);
})();
