/**
 * @projectDescription Empas Prototye & UI
 * @copyright Empas Corp. <http://www.empas.com>
 * @author ifsnow ifsnow@empascorp.com
 * @version 1.0
 * 
 * Empas > UI > View > Tab, Rotate, Toggle, Scroller, Floating
 */

if(typeof Prototype == "undefined")
	throw("empas.ui.view.js requires including Prototype library");

if (!$D(Empas)) var Empas = {};
if (!$D(Empas.UI)) Empas.UI = {};

/*============================================================================*
 * ViewItem
 *============================================================================*/
Empas.UI.ViewItem = Class.create();

Empas.UI.ViewItem.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {String} tab_id 탭과 연결할 엘리먼트 아이디
	 * @param {Object} request Ajax 요청 옵션
	 * @constructor
	 */
	initialize: function(id, request) {
		this._el = $(id);
		this.setRequest(request);
	},
	
	/**
	 * Ajax 요청 옵션 설정
	 * 
	 * @param {Object} request 옵션
	 */
	setRequest: function(request) {
		this._request = Object.extend({
			url: '',			// Ajax 호출 URL
			lazyLoading: false,	// 지연 로딩 유무
			isLoad: false		// 로딩 완료 유무
		}, request || {});
		
		if (this._request.lazyLoading) 
			Event.observe(window, "load", this._load.bind(this));
	},
	
	/**
	 * 숨기기
	 */
	hide: function() {
		this._el.hide();
	},

	/**
	 * 보이기
	 */	
	show: function() {
		this._el.show();
		this._load();
	},
	
	/**
	 * Ajax 설정이 된 경우 요청해 엘리먼트 갱신하기
	 */
	_load: function() {
		if (this._request.url!='' && !this._request.isLoad) {
			if(!$D(Ajax))
				throw("Empas.UI.View.js requires including Prototype.Ajax library");
			
			this._request.isLoad = true;
			new Empas.Ajax.Updater(this._el, this._request.url);
		}
	}
};

/*============================================================================*
 * Tab
 *============================================================================*/
Empas.UI.Tab = Class.create();

Empas.UI.Tab.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {Object} options 옵션
	 * @constructor
	 */
	initialize: function(options) {
		this._options = Object.extend({
			changeAction: true,		// 탭 변경시 액션 여부
			clickMode: false,		// 클릭 모드(클릭해야 탭 변경). 기본값은 마우스 오버시 변경
			afterChange: null,		// 변경후 실행될 함수
			noActive: false			// 초기 탭 비활성화 여부
		}, options || {});
		
		this._TabItems = {};
		this._selectedTab = null;
	},
	
	/**
	 * 루트탭 객체 바인딩
	 * 
	 * @param {Empas.UI.View.TabItem} 탭 아이템 객체
	 */	
	add: function(TabItem) {
		if ($D(TabItem.el)) {
			this._TabItems[TabItem.id] = TabItem;
		}
	},	
	
	/**
	 * 탭에 마우스 오버 이벤트 연결
	 * 
	 * @param {String} focusTabId 초기 보여질 탭 아이디 (기본값 : 첫번째 탭)
	 */
	start: function(focusTabId) {
		var initTabId = focusTabId || null;
		var options = this._options;
		var eventKey = options.clickMode ? 'click':'mouseover';
		
		// 탭 아이템별 이벤트 연결
		$H(this._TabItems).each(function(tab) {
			Event.observe(tab.key, eventKey, this._onChangeTab.bindAsEventListener(this, tab.value));
			if (initTabId==null) initTabId = tab.key;
		}.bind(this));
		
		// 초기탭 활성화
		if (!options.noActive && (this._selectedTab = this._TabItems[initTabId])) {
			this._selectedTab._setVisible(true, options.changeAction);
		}
	},
	
	/**
	 * 탭 변경시 실행
	 * 
	 * @param {Empas.UI.View.TabItem} TabItem 이벤트가 발생한 탭 아이템 객체
	 */
	_onChangeTab: function(e, TabItem) {
		var options = this._options;

		// 클릭 모드일 경우 이벤트 전달 막기
		if (options.clickMode) {
			Event.stop(e);
		}
		
		// 이전탭 비활성화
		if (this._selectedTab != null) {
			if (this._selectedTab == TabItem) return; // 현재 활성화 탭과 같을 경우
			this._selectedTab._setVisible(false, options.changeAction);
		}

		// 선택탭 활성화
		TabItem._setVisible(true, options.changeAction);		
		this._selectedTab = TabItem;
		
		if (options.afterChange != null) 
			options.afterChange(TabItem);
	}
};

/*============================================================================*
 * TabItem
 *============================================================================*/
Empas.UI.TabItem = Class.create();

