/*******************************************************************************
 
 @auther kawamata@team-lab
 
 確認ブラウザ
  WindowsXP
    InternetExplorer 7.0.5730.11IC
    Opera 9.1.0
    Firefox 2.0.0.4
    Safari 3.0.3
    Netscape 7.1
 
 *******************************************************************************/

// レオパレスオブジェクト作成
var Leopalace = Object.extend({}, Leopalace || {});

/**
 * レオパレスユーティリティ
 */
Leopalace.Util = new (Class.create({
	
	/**
	 * 透明度の設定
	 * ブラウザごとに設定項目が違うので、全部設定する
	 */
	setOpacity : function(element, ratio){
		var style = $(element).style;
		if(ratio >= 0.9999) ratio = 1;
		if(ratio <= 0.0001) ratio = 0;
		
		Element.setStyle(element, {
			filter     : "alpha(opacity=" + ratio * 100 + ")", // for Internet Explorer
			MozOpacity : ratio,                                // for Firefox
			opacity    : ratio                                 // for Safari
		});
	},
	
	/**
	 * ページの幅を取得します
	 */
	getPageWidth : function(){
		if(document.width) return document.width;
		if(document.body.scrollWidth) return document.body.scrollWidth;
		return 0;
	},
	
	/**
	 * ページの高さを取得します
	 */
	getPageHeight : function(){
		if(document.height) return document.height;
		if(document.body.scrollHeight) return document.body.scrollHeight;
		return 0;
	}
	
}))();

/**
 * スクロールを管理するクラス
 */
Leopalace.ScrollManager = new (Class.create({

	/**
	 * コンストラクタ
	 */
	initialize : function(){
		this.onInterval = this.onInterval.bind(this);
	},
	
	/**
	 * インターバル関数
	 */
	onInterval : function(){
		var curX = parseInt(document.body.scrollLeft || document.documentElement.scrollLeft || window.pageXOffset || window.scrollX || 0);
		var diff = this.toValue - this.curTop;
		this.curTop += diff * 0.25;
		window.scrollTo(curX, this.curTop);
		this.timerId = (Math.abs(diff) >= 1) ? setTimeout(this.onInterval, 40) : null;
	},
	
	/**
	 * 指定したY座標にスクロールを開始します
	 * @param top Y座標
	 */
	moveTo : function(top){
		this.toValue = parseInt(top);
		this.curTop = parseInt(document.body.scrollTop  || document.documentElement.scrollTop  || window.pageYOffset || window.scrollY || 0);
		if(!this.timerId) this.timerId = setTimeout(this.onInterval, 40);
	}
}))();


// =========================================================================================
//
//  バリデータ関連
//
// =========================================================================================

Leopalace.Validator = {};

/**
 * バリデーションマネージャ
 * 基本<form>オブジェクトに対して1:1となる
 */
