/**
 * Scripts for [Space Shower TV]
 * using jQuery JavaScript Framework
 *
 * bookmark of your favorite (あなたのツボ)
 *
 * @author     RaNa design associates, inc.
 * @copyright  2011 RaNa design associates, inc.
 */

(function($) {

	var sstv = {};

	$(function() {
		var button = $(".tsubo a"),
			sideTsubo = $(".mod_sideTsubo"),
			favorite = sideTsubo.find(".favorite");
		// set bookmark jar
		button.setJar();
		sstv.buttonTsubo = button.data("setJar");
		// ツボモジュール
		sideTsubo.tsubo();
		sstv.sideTsubo = sideTsubo.data("tsubo");
	});

	/**
	 * set Jar
	 *
	 * cookie: entryIdキーにmt:EntryIdを配列形式で格納。
	 */
	$.widget("ui.setJar", {
		options: {
			smokeImg: "/images/mod_tsubo/smoke.png",
			tsuboImg: "/images/mod_tsubo/tsubo-shape.png"
		},
		_create: function() {
			var self = this,
				cache = new Image(),
				id = this.element.data("entryId");
			cache.src = this.options.smokeImg;
			cache.src = this.options.tsuboImg;
			this._id = id;

			// クッキー利用可能かの判定
			if (navigator.cookieEnabled) {
				// a要素のshow()はinlineになるため、blockに変更。
				this.element.show().css("display", "block");
				// 既につぼに入っている場合はdisabledにする。
				this.checkDisabled();
			} else {
				return false;
			}
			// [この記事をツボに入れる]ボタン
			this.element.unbind("click").click(function() {
				self.setCookie();
				return false;
			});
		},
		/**
		 * ボタンの使用許可
		 * 既につぼに入っている場合はdisabledにする。
		 */
		checkDisabled: function() {
			if (this.checkCookie()) {
				this.element.removeClass("disabled");	
			} else {
				this.element.addClass("disabled");
			}
		},
		/**
		 * クッキー確認
		 */
		checkCookie: function() {
			if (!$.cookie("entryId")) {
				return true;
			}
			var entries = $.cookie("entryId").split(",");
			for (var key in entries) {
				if (entries[key] == this._id) {
					return false;
				}
			}
			return true;
		},
		/**
		 * クッキー登録
		 */
		setCookie: function() {
			if (!this.checkCookie()) {
				return false;
			}
			var entries = $.cookie("entryId") ? $.cookie("entryId").split(",") : [];
			entries.push(this._id);
			if (entries.length > 5) {
				entries.shift();
			}
			$.cookie("entryId", entries, { path: "/", expires: 90 });
			this.checkDisabled();
			// ツボ登場へ
			this.showJar();
		},
		/**
		 * オーバーレイでツボ登場。
		 */
		showJar: function() {
			var self = this,
				shade = $("<div>", { "class": "mod_intoJar" }),
				tsubo = $("<img>", { "class": "tsubo" }),
				smoke = $("<img>", { "class": "smoke" });
			this.shade = shade;
			this.tsubo = tsubo;
			this.smoke = smoke;
			shade.append(smoke, tsubo).appendTo("#container");
			// 煙
			smoke.attr("src", this.options.smokeImg);
			// 壷
			tsubo.attr("src", this.options.tsuboImg)
			.animate({
				marginTop: 0
			}, {
				easing: "easeOutBounce",
				complete: function() {
					self._intoJar()
				}
			});
		},
		// ツボに煙が入る。
		_intoJar: function() {
			var self = this,
				smoke = this.smoke;
			smoke.animate({
				width: 0,
				height: 0,
				marginLeft: 0,
				marginTop: 80
			}, {
				duration: 600,
				complete: function() {
					self._shakeJar();
				}
			});
		},
		// ツボ震える。
		_shakeJar: function() {
			var self = this,
				tsubo = this.tsubo,
				defaultPosition = tsubo.css("marginLeft"),
				i = 0;
			setTimeout(function() {
				i += 10
				tsubo.css("marginLeft", i % 20 ? -98 : -90);
				if (i < 100) {
					setTimeout(arguments.callee, 20);
				} else {
					tsubo.css("marginLeft", defaultPosition);
					setTimeout(function() {
						self._hideJar();
					}, 200);
				}
			}, 20);
		},
		// ツボ退場。
		_hideJar: function() {
			var self = this,
				shade = this.shade,
				tsubo = this.tsubo,
				size = 189;
			tsubo.animate({
				opacity: 0,
				width: size * 1.5,
				height: size * 1.5,
				marginLeft: -size * 1.5 / 2,
				marginTop: -size / 2
			}, {
				duration: 400,
				complete: function() {
					shade.remove();
					// サイドツボの中身を再読込
					if (sstv.sideTsubo) {
						sstv.sideTsubo.reloadList(self.element.data("entryId"));
					}
				}
			});
		}
	});
	
	/**
	 * ツボモジュール
	 */
	$.widget("ui.tsubo", {
		_create: function() {
			this._favorite = this.element.find(".favorite");
			this._recommend = this.element.find(".recommend");
			// 初期設定
			this._favorite.addClass("opened");
		},
		_init: function() {
			this.setUserguide();
			this.toggleSmoke();
			this.getEntryAll();
			this.changeDrop();
		},
		// エントリー数カウント用
		_count: 0,
		// エントリー管理用
		_entries: [],
		// タグ管理用。(commonタグは必ず含める)
		_tags: ["common"],
		// タグエントリー
		_tagEntries: [],
		/**
		 * クッキーに保存してあるIDから、記事情報をまとめて取得
		 */
		getEntryAll: function() {
			if (!$.cookie("entryId")) {
				this.getTagAll();
				return false;
			}
			var self = this,
				entries = $.cookie("entryId").split(","),
				api = "/data/entry/",
				ext = ".json";
			this._entries = entries;
			$.map(entries, function(value) {
				self.getEntry(value, ".favorite");
			});
		},
		/**
		 * エントリーjsonから記事情報を取得
		 */
		getEntry: function(apiId, modClass) {
			if (!apiId) {
				return false;
			}

			var self = this,
				module = this.element.find(modClass).find(".entries"),
				apiPath = "/data/entry/",
				apiExt = ".json",
				list = $("<li>"),
				listImg = new Image,
				listP = $("<p>"),
				listLink = $("<a>", { "class": "link", href: "#" }),
				listClose = $("<a>", { "class": "close", href: "#" });
			// closeボタンでデータ削除
			listClose.click(function() {
				list.hideList(function() {
					self.removeCookie(apiId);
				});
				return false;
			});
			// 順序の確定。
			list.hide().appendTo(module)

			$.ajax(apiPath + apiId + apiExt, {
				dataType: "json",
				success: function(result) {
					var entry = result[0];
					listP.html(entry.title);
					listImg.src = entry.imgsrc;
					listLink.attr("href", entry.permalink)
						.attr("target", entry.target || "_self")
						.append(listImg, listP);
					list.data("entryId", apiId)
						.append(listLink, modClass === ".recommend" ? "" : listClose)
						.slideDown(function() {
							// 煙が閉じていたら開ける。
							if (!self._favorite.hasClass("opened")) {
								self._favorite.find(".button").click();
							}
						});
					// タグを連結した後、重複を取り除く。
					self._tags = self._tags.concat(entry.tagIDs);
					self._tags = self._tags.unique();
					// 最終時にタグ一覧取得
					if (++self._count === self._entries.length) {
						self.getTagAll();
					}
				},
				error: function() {
					self.removeCookie(apiId);
				}
			});
			// ツボの使い方
			this.setUserguide();
		},
		/**
		 * タグ一覧からエントリーIDを取得
		 */
		getTagAll: function() {
			var self = this,
				api = "/data/tags.json";
			$.getJSON(api, function(tags) {
				for (var i = self._tags.length; i-- > 0; ) {
					self._tagEntries = self._tagEntries.concat(tags[self._tags[i]]);
				}
				// 重複を除き、中身をシャッフルする。
				self._tagEntries = self._tagEntries.uncover(self._entries).shuffle();
				self.getTagEntry();
			});
		},
		/**
		 * タグから取得したエントリーデータを読み込む
		 */
		getTagEntry: function() {
			var self = this;
			for (var i = 0, len = self._tagEntries.length; i < len && i < 5; i++) {
				self.getEntry(self._tagEntries[i], ".recommend");
			}
		},
		/**
		 * クッキーからエントリーIDを削除
		 */
		removeCookie: function(id) {
			// webkit対策
			this._entries = $.cookie("entryId").split(",");
			// 配列を再作成
			this._entries = $.map(this._entries, function(value) {
				if (value == id) {
					return null;
				} else {
					return value;
				}
			});
			$.cookie("entryId", this._entries, { path: "/", expires: 90 });
			// ページにボタンがある場合は復活させる。
			sstv.buttonTsubo && sstv.buttonTsubo.checkDisabled();
			// ツボの使い方
			this.setUserguide();
		},
		/**
		 * リストを再読込
		 */
		reloadList: function(id) {
			var lists = this._favorite.find("li");
			if (lists.length >= 5) {
				lists.eq(0).hideList();
			}
			sstv.sideTsubo.getEntry(id, ".favorite");
		},
		/**
		 * けむりの開閉
		 */
		toggleSmoke: function() {
			// 開閉ボタン
			this.element.find(".button").unbind("click").click(function() {
				var smoke = $(this).parents(".smoke");
				
				if (smoke.hasClass("opened")) {
					// close
					smoke.find(".entries").slideUp(function() {
						smoke.removeClass("opened");
					});
				} else {
					// open
					smoke.find(".entries").slideDown(function() {
						smoke.addClass("opened");
					});
				}
				return false;
			});
		},
		/**
		 * ツボの使い方
		 * クッキーが空の場合は使い方を表示。
		 */
		setUserguide: function() {
			if ($.cookie("entryId")) {
				this.element.find(".userguide").slideUp();
			} else {
				this.element.find(".userguide").slideDown();
			}
		},
		/**
		 * ツボを落とすかどうかの切替
		 */
		changeDrop: function() {
			var self = this,
				now = new Date();
			// 期限を15分後に設定
			now.setTime(now.getTime() + 15 * 60 * 1000);

			if ($.cookie("isDropped")) {
				this._noDropJar();
			} else {
				this._dropJar();
				$.cookie("isDropped", "true", { path: "/", expires: now });
			}
		},
		// ツボを落とす
		_dropJar: function() {
			var self = this;
			this.element.find(".jar")
				.css("position", "absolute")
				.css("left", 47)
				.css("bottom", $(document).height())
				.show()
				.animate({
					bottom: 0
				}, {
					duration: 2500,
					easing: "easeInQuint",
					complete: function() {
						self._elasticJar();
					}
				});
		},
		// ツボを落とさない
		_noDropJar: function() {
			this.element.find(".jar").show()
			this._elasticJar();
		},
		// ツボはずむ
		_elasticJar: function() {
			var self = this,
				jar = this.element.find(".jar"),
				jarHeight = jar.height();

			this.element.height(jarHeight);

			jar.animate({
				height: jarHeight / 2
			}, {
				duration: 300,
				complete: function() {
					jar.animate({
						height: jarHeight
					}, {
						duration: 1000,
						easing: "easeOutBounce",
						complete: function() {
							// reset
							self.element.height("auto");
							jar.css("position", "relative").css("left", 0);
							// 煙がたなびく
							self.element.find(".smoke").slideDown();
						}
					});
				}
			});
		}
	});

	/**
	 * jQuery object prototype extend
	 */	
	$.fn.extend({
		/**
		 * リストを非表示
		 */
		hideList: function(callback) {
			var callback = callback || function() {};
			this.animate({
				opacity: 0,
				height: 0,
				paddingTop: 0
			}, {
				complete: function() {
					$(this).remove();
					callback();
				}
			});
		}
	});

})(jQuery);