Empas.UI.TabItem.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {String} tab_id 탭과 연결할 엘리먼트 아이디
	 * @constructor
	 */
	initialize: function(tab_id) {
		this.view = null; // 탭과 연결할 뷰 아이템
		
		if ((this.el = $(tab_id)) != null) {			
			this.id = tab_id;
			
			// 마우스 오버시 실행할 명령에 대한 설정값 저장
			if (this.el.tagName=="IMG") { // 이미지일 경우
				this._over = {
					mode: 'img',
					off: this.el.readAttribute('offsrc')!=null ? 
							this.el.readAttribute('offsrc'):this.el.src,
					on: this.el.readAttribute('onsrc')
				};
			} else {
				this._over = {
					mode: 'class',
					off: this.el.readAttribute('offclass')!=null ? 
							this.el.readAttribute('offclass'):$(this.el).className,
					on: this.el.readAttribute('onclass')
				};
			}
		}
	},
	
	/**
	 * 탭과 뷰 연결
	 * 
	 * @param {String} view_id 뷰 엘리먼트 아이디
	 * @param {Object} request Ajax 요청 옵션 
	 */
	setView: function(view_id, request) {	
		if ((this.view = new Empas.UI.ViewItem(view_id, request)) != null) {
			this.view.hide();
		}
	},
	
	/**
	 * 뷰 보임/안보임 처리
	 * 
	 * @param {Boolen} visible 보임/안보임
	 * @param {Boolen} changeAction 상태 변경시 액션 여부
	 */	
	_setVisible: function(visible, changeAction) {
		if (!this.view) return;
		
		var tab = this.el;
		if (visible) {
			if (changeAction && this._over.on!=null) {
				if (this._over.mode=='img') {
					tab.src = this._over.on;
				} else if (!tab.hasClassName(this._over.on)){
					tab.removeClassName(this._over.off);
					tab.addClassName(this._over.on);
				}
			}
			this.view.show();
		}
		else {
			if (changeAction && this._over.off!=null) {
				if (this._over.mode=='img') {
					tab.src = this._over.off;
				} else if (!tab.hasClassName(this._over.off)){
					tab.removeClassName(this._over.on);
					tab.addClassName(this._over.off);
				}
			}
			this.view.hide();
		}
	}
};

/*============================================================================*
 * Rotate
 *============================================================================*/
Empas.UI.Rotate = Class.create();

Empas.UI.Rotate.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {Object} options 옵션
	 * @constructor
	 */
	initialize: function(options) {
		this._options = Object.extend({			
			autoTime: 0,		// 타이머 (자동 롤링). 초단위
			useHand: true,		// 마우스 오버시 손모양 마우스 여부
			afterChange: null	// 변경시 실행할 함수
		}, options || {});
		
		this._ViewItems = [null];
	},
	
	/**
	 * 뷰 추가
	 * 
	 * @param {String} view_id 뷰 엘리먼트 아이디
	 * @param {Object} request Ajax 요청 옵션
	 */	
	add: function(view_id, request) {
		this._ViewItems.push(new Empas.UI.ViewItem(view_id, request));
	},	
	
	/**
	 * 실행
	 * 
	 * @param {Number} initIdx 초기 뷰 인덱스
	 */
	start: function(initIdx) {
		var options = this._options;

		// 이벤트 연결
		Event.observe(options.prev, "click", this._onClick.bindAsEventListener(this, 'prev'));
		Event.observe(options.next, "click", this._onClick.bindAsEventListener(this, 'next'));
		
		// 마우스 커서
		if (options.useHand) {
			$(options.prev).setStyle({ cursor: "pointer" });
			$(options.next).setStyle({ cursor: "pointer" });			
		}

		// 초기 뷰
		this._endIdx = this._ViewItems.length-1;
		this._savedIdx = this._curIdx = $D(initIdx) ? initIdx:1;
		
		this._show();
	},

	/**
	 * 이전 버튼 외부 함수
	 */	
	priv: function() {
		this._onClick(null, "priv");
	},
	
	/**
	 * 다음 버튼 외부 함수
	 */		
	next: function() {
		this._onClick(null, "next");
	},
	
	/**
	 * 뷰 노출 여부
	 */
	_show: function() {
		var options = this._options;

		// 현재 아이템
		this._ViewItems[this._curIdx].show();

		// 자동 롤링 타이머 설정
		if (options.autoTime != 0) {
			if ($D(this._timer)) this._timer.stop();
						
			this._timer = new PeriodicalExecuter(function () {
				this._onClick('next'); 
			}.bind(this), options.autoTime);
		}

		if (options.afterChange!=null)
			options.afterChange(this._curIdx);		
	},
	
	/**
	 * 이전, 다음 클릭 이벤트 발생시 실행
	 */	
	_onClick: function(e, mode) {
		Event.stop(e);
		
		this._curIdx += mode=="next" ? 1:-1;
		
		if (this._curIdx <= 0) 
			this._curIdx = this._endIdx;
		else if (this._curIdx > this._endIdx)
			this._curIdx = 1;

		this._ViewItems[this._savedIdx].hide();
		this._savedIdx = this._curIdx;
		
		this._show();
	}
};