Leopalace.Validator.Manager = Class.create({
	
	/**
	 * コンストラクタ
	 */
	initialize : function(formElement, paramHash){
		var params = paramHash || {};
		this.formElement = formElement;
		this.groups = $A();
		this.submitBtn = params.submit;
		this.init(params);
		this.hasError = true;
		this.moveOnError = (paramHash.moveOnError == false) ? false : true;
	},
	
	/**
	 * 初期化メソッド
	 * 必要に応じてオーバーライドします
	 */
	init : function(params){
	},
	
	/**
	 * 管理下におくグループを追加します
	 */
	append : function(group){
		if(!group) return;
		this.groups.push(group);
	},
	
	/**
	 * 全項目に対してチェックを実行します
	 */
	validate : function(){
		var groups = this.groups;
		var errorGroup = null;
		
		groups.each(function(group){
			if(group.checkApply()) errorGroup = errorGroup || group;
		});
		
		this.hasError = !!errorGroup;
		
		(this.hasError) ? this.onInvalid(errorGroup) : this.onValid();
		
		if(this.submitBtn) this.submitBtn.setErrorStatus(this.hasError);
		
		return !this.hasError;
	},
	
	/**
	 * ボタンのステータス変更用メソッドです
	 */
	buttonStatus : function(){
		if(!this.submitBtn) return;
		
		var groups = this.groups;
		this.hasError = !!groups.detect(function(group){
			return !!group.checkOnly();
		});
		
		this.submitBtn.setErrorStatus(this.hasError);
	},
	
	/**
	 * エラー無しの時に呼ばれるvalidate()のコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onValid : function(){
		if(this.submitBtn) this.submitBtn.enable();
	},
	
	/**
	 * エラーがあるときに呼ばれるvalidate()のコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onInvalid : function(firstErrorGroup){
		if(this.submitBtn) this.submitBtn.disable();
		if(this.moveOnError) Leopalace.ScrollManager.moveTo(firstErrorGroup.getHead());
	}
});

/**
 * バリデータのグループ
 */
Leopalace.Validator.Group = Class.create({
	
	/**
	 * コンストラクタ
	 * @param manager Leopalace.Validator.Managerインスタンス
	 * @param paramHash パラメータ
	 */
	initialize : function(manager, paramHash){
		this.manager = manager;
		this.checkers = $A();
		
		var params = paramHash || {};
		this.headElement = $(params.head);
		
		this.init(params);
		this.manager.append(this);
	},
	
	/**
	 * グループの頭のY座標を取得します
	 */
	getHead : function(){
		return (!!this.headElement) ? Position.cumulativeOffset(this.headElement)[1] : 0;
	},
	
	/**
	 * 初期化関数
	 * 必要に応じてオーバーライドします
	 * @param params initializeのparamHashと同じ内容
	 */
	init : function(params){
	},
	
	/**
	 * checkerを追加します
	 * @param checker Leopalace.Validator.Checkerインスタンス
	 */
	append : function(checker){
		if(!checker) return;
		this.checkers.push(checker);
	},
	
	/**
	 * チェックが有効かどうかを返します
	 * チェック自体させたくないときなどはオーバーライドしてfalseを返させます
	 * @return true:  チェックする
	 *         false: チェックしない
	 */
	isCheckEnabled : function(){
		return true;
	},
	
	/**
	 * チェックだけして反映はしません
	 * @return true:  NGのとき
	 *         false: OKのとき
	 */
	checkOnly : function(){
		if(!this.isCheckEnabled()) return false;
		
		var checkers = this.checkers;
		return !!checkers.detect(function(checker){
			return !!checker.check();
		});
	},
	
	/**
	 * チェックして結果を反映させます
	 * @return true:  NGのとき
	 *         false: OKのとき
	 */
	checkApply : function(){
		if(!this.isCheckEnabled()){
			this.onInit();
			return false;
		}
		
		var checkers = this.checkers;
		var self = this;
		var errorCode = null;
		checkers.each(function(checker){
			var fieldError = checker.check();
			(fieldError) ? checker.onValid() : checker.onInvalid(fieldError);
			errorCode = errorCode || fieldError;
		});
		
		(errorCode) ? this.onInvalid(errorCode) : this.onValid();
		
		return !!errorCode;
	},
	
	/**
	 * 初期状態へ戻すときのコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onInit : function(){
	},
	
	/**
	 * チェックOK時のコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onValid : function(){
	},
	
	/**
	 * チェックNG時のコールバック関数
	 * 必要に応じてオーバーライドします
	 * @param errorCode checkerが返したエラーコード
	 */
	onInvalid : function(errorCode){
	}
});

/**
 * チェッカー
 */
Leopalace.Validator.Checker = Class.create({

	/**
	 * コンストラクタ
	 * @param group Leopalace.Validator.Groupインスタンス
	 * @param paramHash パラメータ
	 */
	initialize : function(group, paramHash){
		this.group = group;
		this.init(paramHash || {});
		this.group.append(this);
	},
	
	/**
	 * 初期化関数
	 * 必要に応じてオーバーライドします
	 * @param params initializeのparamHashと同じ内容
	 */
	init : function(params){
	},
	
	/**
	 * チェックを実行します
	 * @return empty: チェックOK
	 *         any:   NG時のエラーコード
	 */
	check : function(){
	},
	
	/**
	 * 初期状態へ戻すときのコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onInit : function(){
	},
	
	/**
	 * 編集状態へ戻すときのコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onEdit : function(element){
	},
	
	/**
	 * チェックOK時のコールバック関数
	 * 必要に応じてオーバーライドします
	 */
	onValid : function(){
	},
	
	/**
	 * チェックNG時のコールバック関数
	 * 必要に応じてオーバーライドします
	 * @param errorCode checkerが返したエラーコード
	 */
	onInvalid : function(errorCode){
	}
});

/**
 * バリデーションのトリガーを付与するユーティリティ
 */
Leopalace.Validator.ValidationTrigger = new (Class.create({
	
	/**
	 * エンターキーに対してトリガーを付与する
	 * テキストボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Managerインスタンス
	 * @param callback コールバック関数
	 */
	attachKeypress : function(elementsArray, manager, callback){

		var realcollback;
		if(!callback){
			realcollback = Prototype.emptyFunction;
		}else if(typeof callback == "function"){
			realcollback = callback;
		}else{
			realcollback = function(){ manager.formElement.action = callback };
		}
		
		var onKeypressCallback = function(event){
			if(event.keyCode == Event.KEY_RETURN){
			 	if(!!manager && !manager.validate()){
					Event.stop(event);
				}else{
					realcollback.apply(window);
				}
			}
		};
		elementsArray.each(function(element){
			Event.observe(element, 'keypress', onKeypressCallback);
		});
	},
	
	/**
	 * マウスクリックに対してトリガーを付与する
	 * ラジオボタンやチェックボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Managerインスタンス
	 * @param callback コールバック関数
	 */
	attachClick : function(elementsArray, manager, callback){
		
		var realcollback;
		if(!callback){
			realcollback = Prototype.emptyFunction;
		}else if(typeof callback == "function"){
			realcollback = callback;
		}else{
			realcollback = function(){ manager.formElement.action = callback };
		}
		
		var onClickCallback = function(event){
		 	if(!!manager && !manager.validate()){
				Event.stop(event);
			}else{
				realcollback.apply(window);
			}
		};
		elementsArray.each(function(element){
			Event.observe(element, 'click', onClickCallback);
		});
	}
	
}))();

/**
 * グループの初期化のトリガーを付与するユーティリティ
 */
Leopalace.Validator.InitTrigger = new (Class.create({
	
	/**
	 * フォーカスに対してトリガーを付与する
	 * テキストボックスやテキストエリアに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Managerインスタンス
	 */
	attachFocus : function(elementArray, group){
		var onFocusCallback = function(event){
			group.onInit();
		};
		elementArray.each(function(element){
			Event.observe(element, 'focus', onFocusCallback);
		});
	}
}))();

/**
 * チェックを実行するトリガーを付与するユーティリティ
 */
Leopalace.Validator.CheckTrigger = new (Class.create({
	
	/**
	 * 非活性化されたときのトリガーを付与します
	 * テキストボックスやテキストエリアに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Groupインスタンス
	 */
	attachBlur : function(elementArray, group){
		var onBlurCallback = function(event){
			if($F(Event.element(event)) == "") return;
			group.checkApply();
			group.manager.buttonStatus();
		};
		elementArray.each(function(element){
			Event.observe(element, 'blur', onBlurCallback);
		});
	},
	
	/**
	 * クリックされたときのトリガーを付与します
	 * ラジオボタンやチェックボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Groupインスタンス
	 */
	attachOnClick : function(elementArray, group){
		var onClickCallback = function(event){
			group.checkApply();
			group.manager.buttonStatus();
		};
		elementArray.each(function(element){
			Event.observe(element, 'click', onClickCallback);
		});
	},
	
	/**
	 * 変更されたときのトリガーを付与します
	 * セレクトボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Groupインスタンス
	 */
	attachChange : function(elementArray, group){
		var onChangeCallback = function(event){
			group.checkApply();
			group.manager.buttonStatus();
		};
		elementArray.each(function(element){
			Event.observe(element, 'change', onChangeCallback);
		});
	},
	
	/**
	 * チェックが入ったときのトリガーを付与します
	 * ラジオボタンやチェックボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Groupインスタンス
	 */
	attachOnCheck : function(elementArray, group){
		var onClickCallback = function(event){
			if(this.checked || this.selected || false){
				group.checkApply();
				group.manager.buttonStatus();
			}
		};
		elementArray.each(function(element){
			Event.observe(element, 'click', onClickCallback);
		});
	},
	
	/**
	 * チェックが取れたときのトリガーを付与します
	 * ラジオボタンやチェックボックスに使用します
	 * @param elementsArray 付与するエレメントの配列
	 * @param manager Leopalace.Validator.Groupインスタンス
	 */
	attachOnUncheck : function(elementArray, group){
		var onClickCallback = function(event){
			if(!(this.checked || this.selected || false)){
				group.checkApply();
				group.manager.buttonStatus();
			}
		};
		elementArray.each(function(element){
			Event.observe(element, 'click', onClickCallback);
		});
	}
}))();
	
/**
 * コンビネーション
 */
Leopalace.Combination = new (Class.create({

	/**
	 * 指定した桁数に達したときにテキストボックスのフォーカスを移動します
	 * @param fieldElement テキストボックス
	 * @param params パラメータ
	 *   @name next 次のテキストボックス
	 *   @name prev 前のテキストボックス
	 *   @name digit 次へ移るときの桁数
	 */
	attachPrevNext : function(fieldElement, params) {
		var element = $(fieldElement);
		
		var nextField = $(params.next);
		var prevField = $(params.prev);
		var digit = params.digit || 0;
		
		Event.observe(element, 'keyup', function(event){
			if(event.keyCode == Event.KEY_TAB || 
			   event.keyCode == Event.KEY_RETURN || 
			   event.keyCode == Event.KEY_ESC || 
			   event.keyCode == Event.KEY_LEFT || 
			   event.keyCode == Event.KEY_UP || 
			   event.keyCode == Event.KEY_RIGHT || 
			   event.keyCode == Event.KEY_DOWN || 
			   event.keyCode == Event.KEY_DELETE){
				return;
			}
			
			var value = ($F(element) || "");
			if(event.keyCode != Event.KEY_BACKSPACE && value.length >= digit && nextField){
				Field.focus(nextField);
			}else if(event.keyCode == Event.KEY_BACKSPACE && value.length <= 0 && prevField){
				Field.focus(prevField);
			}
		});
		
	},
	
	/**
	 * クリックしたときに指定したオブジェクトへフォーカスを移動します
	 * @param fieldElement ラジオボタンかチェックボックス
	 * @param params パラメータ
	 *   @name focus フォーカスを当てるエレメント
	 */
	attachClickFocus : function(fieldElement, params) {
		var element = $(fieldElement);
		var focusField = $(params.focus);
		var defaultValue = params.defaultValue || "";
		Event.observe(element, 'click', function(event){
			if(!focusField) return;
			
			if(element.checked || element.selected || false){
				Field.focus(focusField);
			}else{
				focusField.value = defaultValue;
			}
		});
	},
	
	/**
	 * デフォルトの値が入ったテキストフィールドを生成します
	 * @param fieldElement テキストボックス
	 * @param params パラメータ
	 *   @name defaultValue デフォルトの値
	 */
	attachDefaultField : function(fieldElement, params) {
		var element = $(fieldElement);
		var defaultValue = params.defaultValue || "";
		Event.observe(element, 'focus', function(event){
			var value = element.value || "";
			if(value == defaultValue){
				element.value = "";
			}
		});
		Event.observe(element, 'blur', function(event){
			var value = element.value || "";
			if(value == "" || value == defaultValue){
				element.value = defaultValue;
			}
		});
		
		var value = element.value || "";
		if(value == "" || value == defaultValue){
			element.value = defaultValue;
		}
	},
	
	
	/**
	 * フォーカスがあたったときにクラス名を追加します
	 * @param fieldElement エレメント
	 * @param params パラメータ
	 *   @name className クラス名
	 */
	attachFocusFields : function(fieldElementArray, params) {
		var className = params.className || "";
		
		fieldElementArray.each(function(element){
			Event.observe(element, 'focus', function(event){
				Element.addClassName(element, className);
			});
			Event.observe(element, 'blur', function(event){
				Element.removeClassName(element, className);
			});
		});
	},
	
	/**
	 * テキストボックスからフォーカスが離れたときにデフォルトとは異なる値が入っていた場合、チェックボックスにチェックを入れる
	 * @param textElement テキストボックスエレメント
	 * @param cboxElement チェックボックス/ラジオボタンエレメント
	 * @param params パラメータ
	 *   @name defaultValue デフォルト値
	 */
	attachCheckOnNotEmpty : function(textElement, cboxElement, params){
		var tElement = $(textElement);
		var cElement = $(cboxElement);
		var defaultValue = params.defaultValue || "";
		Event.observe(textElement, 'blur', function(event){
			if($F(tElement) != defaultValue){
//				cElement.checked =  true;
			}else{
//				cElement.checked =  false;
			}
		});
	}
	
}))();

/**
 * マウスオーバーでハイライト表示されるための画像ボタンクラス
 */
Leopalace.Button = Class.create({
	
	/**
	 * コンストラクタ
	 * @param buttonElement ボタンオブジェクト
	 * @param params パラメータ
	 *   @name disable 通常時の画像URL
	 *   @name enable  ハイライト時の画像URL
	 */
	initialize : function(buttonElement, params){
		
		this.element = $(buttonElement);
		this.disableImage = params.disable || "";
		this.highlightImage = params.highlight || "";
		this.enableImage = params.enable || "";
		this.errorStatus = true;
		this.isOver = false;
		
		Event.observe(this.element, 'mouseover', this.enable.bind(this));
		Event.observe(this.element, 'mouseout', this.disable.bind(this));
	},
	
	/**
	 * ハイライトにする
	 */
	enable : function(){
		this.isOver = true;
		this.update();
	},
	/**
	 * 通常字にする
	 */
	disable : function(){
		this.isOver = false;
		this.update();
	},
	
	/**
	 * ボタン画像を更新します
	 */
	update : function(){
		if(this.isOver){
			// マウスオーバーのとき
			if(this.enableImage){
				this.element.src = (this.errorStatus) ? this.disableImage : this.highlightImage;
			}else{
				this.element.src = this.highlightImage;
			}
			
		}else{
			// マウスアウトのとき
			if(this.enableImage){
				this.element.src = (this.errorStatus) ? this.disableImage : this.enableImage;
			}else{
				this.element.src = this.disableImage;
			}
		}
	},
	
	/**
	 * エラー状態を設定します
	 */
	setErrorStatus : function(errorStatus){
		this.errorStatus = !!errorStatus;
		this.update();
	}
});

/**
 * ボタンのイベントに動作を加えるためのユーティリティ
 */
Leopalace.ButtonAppender = new (Class.create({
	
	/**
	 * インラインフレームの画像を挿入します
	 * @param formElement フォームオブジェクト
	 * @param wait 表示時間[ms]
	 * @param imgSrc 表示するURI
	 */
	processImage : function(buttonElement, wait, imgSrc, intercepter){
		
		var im = new Leopalace.PopupImageManager(buttonElement, 'click', wait, imgSrc, intercepter);
		im.bindEvent()
	}
}))();

/**
 * 画像のポップアップを行うマネージャ
 */
Leopalace.PopupImageManager = Class.create({
	
	initialize : function(element, eventName, wait, imgSrc, intercepter){
		
		element = $(element);
		
		var div = document.createElement('div');
		div.className = "imagepopup";
		Leopalace.Util.setOpacity(div, 0);
		Element.hide(div);
		
		var table = document.createElement('table');
		table.cellpadding = "0";
		table.cellspacing = "0";
		Element.setStyle(table, {
			width : "100%",
			height : "100%"
		});
		
		var tbody = document.createElement('tbody');
		var tr = document.createElement('tr');
		var td = document.createElement('td');
		td.align = "center";
		
		var img = document.createElement('img');
		img.border = "0";
		img.src = imgSrc;
		
		td.appendChild(img);
		tr.appendChild(td);
		tbody.appendChild(tr);
		table.appendChild(tbody);
		div.appendChild(table);
		document.body.appendChild(div);
		
		this.element = element;
		this.div = div;
		this.eventName = eventName;
		this.openImage = false;
		this.wait = wait;
		
		this.intercepter = $A(intercepter);
	},
	
	bindEvent : function(){
		Event.observe(this.element, this.eventName, this.process.bind(this));
	},
	
	process : function(event){
		
		if(this.openImage) return;
		
		if(event) Event.stop(event);
		
		if(!!this.intercepter.detect(function(intercepter){
			return intercepter.call(window);
		})) return;
		
		this.openImage = true;
		
		Element.show(this.div);
		var opacity = 0;
		var self = this;
		var opacityInterval = function(){
			opacity += (1 - opacity) * 0.2;
			Leopalace.Util.setOpacity(self.div, opacity);
			
			if(opacity > 0.999){
				setTimeout(function(){
					(self.element[self.eventName])();
				}, self.wait);
			}else{
				setTimeout(opacityInterval, 40);
			}
		};
		
		opacityInterval();
	}

});

/**
 * 画像ラジオボタン
 */
Leopalace.GUIRadio = new (Class.create({

	create : function(oncls, offcls, objects){
		
		var objects = objects || {};
		
		var refresh = function(){
			for(var imgId in objects){
				var img = $(imgId);
				if(!img) continue;
				
				var obj = $(objects[imgId]);
				if(!obj) continue;
				
				if(obj.checked){
					Element.addClassName(img, oncls);
					Element.removeClassName(img, offcls);
				}else{
					Element.removeClassName(img, oncls);
					Element.addClassName(img, offcls);
				}
			}
		};
		
		for(var imgId in objects){
			var img = $(imgId);
			if(!img) continue;
			
			var obj = $(objects[imgId]);
			if(!obj) continue;
			
			Event.observe(img, 'click', function(event){
				Event.stop(event);
				
				var body = document.body;
				var obj = null;
				for(var e = Event.element(event); !!e && e != body; e = e.parentNode){
					var id = e.id;
					if(!id) continue;;
					
					var obj = $(objects[id]);
					if(!obj) continue;;
					
					break;
				}
				
				if(!obj) return;
				obj.click();
				refresh();
			});
		}
		refresh();
	}
}))();