/**
 * prototype extend
 */

/**
 * Array.unique()
 * 配列内の重複を取り除く。
 */
Array.prototype.unique = function() {
	var array = [],
		checks = {};
	for (var i = this.length; i-- > 0; ) {
		if (!(this[i] in checks)) {
			checks[this[i]] = true;
			array.push(this[i]);
		}
	}
	return array;
}

/**
 * Array.uncover(params)
 * 引数で渡した配列と重複している値を削除した配列を返す。
 */
Array.prototype.uncover = function(params) {
	var self = this.unique(),
		array = [],
		_compare = function(a, b) {
			return a - b;
		};
	array = self.sort(_compare).slice(0);  // 比較用にコピー
	params.sort(_compare);
	for (var i = 0, j = 0, len = params.length; i < len; i++) {
		for (var len = array.length; j < len; j++) {
			if (params[i] == array[j]) {
				self.splice(j, 1);
			} else if (params[i] < array[j]) {
				j--;
				break;
			}
		}
	}
	return self;
}

/**
 * Array.shuffle()
 * 配列の値をシャッフルする。
 */
Array.prototype.shuffle = function() {
	var self = this,
		array = [];
	for (var i = this.length; i-- > 0; ) {
		var j = Math.floor(Math.random() * self.length);
		array = array.concat(self.splice(j, 1));
	}
	return array;
}

/**
 * Array.indexOf(obj)
 * 引数で渡したオブジェクトが保持されているインデックス番号を返す。
 * (IEが非対応のため)
 *
	if (!Array.indexOf) {
		Array.prototype.indexOf = function(target) {
			for (var i = 0, len = this.length; i < len; i++) {
				if (this[i] === target) {
					return i;
				}
			}
			// 一致するものが無い場合は-1を返す。
			return -1;
		}
	}
 */