/*============================================================================*
 * Toggle
 *============================================================================*/
Empas.UI.Toggle = Class.create();

Empas.UI.Toggle.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {String} id 토글을 연결할 엘리먼트 아이디
	 * @param {String} view_id 뷰 엘리먼트 아이디
	 * @param {String} options 옵션
	 * @constructor
	 */
	initialize: function(id, view_id, options) {
		this._options = Object.extend({
			visible: false,		// 초기 출력 여부
			afterChange: null,	// 실행후 호출할 함수
			useHand:false		// 마우스 손모양 커서 유무
		}, options || {});
		
		this._el = $(id);
		if (!this._el) return;
		
		if (this._options.useHand) 
			this._el.setStyle({ cursor: "pointer" });
			
		this._view = new Empas.UI.ViewItem(view_id);
		
		this.toggle(false);
		
		this._el.observe("click", this.toggle.bind(this));
	},
	
	/**
	 * 토글 함수
	 * 
	 * @param {Boolean} change 상태값 변경 여부 (기본값 true)
	 */
	toggle: function(change) {
		var options = this._options;

		if ((change = change || false))
			options.visible = !options.visible;
			
		this._view[options.visible ? 'show':'hide']();
		
		if (options.afterChange!=null)
			options.afterChange(this._el, options.visible);
	}
};

/*============================================================================*
 * Scroller
 *============================================================================*/
Empas.UI.Scroller = Class.create();

Empas.UI.Scroller.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {String} id 루트 엘리먼트 아이디
	 * @param {Object} options 옵션 
	 * @constructor
	 */
	initialize: function(id, options) {
		id = $(id);
		if (!id) return;

		this._options = Object.extend({	
			height: 18,			// 높이
			width: "100%",		// 너비
			width_unit: "px",	// 너비 단위
			pauseTime: 3,		// 멈춤시간(초)
			speed: 0.02,		// 스크롤 이동 호출시간 (낮을수록 빠름)
			step: 1,			// 이동 픽셀 단위
			overStop: true,		// 마우스 오버시 멈춤 여부
			autoStart: true		// 시작시 롤링 시작
		}, options || {});

		options = this._options;

		if (options.width.indexOf("%")!=-1)
		{
			options.width = options.width.replace("%","");
			options.width_unit = "%";
		}

		// 루트 엘리먼트 스타일 설정
		this._el = $C("div");
		$(this._el).setStyle({
			position : "relative",
			overflow : "hidden",
			height : options.height + "px",
			width : options.width + options.width_unit
		});	
		id.appendChild(this._el);

		// 아이템 시작 위치(y)
		options.readyPos = options.height;
		
		// 아이템 저장 배열
		this._items = [];
		this._itemCnt = 0;
	},
	
	/**
	 * 데이터 추가
	 * 
	 * @param {String} html 추가할 div에 넣을 내용
	 */	
	add: function(html) {
		if (!$D(this._options)) return;
		
		var options = this._options;

		// div 객체 만들기
		var item = $C("div");
		item.top = (this._itemCnt==0) ? 0:options.readyPos;
		$(item).setStyle( {
			position : "absolute",
			top : item.top + "px",
			height : options.height + "px",
			width : options.width + options.width_unit
		});
		item.innerHTML = html;
		
		// 추가
		this._el.appendChild(item);
		this._items[this._itemCnt++] = item;
	},
	
	/**
	 * 실행
	 */	
	start: function() {	
		if (this._itemCnt>1) {
			// 초기화
			this._pause = false;
			this._curIdx = 0;
			this._nextIdx = 1;

			// mouse over 이벤트 등록
			if (this._options.overStop) {
				this._el.observe("mouseover", this._setPause.bind(this, true));
				this._el.observe("mouseout", this._setPause.bind(this, false));
			}
			
			this._start();
		}
	},
	
	/**
	 * 스크롤 정지 변수 설정
	 * 
	 * @param {Boolean} val 정지 여부
	 */
	_setPause: function(val) {
		this._pause = val;		
	},
	
	/**
	 * 스크롤 함수 실행
	 */	
	_start: function() {
		new PeriodicalExecuter(function (pe) {
			pe.stop();
		
			// 아이템 이동 함수 실행
			if (this._Executer) this._Executer.stop();			
			this._Executer = new PeriodicalExecuter(function () {
				this._moveItem(); 
			}.bind(this), this._options.speed);
						
		}.bind(this), this._options.pauseTime);
	},
	
	/**
	 * 스크롤 정지 변수 설정
	 * 
	 * @param {Boolean} val 정지 여부
	 */
	_moveItem: function() {
		if (this._pause) return;
		var oerflow = false;
		var items = this._items;
		var options = this._options;
		
		[this._curIdx, this._nextIdx].each(function(idx) {
			// 현재 아이템을 위로 이동
			items[idx].top -= options.step;
			if (idx==this._nextIdx && items[idx].top <= 0) {
				items[idx].top = 0;
				oerflow = true;
			}
			items[idx].style.top = items[idx].top + "px";
			
			// 다음 아이템이 정지 위치에 올 경우
			if (oerflow) {
				if (this._Executer) this._Executer.stop();

				// 현재 아이템(위로 사라진)을 대기 위치로 이동
				items[this._curIdx].top = options.readyPos;
				items[this._curIdx].style.top = items[this._curIdx].top + "px";

				// 현재, 다음 아이템 인덱스 증가
				if (++this._curIdx>=this._itemCnt) this._curIdx = 0;
				if (++this._nextIdx >= this._itemCnt) this._nextIdx = 0;
			
				// 스크롤 다시 시작			
				this._start();
			}
		}.bind(this));
	}
};

