var $beauty = (function(window) {
	/**  Beauty JavaScript Library  */

	/**
	 * $beautyの名前で公開
	 */
	function Beauty() {};
	/**
	 * URLの正規表現
	 */
	Beauty.URL_PATTERN = /^http[s]?:\/\/.+/;

	/**
	 * AJAXデフォルト通信設定
	 * $.ajax関数をコールする場合には本設定を利用します
	 */
	Beauty.AJAX_DEFAULT_SETTINGS = {
		cache : false,
		type : "POST",
		timeout : 10000,
		async : true,
		contentTypeString : 'application/x-www-form-urlencoded',
		success : function(data, textStatus, req) {
			if (!Beauty.fn.alertIfAjaxError(data)) {
				$(this).html(data);
			}
		},
		error : function(req, textStatus, errorThrown) {
			alert("通信に失敗しました");
		}
	};

	/**
	 * 非同期で通信を行う。（リンククリック時）
	 * 引数に設定するコールバック関数は以下シグネチャである必要があります。
	 * <ul>
	 * <li>第1引数：JSON結果オブジェクト</li>
	 * <li>第2引数：書き換えられる領域を囲むタグのid属性値</li>
	 * </ul>
	 * @param {string} url 非同期通信を行うサーバURL
	 * @param {object} params クエリパラメータ
	 * @param {string} targetAreaId 書き換えられる領域を囲むタグのid属性値
	 * @param {function} func 通信成功時に実行するコールバック関数
	 */
	Beauty.prototype.asyncLink = function(url, params, targetAreaId, func) {
	    $.getJSON(url, params, function(json) {
	    	func(json, targetAreaId);
	    });
	};

	/**
	 * 2重押しチェックフラグ
	 */
	var doubleClickCheck;
	/**
	 * 2重押し判定用オブジェクト
	 */
	var DoubleClick = function () {
	    var id = 0;
	    var isLock = false;
	    this.setLock = function () {
            isLock = true;
        };
        this.isLocked = function () {
            return isLock;
        };
        this.clear = function (ele) {
            $(ele).attr("disabled", false);
            isLock = false;
        };
        this.getId = function () {
            return id;
        };
        this.cancel = function() {
        	isLock = false;
        };
	};

	/**
	 * 2重押しチェックをキャンセル（ロック解除）する
	 */
	function cancelDoubleClickCheck() {
		if (doubleClickCheck && doubleClickCheck.isLocked()) {
			doubleClickCheck.cancel();
		}
	};

	// ======================================================================
	// 2重押しチェック
	// ==============
	/**
	 * 2重押しチェックを行う
	 * 2重押しチェック間隔は3秒間それ以上経過すると、再度遷移可能になる
	 * @return 2重押しの場合にfalse、問題なければtrueを返す
	 */
	Beauty.prototype.checkDoubleClick = function() {
		doubleClickCheck = new DoubleClick();
	    $("input[type='submit']").click(function () {
	        if (doubleClickCheck.isLocked()) {
	            return false;
	        }
	        doubleClickCheck.setLock();

	        setTimeout(
	        	function() {
	        		cancelDoubleClickCheck();
	        	}, 3000);
	        return true;
	    });
	};

	/**
	 * テキストボックスでEnterキーが押下された際、submitを抑止する
	 */
	Beauty.prototype.preventEnterKeySubmit = function() {
		$("input[type='text']").bind("keydown.preventEnterKeySubmit", function(e) {
			if (e.which === 13) {
				return false;
			}
		});
	};

	/**
	 * パスワードでEnterキーが押下された際、submitを抑止する
	 */
	Beauty.prototype.preventEnterKeyPasswdSubmit = function() {
		$("input[type='password']").bind("keydown.preventEnterKeyPasswdSubmit", function(e) {
			if (e.which === 13) {
				return false;
			}
		});
	};

	// ======================================================================
	// ダイアログ
	// ==============
	/**
	 * 確認ダイアログを表示する
	 * @param {string} clickableId ボタン、リンクのid属性値
	 * @param {string} message 表示するメッセージ(オプション)
	 */
	Beauty.prototype.confirm = function(clickableId, message) {
		$(Beauty.fn.idSelector(clickableId)).click(function() {
			var msg = message || "作業を継続しますよろしいですか？";
			return window.confirm(msg);
		});
	};

	/**
	 * 警告ダイアログを表示する
	 * @param {string} clickableId ボタン、リンクのid属性値
	 * @param {string} message 表示するメッセージ(オプション)
	 */
	Beauty.prototype.alert = function(clickableId, message) {
		$(Beauty.fn.idSelector(clickableId)).click(function() {
			var msg = message || "作業を継続できません";
			return window.alert(msg);
		});
	};

	// ======================================================================
	// 反映
	// ==============
	/**
	 * リンククリック時に指定されたhiddenの値を書き換える
	 * @param {string} linkId 	クリックされるリンクのid属性値
	 * @param {string} hiddenId 値を書き換えるhiddenのid属性値
	 * @param {string} val 		hiddenに設定する値
	 */
	Beauty.prototype.rewriteHiddenValue = function(linkId, hiddenId, val) {
		$(Beauty.fn.idSelector(linkId)).bind("click.rewriteHidden", function() {
			$(Beauty.fn.idSelector(hiddenId)).val(val);
			return false;
		});
	};

	/**
	 * ボタン(リンク)クリック時に、子画面の値（チェックボックス）を親画面の指定されたフィールドに反映
	 * 反映後、子画面（自身）を閉じる
	 * 規約として、メッセージ反映先タグのid属性値の兄弟タグ（SPAN ID属性あり）があり、そちらにデフォルト
	 * メッセージが表示されているようなタグ構造である必要があります。
	 * ○検索結果一覧のこだわり条件／エリア選択時（ポップアップ）にこの関数を呼び出します
	 * @param {string} attachButtonId 	反映ボタン(リンク)のid属性値
	 * @param {string} reflectItemName 	反映先フィールドのname属性値
	 * @param {string} reflectMsgId 	メッセージ反映先タグのid属性値
	 * @param {boolean} areaFlg 	エリア選択画面から呼ばれているかどうか(オプション)
	 */
	Beauty.prototype.attachTemplateOnClose = function(attachButtonId, reflectItemName, reflectMsgId, areaFlg) {
		$(Beauty.fn.idSelector(attachButtonId)).bind("click.attachTemplate", function() {
			var idVal;
			var message = "";
			var checkerCount = 0;
			var $target;
			var labelText;
			var parent = window.opener;
			if (!parent || typeof parent.document !== 'object') {
				alert("親画面が存在しません");
				return false;
			}

			$target = $("form", parent.document); // 親ウィンドウのformタグ
			// 対象のhidden値を初期化（削除）
			$(Beauty.fn.inputNameSelector(reflectItemName), $target).remove();
			var $checker = $("input[type='checkbox']").filter(":checked");
			$checker.each(function(i) {
				idVal = $(this).attr("id");
				if (i > 0) {
					message = message + ", ";
				}

				labelText = $("label[for='"+ idVal +"']").text();
				if (areaFlg) {
					// エリア選択時、チェックボックスのラベルからファセット件数を取り除く
					labelText = trimFacetCount(labelText);
				}
				message = message + $.trim(labelText);
				// hiddenタグを作成
				$(parent.document.createElement("input"))
					.attr({
						type: "hidden",
						name: reflectItemName,
						value: idVal
					}).appendTo($target);
				checkerCount++;
			});

			if (areaFlg) {
				if (checkerCount === 0) {
					$(Beauty.fn.idSelector(reflectMsgId), parent.document).html("<strong>すべて</strong>");
				}
			} else {
				if (checkerCount === 0) {
					$(Beauty.fn.idSelector(reflectMsgId), parent.document).text("");
				}
			}
			if (checkerCount > 0) {
				$(Beauty.fn.idSelector(reflectMsgId), parent.document).text(message);
			}
			window.close();
			return false;
		});
	};

	/**
	 * リンククリック（スタイル選択）時、以下の処理を行います。
	 * <ul>
	 * <li>親画面の指定項目を上書く</li>
	 * <li>親画面の画像を選択した画像に差し替える</li>
	 * <li>親画面の画像横に「イメージを削除する」リンクを表示（活性化）</li>
	 * <li>ウィンドウ（子画面）をクローズ</li>
	 * </ul>
	 * またタグは以下の構成になっている必要があります。
	 * <ul>
	 * <li>スタイル画像番号ID属性値が設定されたタグのボディ＝スタイル名に設定する内容</li>
	 * <li>スタイル画像番号ID属性値が設定されたタグはクリックされたAタグと兄弟関係（次の要素）</li>
	 * </ul>
	 * @param {object} $target クリックされた対象のセレクタ（jQueryオブジェクト）
	 * @param {string} deleteImgId イメージ削除リンクの親タグID属性値
	 * @param {string} favoriteStyleImgId 画像差し替え先の親要素ID
	 * @param {string} destStyleIdName 反映先フィールドのname属性値（なりたいスタイルID）
	 * @param {string} destStyleImageName 反映先フィールドのname属性値（なりたいスタイル画像名）
	 * @param {string} destStyleName 反映先フィールドのname属性値（なりたいスタイル名）
	 */
	Beauty.prototype.attachAndSwitchImageOnClose = function($target, deleteImgId, favoriteStyleImgId, destStyleIdName, destStyleImageName, destStyleName) {
		// 親ウィンドウ取得
		var parent = window.opener;
		if (!parent || typeof parent.document !== 'object') {
			alert("親画面が存在しません");
			return false;
		}

		var linkId = $target.attr("id");
		var $linkSiblingTag = $target.next();
		var styleImageId = $linkSiblingTag.attr("id");
		var styleName = $linkSiblingTag.text();
		// 親ウィンドウのformタグ
		var $parentForm = $("form", parent.document);
		var $imgChangeArea = $(Beauty.fn.idSelector(favoriteStyleImgId), parent.document);
		var $targetImage = $("img[src*="+ styleImageId +"]");
		var targetImageHeight = $targetImage.attr("height");
		var targetImageWidth = $targetImage.attr("width");
		var targetImageAlt = $targetImage.attr("alt");
		var targetImageSrc = $targetImage.attr("src");
		$(Beauty.fn.inputNameSelector(destStyleIdName), $parentForm).val(linkId);
		$(Beauty.fn.inputNameSelector(destStyleImageName), $parentForm).val(styleImageId);
		$(Beauty.fn.inputNameSelector(destStyleName), $parentForm).val(styleName);
		// 削除リンク表示
		$(Beauty.fn.idSelector(deleteImgId), parent.document).show();
		// 画像を差し替え
		$imgChangeArea.find("div").hide();
		$("img", $imgChangeArea).remove();
		$(parent.document.createElement("img"))
			.attr({
				height: targetImageHeight,
				width: targetImageWidth,
				alt: targetImageAlt,
				src: targetImageSrc
			}).appendTo($imgChangeArea);
		// ウィンドウクローズ
		window.close();
	};

	/**
	 * 反映後に置換するタグ名
	 */
	var DEFAULT_REPLACE_TAGNAME = {
		tagName : "strong"
	};

	/**
	 * リンククリック時に、ID値で対象の入力項目の値を上書きする。
	 * 
	 * @param {object} $target クリックされた対象のセレクタ（jQueryオブジェクト）
	 * @param {string} reflectItemName 	反映先フィールドのname属性値
	 */
	Beauty.prototype.attachLinkId = function($target, reflectItemName) {
		var linkId = $target.attr("id");
		if (!linkId || linkId === "") {
			$(Beauty.fn.inputNameSelector(reflectItemName)).val("");
		} else {
			$(Beauty.fn.inputNameSelector(reflectItemName)).val(linkId);
		}
	};

	/**
	 * リンククリック時に、ID値で対象の入力項目の値を上書きする。
	 * 反映後、クリックされた要素は指定のタグに置き換えます。
	 * 
	 * @param {object} $target クリックされた対象のセレクタ（jQueryオブジェクト）
	 * @param {string} reflectItemName 	反映先フィールドのname属性値
	 * @param {object} tagNameSetting リンククリック時、置換する（ラップし直す）タグ名（オプション）
	 */
	Beauty.prototype.attachLinkIdAfterLabel = function($target, reflectItemName, tagNameSetting) {
		var replaceTagName = $.extend({}, DEFAULT_REPLACE_TAGNAME, tagNameSetting);
		var $siblingLabelTag = $target.siblings(replaceTagName.tagName);
		var linkId = $target.attr("id");
		var startTag;
		if (!linkId || linkId === "") {
			startTag = "<" + replaceTagName.tagName + ">";
			$(Beauty.fn.inputNameSelector(reflectItemName)).val("");
		} else {
			startTag = "<" + replaceTagName.tagName + " id='"+ linkId +"'>";
			$(Beauty.fn.inputNameSelector(reflectItemName)).val(linkId);
		}
		var endTag = "</" + replaceTagName.tagName + ">";

		if ($siblingLabelTag) {
			// 兄弟タグを全てリンクに変更
			var $siblingLabelTagId = $siblingLabelTag.attr("id");
			if (!$siblingLabelTagId || $siblingLabelTagId === "") {
				$siblingLabelTag.replaceWith("<a href='javascript:void(0);'>" + $siblingLabelTag.text() + "</a>");
			} else {
				$siblingLabelTag.replaceWith("<a href='javascript:void(0);' id='"+ $siblingLabelTagId +"'>" + $siblingLabelTag.text() + "</a>");
			}
		}
		$target.replaceWith(startTag + $target.text() + endTag);
	};

	/**
	 * メニューカテゴリ反映設定
	 */
	var DEFAULT_MENU_CATEGORYS = {
		MC01 : "カット",
		MC02 : "カラー",
		MC03 : "パーマ",
		MC04 : "縮毛矯正",
		MC05 : "エクステンション",
		MC06 : "トリートメント",
		MC07 : "その他メニュー"
	};
	/** メニューカテゴリCDの文字数 */
	var MENU_CATEGORY_CD_LENGTH = 4;

	/**
	 * キレイ　メニューカテゴリ反映設定
	 */
	var DEFAULT_KIREI_MENU_CATEGORYS = {
		MENU_LIST : [
			{categoryCd : "MC01",
			 categoryName : "ボディトリートメント",
			 genreCd : "GR01"},
			{categoryCd : "MC02",
			 categoryName : "ボディケア",
			 genreCd : "GR01"},
			{categoryCd : "MC03",
			 categoryName : "足裏・リフレクソロジー",
			 genreCd : "GR01"},
			{categoryCd : "MC04",
			 categoryName : "ヘッド",
			 genreCd : "GR01"},
			{categoryCd : "MC05",
			 categoryName : "その他",
			 genreCd : "Other"},
			{categoryCd : "MC06",
			 categoryName : "整体",
			 genreCd : "GR02"},
			{categoryCd : "MC07",
			 categoryName : "カイロプラクティック",
			 genreCd : "GR02"},
			{categoryCd : "MC08",
			 categoryName : "骨盤・美容矯正",
			 genreCd : "GR02"},
			{categoryCd : "MC09",
			 categoryName : "O脚・X脚矯正",
			 genreCd : "GR02"},
			{categoryCd : "MC10",
			 categoryName : "小顔矯正",
			 genreCd : "GR02"},
			{categoryCd : "MC11",
			 categoryName : "その他",
			 genreCd : "Other"},
			{categoryCd : "MC12",
			 categoryName : "岩盤浴・溶岩浴・ゲルマ温浴",
			 genreCd : "GR03"},
			{categoryCd : "MC13",
			 categoryName : "スパ・温浴施設",
			 genreCd : "GR03"},
			{categoryCd : "MC14",
			 categoryName : "酸素カプセル・酸素バー",
			 genreCd : "GR03"},
			{categoryCd : "MC15",
			 categoryName : "その他",
			 genreCd : "Other"},
			{categoryCd : "MC16",
			 categoryName : "ケアカラー",
			 genreCd : "GR04"},
			{categoryCd : "MC17",
			 categoryName : "ジェル",
			 genreCd : "GR04"},
			{categoryCd : "MC18",
			 categoryName : "スカルプ",
			 genreCd : "GR04"},
			{categoryCd : "MC19",
			 categoryName : "フット",
			 genreCd : "GR04"},
			{categoryCd : "MC20",
			 categoryName : "アート",
			 genreCd : "GR04"},
			{categoryCd : "MC21",
			 categoryName : "その他",
			 genreCd : "Other"},
			{categoryCd : "MC22",
			 categoryName : "アイビューティー",
			 genreCd : "GR05"},
			{categoryCd : "MC23",
			 categoryName : "ヘア＆メイク・着付け",
			 genreCd : "GR05"},
			{categoryCd : "MC24",
			 categoryName : "その他",
			 genreCd : "Other"},
			{categoryCd : "MC25",
			 categoryName : "フェイシャル",
			 genreCd : "GR06"},
			{categoryCd : "MC26",
			 categoryName : "ボディ",
			 genreCd : "GR06"},
			{categoryCd : "MC27",
			 categoryName : "脱毛",
			 genreCd : "GR06"},
			{categoryCd : "MC28",
			 categoryName : "バストケア",
			 genreCd : "GR06"},
			{categoryCd : "MC29",
			 categoryName : "ブライダルメニュー",
			 genreCd : "GR06"},
			{categoryCd : "MC30",
			 categoryName : "その他",
			 genreCd : "Other"}
		]
	};

	/** 予約・メニュー選択画面のチェックボックスID属性値プレフィックス */
	var RESERVE_CHECKBOX_ID_PREFIX = "menu";

	// ======================================================================
	// チェックボックス
	// ==============
	/**
	 * メニューで選択された施術時間を計算し、選択済みクーポンの施術時間に加算します。
	 * デザインは以下の規約に沿っている必要があります。
	 * チェックボックスのID属性値の命名ルール「menu + メニューカテゴリCD + シーケンス」
	 *
	 * @param {string} durationProcedureId 施術時間のID属性値。命名ルールは末尾がシーケンス。
	 * @param {string} menuContentId メニューのID属性値。命名ルールは末尾がシーケンス。
	 * @param {string} resultTableId 計算結果を表示するテーブル（TBODY）のID属性値。
	 * @param {string} selectedCouponAreaId 選択済みクーポンの施術時間（TD）のID属性値。
	 * @param {string} totalTimeId 計算結果を表示するTDタグのID属性値。
	 * @param {boolean} isBiyou 美容かどうか。true：美容, false：キレイ
	 * @param {boolean} isAppend 追加メニューかどうか。（オプション）true：追加メニュー, false：メニュー
	 */
	Beauty.prototype.calcDurationProcedure = function(durationProcedureId, menuContentId, resultTableId, selectedCouponAreaId, totalTimeId, isBiyou, isAppend) {
		$("input[type='checkbox']").bind("click.calcDurationProcedure", function() {
			var checkId;
			var seq;
			var menuCategoryCd;
			var menuContent;
			var minutes;
			var hour;
			var minute;
			var dispAllTime;
			var tmpCouponTime;
			var couponTime = 0;
			var allTime = 0;
			var menuSelected = false;
			var tmpRowspan = 1;
			var kireiMenu = {};
			var $resultTableTd = $(Beauty.fn.idSelector(resultTableId) + " td");
			if ($resultTableTd.is("[id^='addTd']")) {
				$resultTableTd.filter("[id^='addTd']").parent().remove();
			}

			$(":checked").each(function() {
				checkId = $(this).attr("id");
				// チェックボックスのID属性値から、シーケンス、メニューカテゴリCDを取得
				seq = checkId.slice((RESERVE_CHECKBOX_ID_PREFIX.length + MENU_CATEGORY_CD_LENGTH), checkId.length);
				menuCategoryCd = checkId.slice(RESERVE_CHECKBOX_ID_PREFIX.length, RESERVE_CHECKBOX_ID_PREFIX.length + MENU_CATEGORY_CD_LENGTH);
				minutes = $(Beauty.fn.idSelector(durationProcedureId) + seq).text();
				minute = minutes.slice(0, minutes.length - 1);
				allTime = allTime + (minute - 0);
				menuContent = "<tr id='addTr"+ seq +"'><td id='addTdLeft"+ seq +"'>";
				if (isBiyou) {
					menuContent = menuContent + "<span class='couponMenuIcon pV1 pH10 fgWhite fs10 dib'>"+ DEFAULT_MENU_CATEGORYS[menuCategoryCd] +"</span>";
				} else {
					// キレイの場合、ジャンルCDも別途取得する
					$.each(DEFAULT_KIREI_MENU_CATEGORYS.MENU_LIST, function(i) {
			    		kireiMenu = DEFAULT_KIREI_MENU_CATEGORYS.MENU_LIST[i];
			    		if (kireiMenu.categoryCd === menuCategoryCd) {
			    			return false;
						}
			    	});
					menuContent = menuContent + "<span class='couponMenuIcon"+ kireiMenu.genreCd +" pV1 pH10 fgWhite fs10 dib'>"+ kireiMenu.categoryName +"</span>";
				}
				menuContent = menuContent + "<span class='fgRbrown mL5'>"+ $(Beauty.fn.idSelector(menuContentId) + seq).text() +"</span>";
				menuContent = menuContent + "</td><td id='addTdRight"+ seq +"'>"+ minutes +"</td></tr>";
				$(menuContent).appendTo(Beauty.fn.idSelector(resultTableId));
				menuSelected = true;
				tmpRowspan++;
			});

			if (!menuSelected) {
				if (isAppend && typeof isAppend === "boolean") {
					$("<td>追加メニューが選択されていません。</td><td>&nbsp;</td>").appendTo(Beauty.fn.idSelector("jsAddMenuBaseTr"));
				} else {
					$("<td>メニューが選択されていません。</td><td>&nbsp;</td>").appendTo(Beauty.fn.idSelector("jsAddMenuBaseTr"));
				}
			} else {
				$(Beauty.fn.idSelector("jsAddMenuBaseTr") + " td").remove();
			}
			$(Beauty.fn.idSelector("jsAddMenuBaseTr") + " th[rowSpan]").attr("rowSpan", tmpRowspan);
			// 総施術時間の計算
			tmpCouponTime = $(Beauty.fn.idSelector(selectedCouponAreaId)).text();
			if (tmpCouponTime && $.trim(tmpCouponTime) !== "") {
				tmpCouponTime = tmpCouponTime.replace("分", "");
				couponTime = tmpCouponTime - 0;
				allTime = (!isNaN(couponTime)) ? allTime + couponTime : allTime ;
			}
			hour = Math.floor(allTime / 60);
			minute = allTime % 60;
			dispAllTime = (hour < 1) ? "" : hour +"時間" ;
			dispAllTime = (minute === 0) ? dispAllTime : dispAllTime + minute +"分" ;
			dispAllTime = (dispAllTime === "" ) ? " " : dispAllTime;
			$(Beauty.fn.idSelector(totalTimeId)).text(dispAllTime);
		});
	};

	/**
	 * 選択したスタイリストとその他のスタイリストの表示を切り替えます。
	 * （デザイン会社納品ソースをjQueryにポーティング）
	 *
	 * @param {string} stylistTabId スタイリストタブのID属性値
	 * @param {string} otherStylistTabId 他のスタイリストID属性値
	 * @param {string} otherStylistCnt 他のスタイリスト数
	 */
	Beauty.prototype.changeStylist = function(stylistTabId, otherStylistTabId, otherStylistCnt) {
		$(Beauty.fn.idSelector(stylistTabId)).bind("click.changeStylist", function() {
			if ($(Beauty.fn.idSelector(otherStylistTabId)).hasClass("reserveDateTabOn")) {
				$(Beauty.fn.idSelector(otherStylistTabId)).removeClass("reserveDateTabOn");
			}
			$(Beauty.fn.idSelector(otherStylistTabId)).addClass("rsvS reserveDateTabOff");
			if ($(this).hasClass("reserveDateTabOff")) {
				$(this).removeClass("reserveDateTabOff");
			}
			$(this).addClass("rsvS reserveDateTabOn");
			$(Beauty.fn.idSelector(otherStylistCnt)).hide();
		});

		$(Beauty.fn.idSelector(otherStylistTabId)).bind("click.otherStylist", function() {
			if ($(Beauty.fn.idSelector(stylistTabId)).hasClass("reserveDateTabOn")) {
				$(Beauty.fn.idSelector(stylistTabId)).removeClass("reserveDateTabOn");
			}
			$(Beauty.fn.idSelector(stylistTabId)).addClass("rsvS reserveDateTabOff");
			if ($(this).hasClass("reserveDateTabOff")) {
				$(this).removeClass("reserveDateTabOff");
			}
			$(this).addClass("rsvS reserveDateTabOn");
			$(Beauty.fn.idSelector(otherStylistCnt)).show();
		});

		$("#jsStylistWrap a").bind("click.otherStylistA", function() {
			$("#jsStylistName").html($(this).html());
			var currentStylist = $("#jsCurrentStylist");
			currentStylist.parent().html("<a href='javascript:void(0);' title='" + currentStylist.text() + "'>" + currentStylist.text() + "</a>");
			$(this).parent().html("<span title='" + $(this).text() + "' id='" + currentStylist.attr("id") + "' class='fgLGray'>" + $(this).text() + "</span>");

			$("#jsRsvCdTbl").show();
			$(Beauty.fn.idSelector(stylistTabId)).addClass("rsvS reserveDateTabOn");
			$(Beauty.fn.idSelector(otherStylistTabId)).addClass("rsvS reserveDateTabOff");
			$(Beauty.fn.idSelector(otherStylistCnt)).hide();
		});
	};

	/**
	 * 利用可能ポイントからプルダウンで選択された利用ポイントを減算し、支払い予定金額に反映します。
	 * 
	 * @param {string} selectedPointId 	利用するポイント（プルダウン）のID属性値
	 * @param {string} usePointId 	利用可能ポイント（減算対象）タグのID属性値
	 * @param {string} reflectPointId 	支払い予定金額タグのID属性値
	 */
	Beauty.prototype.recalcEnablePoint = function(selectedPointId, usePointId, reflectPointId) {
		$(Beauty.fn.idSelector(selectedPointId)).bind("change.recalcEnablePoint", function() {
			// 減算した結果のポイント数
			var result;
			var resultText;
			// 利用ポイント
			var tmpSelectedPoint = $(this).val();
			var selectedPoint = tmpSelectedPoint - 0;
			// 現在の利用可能ポイント
			var tmpUsePoint = $(Beauty.fn.idSelector(usePointId)).text();
			tmpUsePoint = unFormatNumber(tmpUsePoint);
			var usePoint = tmpUsePoint - 0;
			if ((!usePoint || isNaN(usePoint)) || isNaN(selectedPoint)) {
				// 引数のID指定されたタグのコンテンツのいずれかが数値ではない場合、処理終了
				return false;
			}
			result = usePoint - selectedPoint;
			resultText = "&yen;" + formatNumber(result);
			// 減算結果を支払い予定金額に反映
			$(Beauty.fn.idSelector(reflectPointId)).html(resultText);
		});
	};

	// ======================================================================
	// Functions
	// ==============
	/**
	 * 【Beauty.fn】汎用的なFunctionを定義
	 */
	Beauty.fn = Beauty.prototype.fn = {
		/**
		 * id属性値からセレクタを返す
		 */
		idSelector : function(id) {
			return "#" + id;
		},

		/**
		 * クラス属性値からセレクタを返す
		 */
		classSelector : function(className) {
			return "." + className;
		},

		/**
		 * inputのname値からセレクタを返す
		 */
		inputNameSelector : function(name) {
			return "input[name='" + name + "']";
		},

		/**
		 * 値を数値として返す。数値に変換できない場合はnullを返す
		 * @param val 変換元の値
		 */
		num : function(val) {
			if (!val || isNaN(val)) {
				return null;
			} else {
				return val - 0;
			}
		},

		/**
		 * input部品の値を保存する
		 * id属性が指定されていない場合は保存しない
		 * @param {string} (オプション) formId 対象のinput部品が属するFormのid
		 */
		saveInput : function(formId) {
			var $form, $context;
			if (formId) {
				$form = $(this.idSelector(formId));
				$context = $("input,select,textarea", $form);
			} else {
				$context = $("input,select,textarea").not(":file,:submit,:image");
			}

			var func = this;
		    $context.each(function () {
		    	if (!this.id) {
		    		return true;
		    	}
				var $self = $(this);
				if (hasCheckedValue($self)) {
					var checkedValue = $self.attr("checked");
					$self.data(this.id, checkedValue);
				} else {
			    	var val = $self.val();
			        $self.data(this.id, val);
				}
		    });
		},

		/**
		 * 指定されたclass属性を持つinput部品の値を保存する
		 * チェックボックス、ラジオボタンについては、チェックされているかどうかを保存する
		 * 対象のinput部品は、id属性が必須
		 * @param {string} targetClass 対象のinput部品に共通するclass属性値
		 */
		saveInputByClass : function(targetClass) {
			var $context = $("input,select,textarea").filter("." + targetClass).not(":file,:submit,:image");
			var func = this;
		    $context.each(function () {
				var $self = $(this);
		    	if (!$self.attr("id")) {
		    		$self.attr("id", "savedInputByClass" + new Date().getTime());
		    	}
				if (hasCheckedValue($self)) {
					$self.data($self.attr("id"), $self.attr("checked"));
				} else {
			    	var val = $self.val();
			        $self.data($self.attr("id"), val);
				}
		    });
		},

		/**
		 * input部品が編集されたことを記憶する
		 * @param {string} (オプション) formId 対象のinput部品が属するFormのid属性値
		 */
		saveEdited : function(formId) {
			var $form, $context;
			if (formId) {
				$form = $(this.idSelector(formId));
				$context = $("input,select,textarea", $form);
			} else {
				$context = $("input,select,textarea");
			}

			$context.change(function () {
		        $(this).data(this.id + "Edited", true);
		    });
		},

		/**
		 * チェック状態にする
		 * @param {string} id属性値
		 */
		check : function(id) {
			$(this.idSelector(id)).attr("checked", true);
		},

		/**
		 * ポップアップウィンドウを新規に作成する
		 * 自由にカスタマイズしたいとき向け
		 * @param settings 設定
		 * @return ポップアップクラスのインスタンス
		 */
		createPopup : function(settings) {
			return new Popup(settings);
		},

		/**
		 * disabled設定可能な部品を非活性化する
		 * @param targetId ターゲットID
		 */
		disable : function(targetId) {
			var $target = $(this.idSelector(targetId));
			$target.attr("disabled", true);
		},

		/**
		 * disabled設定可能な部品をすべて非活性化する
		 * @param targetClass ターゲットCLASS
		 */
		disableAll : function(targetClass) {
			var $targets = $(this.classSelector(targetClass));
			$targets.attr("disabled", true);
		},

		/**
		 * disabled設定可能な部品を活性化する
		 * @param targetId ターゲットID
		 */
		enable : function(targetId) {
			var $target = $(this.idSelector(targetId));
			$target.attr("disabled", false);
		},

		/**
		 * disabled設定可能な部品をすべて非活性化する
		 * @param targetClass ターゲットCLASS
		 */
		enableAll : function(targetClass) {
			var $targets = $(this.classSelector(targetClass));
			$targets.attr("disabled", false);
		},

		/**
		 * リンクを非活性化する
		 * @param linkId リンクのID
		 */
		disableLink : function(linkId) {
			var $a = $(this.idSelector(linkId));
			$a.data("disabled", true);
			$a.bind("click.capability", function() {
				return false;
			});
		},

		/**
		 * リンクを活性化する
		 * @param linkId リンクのID
		 */
		enableLink : function(linkId) {
			var $a = $(this.idSelector(linkId));
			$a.data("disabled", false);
			$a.unbind("click.capability");
		},

		/**
		 * input部品のうち、サブミット時に除外されるtype属性であればtrueを返す
		 * @param type input部品
		 */
		isExcludeType : function(type) {
			return type === "file" || type === "submit" || type === "button" || type === "reset" || type === "image";
		},

		/**
		 * 文字列をHTMLサニタイジングします。
		 * @param str 文字列
		 */
		escape : function(str) {
			return str.replace("&", "&amp;")
						.replace("<", "&lt;")
						.replace(">", "&gt;");
		},

		/**
		 * 非同期通信でvalidateエラーになった場合は、アラートでメッセージを表示する
		 * システムエラーの場合は、元画面をエラー画面へ遷移させる
		 * @param data データ
		 */
		alertIfAjaxError : function(data) {
			var status = $(data).attr("id");
			if (status === "ajaxSystemError") {
				var url = $(data).attr("url");
				window.location.href = url;
				return true;
			} else if (status === "ajaxMsgError") {
				var message = "";
				$("li", $(data)).each(function(){
					message += $(this).text() + "\n";
				});
				alert(message);
				return true;
			}
			return false;
		}
	};

	/**
	 * 入力部品かどうか判別する
	 * 入力部品の場合にtrueを返す
	 * @param {jquery} jQueryオブジェクト
	 */
	function hasValue($obj) {
		return $obj.is("input,textarea,select");
	};

	/**
	 * チェック部品かどうか判別する
	 * チェックボックス・ラジオボタンの場合にtrueを返す
	 * @param {jquery} jQueryオブジェクト
	 */
	function hasCheckedValue($obj) {
		return $obj.is("input[type='checkbox'],input[type='radio']");
	};

	/**
	 * 1000桁区切り(カンマ)を取り除く。
	 * @param input カンマ区切りの金額
	 */
	function unFormatNumber(input) {
		return input.toString().replace(/,/g, "");
	};

	/**
	 * 数値を1000桁区切り(カンマ)の文字列に書式設定する。
	 * @param input 数値
	 */
	function formatNumber(input) {
	    var output = input.toString();
	    output = unFormatNumber(output);
	    output = output.replace(/(\d{1,3})(?=(\d{3})+(?!\d))/g, "$1,");
	    return output;
	};

	/**
	 * 文字列からファセット件数の箇所を取り除く。
	 * @param input 文字列
	 */
	function trimFacetCount(input) {
	    var output = input.toString();
	    output = output.replace(/[(][0-9]+[)]/g, "");
	    return output;
	};

	/**
	 * 値を取得する
	 * <ul>
	 * <li>チェックボックス、ラジオボタンはチェックされていればtrueを返す</li>
	 * <li>他のinput部品はvalueを返す</li>
	 * <li>input部品ではない場合は、表示文字列を返す</li>
	 * </ul>
	 * @param {string} $target セレクタ
	 * @return チェック状態、値、表示文字列のいずれか
	 */
	function getValue($target) {
		var val;
		if (hasCheckedValue($target)) {
			val = $target.attr("checked");
		} else if (hasValue($target)) {
			val = $target.val();
		} else {
			val = $target.text();
		}
		return val;
	};

	// ======================================================================
	// ポップアップウィンドウ
	// ==============
	var DEFAULT_WINDOW_SETTINGS = {
		url : "about:blank",
		name : "child",
		location : "yes",
		resizable : "yes",
		status : "yes",
		menubar : "yes",
		scrollbars : "yes",
		width : 630,
		height : 600,
		left : 0,
		top : 0,
		dependent : "no",
		directories : "no",
		action : null,
		toolbar : "yes",
		rootFormId : null,
		closeOnUnload : false
	};

	/**
	 * リンククリックでポップアップ画面を表示する
	 * onclickイベントのバインド対象となる<a>タグのid属性値を引数にとる
	 *
	 * @param {string} linkId <a>タグのid属性値
	 * @param {object} properties windowの追加設定（オプション）
	 * @return false 画面遷移を行わない
	 */
	Beauty.prototype.linkPopup = function(linkId, properties) {
		var settings = $.extend({}, DEFAULT_WINDOW_SETTINGS, properties);
		$(Beauty.fn.idSelector(linkId)).click(function() {
			var popup = Beauty.fn.createPopup(settings);
			popup.data(settings);
			var win = popup.open();
			if (settings.closeOnUnload) {
				closeWindowOnUnload(win);
			}
			return false;
		});
	};

	/**
	 * リンククリックでポップアップ画面を表示し、引数で指定した親画面のプロパティ値を
	 * 子画面のチェックボックスに反映する。
	 *
	 * @param {string} linkId <a>タグのid属性値
	 * @param {object} properties windowの追加設定（オプション）
	 * @param {string} reflectItemName 	チェックボックスに反映するinputのname属性値
	 * @return false 画面遷移を行わない
	 */
	Beauty.prototype.linkPopupReflectCheckbox = function(linkId, properties, reflectItemName) {
		var settings = $.extend({}, DEFAULT_WINDOW_SETTINGS, properties);
		var actionPath;
		$(Beauty.fn.idSelector(linkId)).bind("click.linkPopupReflect", function() {
			if (!actionPath || actionPath.length === 0) {
				actionPath = settings.url;
			}
			var $reflectItemName = $(Beauty.fn.inputNameSelector(reflectItemName));
			var reflectItemId;
			var queryParams = "";
			if ($reflectItemName) {
				$reflectItemName.each(function(i) {
    				reflectItemId = $(this).val();
    				if (i === 0) {
    					queryParams = "?" + reflectItemName + "=" + reflectItemId;
    				} else {
    					queryParams = queryParams + "&" + reflectItemName + "=" + reflectItemId;
    				}
				});
			}
			settings.url = actionPath + queryParams;
			var popup = Beauty.fn.createPopup(settings);
			popup.open();
			return false;
		});
	};

	/**
	 * リンククリックでポップアップ画面を表示する(動的にリンクの数が変わる場合用)
	 * onclickイベントのバインド対象となる<a>タグのclass属性値を引数にとる
	 * @param {string} linkClass <a>タグのclass属性値
	 * @param {object} properties windowの追加設定（オプション）
	 * @return false 画面遷移を行わない
	 */
	Beauty.prototype.linksPopup = function(linkClass, properties) {
		var settings = $.extend({}, DEFAULT_WINDOW_SETTINGS, properties);
		$(Beauty.fn.classSelector(linkClass)).bind("click.linksPopup", function() {
			var popup = Beauty.fn.createPopup(settings);
			popup.data(settings);
			var win = popup.open();
			if (settings.closeOnUnload) {
				closeWindowOnUnload(win);
			}
			return false;
		});
	};

	function closeWindowOnUnload(win) {
		$(win.opener).unload(function() {
			win.close();
		});
	};

	/**
	 * ポップアップオブジェクト
	 * window一つにつき、新たにインスタンスを生成する
	 * settings: ポップアップウィンドウの設定値
	 */
	var Popup = function(settings) {
		var config = settings;
		/**
		 * 追加設定を行う
		 * @param {string} key 設定用キー
		 * @param {object} value 設定値
		 */
		this.put = function(key, value) {
			config[key] = value;
		};

		/**
		 * 追加設定を行う
		 * 引数が存在しない、またはObjectでない場合は何もしない
		 * @param {object} map key:valueペアの配列
		 */
		this.data = function(map) {
			if (map && typeof map === "object") {
				for (key in map) {
					this.put(key, map[key]);
				}
			}
		};

		this.setUrl = function(url) {
			config.url = url;
		};
		this.setName = function(name) {
			config.name = name;
		};
		this.setResizable = function(resizable) {
			config.resizable = resizable;
		};
		this.setScrollbars = function(scrollbars) {
			config.scrollbars = scrollbars;
		};
		this.setWidth = function(width) {
			config.width = width;
		};
		this.setHeight = function(height) {
			config.height = height;
		};
		this.setLeft = function(left) {
			config.left = left;
		};
		this.setTop = function(top) {
			config.top = top;
		};
		this.setAction = function(action) {
			config.action = action;
		};
		this.setRootFormId = function(rootFormId) {
			config.rootFormId = rootFormId;
		};
		this.setToolbar = function(toolbar) {
			config.toolbar = toolbar;
		};

		this.getAction = function() {
			return config.action;
		};
		this.getUrl = function() {
			return config.url;
		};
		this.getName = function() {
			return config.name;
		};
		this.getLocation = function() {
			return config.location;
		};
		this.getResizable = function() {
			return config.resizable;
		};
		this.getStatus = function() {
			return config.status;
		};
		this.getMenubar = function() {
			return config.menubar;
		};
		this.getScrollbars = function() {
			return config.scrollbars;
		};
		this.getWidth = function() {
			return config.width;
		};
		this.getHeight = function() {
			return config.height;
		};
		this.getLeft = function() {
			return config.left;
		};
		this.getTop = function() {
			return config.top;
		};
		this.getDependent = function() {
			return config.dependent;
		};
		this.getDirectories = function() {
			return config.directories;
		};
		this.getSubmitFormId = function() {
			return config.submitFormId;
		};
		this.getRootFormId = function() {
			return config.rootFormId;
		};
		this.getToolbar = function() {
			return config.toolbar;
		};
	};

	/**
	 * 新しいWindowを開く
	 * @return 開いたwindowへの参照
	 */
	Popup.prototype.open = function() {
		var w = window.open(this.getUrl(), this.getName(), "location="
						+ this.getLocation() + ",resizable="
						+ this.getResizable() + ",status=" + this.getStatus()
						+ ",menubar=" + this.getMenubar() + ",scrollbars="
						+ this.getScrollbars() + ",width=" + this.getWidth()
						+ ",height=" + this.getHeight() + ",left="
						+ this.getLeft() + ",top=" + this.getTop()
						+ ",toolbar="+ this.getToolbar());
		var rootFormId = this.getRootFormId();
		if (rootFormId) {
			var rootForm = $(Beauty.fn.idSelector(rootFormId)).get(0);
			var lastAction = rootForm.action;
			rootForm.action = this.getAction();
			rootForm.target = this.getName();
			rootForm.method = "post";
			rootForm.submit();
			rootForm.action = lastAction;
		}
		return w;
	};

	/**
	 * Windowを閉じる
	 */
	Popup.prototype.close = function(fn, args) {
		this.getWindow().close();
		if (fn && fn instanceof Function) {
			fn.apply(this, args);
		}
	};

	/**
	 * クリック時に、指定classをもつ要素のdisabledを解除する
	 * @param {string} clickableId クリックされる要素のid属性値
	 * @param {string} enableClass disabledを解除する対象要素のclass属性値
	 */
	Beauty.prototype.resetDesabled = function(clickableId, enableClass) {
		$(Beauty.fn.idSelector(clickableId)).live("click", function() {
			Beauty.fn.enableAll(enableClass);
		});
	};
	window.Beauty = Beauty;
	return new Beauty();
})(window);