/*============================================================================*
 * Floating
 *============================================================================*/
Empas.UI.Floating = Class.create();

Empas.UI.Floating.prototype = {
	/**
	 * 생성자
	 * 
	 * @param {String} id 적용할 엘리먼트 아이디
	 * @param {Object} options 옵션
	 * @constructor
	 */
	initialize: function(id, options) {
		this._el = $(id);
		if (!this._el) return;
		
		this._options = Object.extend({
			xMargin: 10,		// X 마진 
			yMargin: 10,		// Y 마진
			xMode: "left",		// X 모드 : left, right, center, center_add
			yMode: "top",		// Y 모드 : top, middle, bottom
			duration: 0.04,	// 이동 체크 시간(초)
			width: this._el.getWidth(),
			height: this._el.getHeight()
		}, options || {});

		options = this._options;

		// yMode에서 사용하기 위한 초기 yMargin 값
		options.yOrgMargin = options.yMargin;

		// yMode에 따른 yMargin값 변경
		this._arragePositionY();
		
		// 루트 엘리먼트 스타일 설정
		this._el.setStyle( {
			position : "absolute",
			top : options.yMargin + "px"
		});
		
		// xMode에 따른 x 위치 변경
		this._arragePositionX();
		
		// 윈도우 크기 변경시 위치 보정
		Event.observe(window, "resize", function () {
			this._arragePositionX();
			this._arragePositionY();
		}.bind(this));

		this.start();
	},
	
	/**
	 * xMode에 따른 x 위치 변경
	 */
	_arragePositionX: function() {
		var docWidth = document.body.clientWidth;
		var options = this._options;
		var xPos = options.xMargin;

		// X 좌표 구하기
		switch(this._options.xMode) {
			case "center_add":
				xPos = parseInt(docWidth/2,10) + options.xMargin;
			break;

			case "right":
				xPos = docWidth - options.width - options.xMargin;
			break;

			case "center":
				xPos = parseInt((docWidth - options.width)/2, 10);
			break;
		}

		this._el.style.left = xPos + "px";
	},
	
	/**
	 * yMode에 따른 yMargin값 변경
	 */	
	_arragePositionY: function() {
		var options = this._options;
		if (options.yMode=="middle") {
			options.yMargin = parseInt((document.body.clientHeight - options.height)/2, 10);
		} else if (options.yMode=="bottom") {
			options.yMargin = document.body.clientHeight - options.height - options.yOrgMargin;
		}
	},
	
	/**
	 * 주기적인 이동함수 실행
	 */	
	start: function() {
		this.stop();		
		this._Executer = new PeriodicalExecuter(function () {
			this._move();
		}.bind(this), this._options.duration);
	},
	
	/**
	 * 이동함수 실행 멈춤
	 */	
	stop: function() {
		if (this._Executer) this._Executer.stop();
	},
	
	/**
	 * 엘리먼트 이동
	 */	
	_move: function() {
		// 시작(현재) 위치
		var startPos = parseFloat(this._el.style.top);
		if (!startPos) startPos = 0;
		
		// 목표 위치
		var endPos = document.body.scrollTop + document.documentElement.scrollTop + this._options.yMargin;
		
		// 이동 방향 (+, -)
		var dir = (endPos < startPos) ? -1:1;

		// 이동
		if (startPos != endPos) {
			var amount = Math.ceil(Math.abs(endPos-startPos)/5);
			this._el.style.top = (startPos + (dir * amount)) + "px";
		} else {
			this.start();
		}
	}
};

