/**
 * @fileOverview 리스트에 페이지 목록 매기고 페이지에 따른 네비게이션을 구현한 컴포넌트
 * @author senxation
 */
nhn.Pagination = new jindo.$Class({
	/** @lends nhn.Pagination */
	
	/**
	 * 리스트에 페이지 목록 매기고 페이지에 따른 네비게이션을 구현한 컴포넌트.
	 * 기본 목록은 마크업에 static하게 정의되어있고, 페이지 이동을위해 클릭시마다 보여줄 아이템 목록을 Ajax Call을 통해 받아온다.
	 * 페이지 컴포넌트가 로드되면 .loaded 클래스명이 추가된다.
	 * @constructs
	 * @param {String | HTMLElement} sId 페이지목록을 생성할 엘리먼트 id 혹은 엘리먼트 자체
	 * @param {Object} oOption 옵션 객체
	 * @example 
var oPagination = new nhn.Pagination("paginate", {
	item : 1000, //전체 아이템 개수
	itemPerPage : 10, //한 페이지에 표시될 아이템 개수
	pagePerPageList : 10, //페이지목록에 표시될 페이지 개수
	page : 1, //초기 페이지
	moveUnit : "pagelist", //페이지목록 이동시 이동 단위 "page" || "pagelist"
	alignCenter : false //현재페이지가 항상 가운데 위치하도록 정렬. moveUnit이 "page"일 때만 사용
}).attach({
	click : function(e) {
		//페이지 이동을 위해 클릭했을때 발생
		//전달되는 이벤트 객체 e = {
		//	page : (Number) 클릭된 페이지
		//}
		//e.stop()을 수행하면 페이지 이동(loaded 이벤트)이 일어나지 않는다.
	},
	loaded : function(e) {
		//페이지 이동이 완료된 이후 발생
		//전달되는 이벤트 객체 e = {
		//	page : (Number) 현재 페이지
		//}
	}
});
	 */
	$init : function(sId, oOption){
		this._elPageList = jindo.$(sId);
		this._elCurrentPage = jindo.$("<strong>");
		this._elPage = jindo.$("<a>");
		jindo.$Element(this._elPage).attr("href","#");
		
		this._elAPrevEndPage = cssquery.getSingle("a.pre_end", this._elPageList);
		this._elAPrevPage = cssquery.getSingle("a.pre", this._elPageList);
		this._elANextEndPage = cssquery.getSingle("a.next_end", this._elPageList);
		this._elANextPage = cssquery.getSingle("a.next", this._elPageList);
		this._elSpanPrevEndPage = cssquery.getSingle("span.pre_end", this._elPageList);
		this._elSpanPrevPage = cssquery.getSingle("span.pre", this._elPageList);
		this._elSpanNextEndPage = cssquery.getSingle("span.next_end", this._elPageList);
		this._elSpanNextPage = cssquery.getSingle("span.next", this._elPageList);
		
		this._fClickPage = jindo.$Fn(this._onClickPageList, this);
		this._fClickPage.attach(this._elPageList, "click");
		
		this.option({
			item : 10,
			itemPerPage : 10,
			pagePerPageList : 10,
			page : 1,
			moveUnit : "pagelist",
			alignCenter : false
		});
		if (oOption) this.option(oOption);
		
		this.setItemCount(this.option("item"));
		this.movePageTo(this.option("page"));
		
		jindo.$Element(this._elPageList).addClass("loaded");
	},
	/**
	 * 전체 아이템의 개수를 리턴한다.
	 * @return {Number} 아이템 개수
	 */
	getItemCount : function() {
		return this.option("item");
	},
	
	/**
	 * 전체 아이템의 개수를 설정한다.
	 * @param {Number} n 아이템 개수
	 */
	setItemCount : function(n) {
		this.option({"item" : n});
	},
	
	/**
	 * 한 페이지에 보여줄 아이템의 개수를 구한다.
	 * @return {Number} 한 페이지에 보여줄 아이템의 개수
	 */
	getItemPerPage : function() {
		return this.option("itemPerPage");
	},
	
	/**
	 * 한 페이지에 보여줄 아이템의 개수를 설정한다.
	 * @param {Object} n 아이템 개수
	 */
	setItemPerPage : function(n) {
		this.option("itemPerPage", n);
	},
	
	/**
	 * 현재 페이지를 리턴한다.
	 * @return {Number} 현재 페이지
	 */
	getCurrentPage : function() {
		return this._nCurrentPage;
	},
	
	_getLastPage : function() {
		return Math.ceil(this.getItemCount() / this.getItemPerPage());
	},

	_getRelativePage : function(sRelative) {
		var nPage = null;

		if (this.option("moveUnit") == "page") {
			switch (sRelative) {
				case "pre" :
					nPage = this.getCurrentPage() - 1;
				break;
				case "next" :
					nPage = this.getCurrentPage() + 1;
				break;
			}
		}
		else {
			var nThisPageList = this._getPageList(this.getCurrentPage());
			switch (sRelative) {
				case "pre_end" :
					var nLastPageOfPrePageList = (nThisPageList - 1) * this.option("pagePerPageList");
					nPage = 1;
				break;
				case "pre" :
					var nLastPageOfPrePageList = (nThisPageList - 1) * this.option("pagePerPageList");
					nPage = nLastPageOfPrePageList;
				break;
				case "next" :
					var nFirstPageOfNextPageList = (nThisPageList) * this.option("pagePerPageList") + 1;
					nPage = nFirstPageOfNextPageList;
				break;
				case "next_end" :
					nPage = this._getLastPage();
				break;
			}
		}
		
		return nPage;
	},
	
	/**
	 * 몇번째 페이지 리스트인지 구함
	 * @param {Number} nThisPage
	 */
	_getPageList : function(nThisPage) {
		if (this.option("alignCenter")) {
			var nLeft = Math.floor(this.option("pagePerPageList") / 2);
			var nPageList = nThisPage - nLeft;
			if (nPageList < 1) nPageList = 1;
			if (nPageList > this._getLastPage()) nPageList = this._getLastPage();
			return nPageList;
		}
		return Math.ceil(nThisPage / this.option("pagePerPageList"));
	},
	
	_onClickPageList : function(e) {
		e.stop($Event.CANCEL_DEFAULT);
		
		var nPage = null;
		
		var el = e.element;
		if (el.tagName != "A") {
			el = cssquery.getSingle("! a", el);
			if (!el) return;
		}
		
		var we = jindo.$Element(el);
		if (we.hasClass("pre_end") || we.hasClass("pre") || we.hasClass("next") || we.hasClass("next_end")) {
			if (we.hasClass("pre_end")) {
				nPage = this._getRelativePage("pre_end");
			}
			else if (we.hasClass("pre")) {
				nPage = this._getRelativePage("pre");
			}
			else if (we.hasClass("next")) {
				nPage = this._getRelativePage("next");
			}
			else if (we.hasClass("next_end")) {
				nPage = this._getRelativePage("next_end");				
			}
		}
		else {
			var nPage = parseInt($Element(el).text());
		}
		
		if (!this.fireEvent("click", {element:el, page:nPage})) return;
		this.movePageTo(nPage);
	},
	
	/**
	 * 지정한 페이지로 이동하고 페이지 목록을 다시 그린다.
	 * 아이템 개수가 하나도 없으면 .no-result 페이지 목록이 하나밖에 없으면 .only-one 클래스명이 추가된다.  
	 * @param {Number} nPage 이동할 페이지 
	 */
	movePageTo : function(nPage){
		this._empty();

		var nLastPage = this._getLastPage();
		
		if (nLastPage == 0) {
			jindo.$Element(this._elPageList).addClass("no-result");
		}
		else if (nLastPage == 1) {
			jindo.$Element(this._elPageList).addClass("only-one");
		}
		else {
			jindo.$Element(this._elPageList).removeClass("only-one").removeClass("no-result");
		} 
		
		if (nPage < 1) nPage = 1;
		if (nPage > nLastPage) nPage = nLastPage;

		this._nCurrentPage = nPage;
		this._paginate(nPage);
		this.fireEvent("loaded",{page:nPage});
	},
	
	/**
	 * 페이징을 다시 그린다.
	 * @param {Number} nItemCount 아이템의 개수가 바뀌었을 경우 설정해준다.
	 */
	reset : function(nItemCount) {
		if (typeof nItemCount == "undefined") var nItemCount = this.option("item");
		else var nItemCount = nItemCount;
		
		this.setItemCount(nItemCount);
		this.movePageTo(1);
	},
	
	_paginate : function(nPage){
		this._empty();
		var nLastPage = this._getLastPage();
		var nThisPageList = this._getPageList(nPage);
		var nLastPageList = this._getPageList(nLastPage);
		
		if (this.option("alignCenter")) {
			var nLeft = Math.floor(this.option("pagePerPageList") / 2);
			var nFirstPageOfThisPageList = nPage - nLeft;
			if (nFirstPageOfThisPageList < 1) {
				nFirstPageOfThisPageList = 1;
			}
			var nLastPageOfThisPageList = nFirstPageOfThisPageList + this.option("pagePerPageList") - 1;
			if (nLastPageOfThisPageList > nLastPage) {
				nFirstPageOfThisPageList = nLastPage - this.option("pagePerPageList") + 1;
				if (nFirstPageOfThisPageList < 1) {
					nFirstPageOfThisPageList = 1;
				}
				nLastPageOfThisPageList = nLastPage;
			}
		}
		else {
			var nFirstPageOfThisPageList = (nThisPageList - 1) * this.option("pagePerPageList") + 1;
			var nLastPageOfThisPageList = (nThisPageList) * this.option("pagePerPageList");
			if (nLastPageOfThisPageList > nLastPage) nLastPageOfThisPageList = nLastPage;
		}
		

		if ((nThisPageList > 1) || (this.option("moveUnit") == "page" && nPage > 1)) {
			if (this._elAPrevEndPage) jindo.$Element(this._elPageList).append(this._elAPrevEndPage);
			jindo.$Element(this._elPageList).append(this._elAPrevPage);
		}
		else {
			if (this._elSpanPrevEndPage) jindo.$Element(this._elPageList).append(this._elSpanPrevEndPage);
			if (this._elSpanPrevPage) jindo.$Element(this._elPageList).append(this._elSpanPrevPage);	
		}		

		//this._elPageList.appendChild(document.createTextNode("\n"));
		for (var i = nFirstPageOfThisPageList; i <= nLastPageOfThisPageList ; i++) {
			if (i == nPage) {
				var el = this._elCurrentPage.cloneNode(true);
			}
			else {
				var el = this._elPage.cloneNode(true);
			}
			if (i == nFirstPageOfThisPageList) {
				jindo.$Element(el).addClass("first-child");
			}
			jindo.$Element(el).text(i.toString());
			jindo.$Element(this._elPageList).append(el);
			
			//this._elPageList.appendChild(document.createTextNode("\n"));
		}

		if ((nThisPageList < nLastPageList) || (this.option("moveUnit") == "page" && nPage < nLastPage)) {
			jindo.$Element(this._elPageList).append(this._elANextPage);
			if (this._elANextEndPage) jindo.$Element(this._elPageList).append(this._elANextEndPage);	
		}
		else {
			if (this._elSpanNextPage) jindo.$Element(this._elPageList).append(this._elSpanNextPage);
			if (this._elSpanNextEndPage) jindo.$Element(this._elPageList).append(this._elSpanNextEndPage);
		}
	},
	
	_empty : function(){
		if (this._elAPrevEndPage) this._elAPrevEndPage = this._elAPrevEndPage.cloneNode(true); 
		if (this._elAPrevPage) this._elAPrevPage = this._elAPrevPage.cloneNode(true); 
		if (this._elANextEndPage) this._elANextEndPage = this._elANextEndPage.cloneNode(true);
		if (this._elANextPage) this._elANextPage = this._elANextPage.cloneNode(true);
		if (this._elSpanPrevEndPage) this._elSpanPrevEndPage = this._elSpanPrevEndPage.cloneNode(true);
		if (this._elSpanPrevPage) this._elSpanPrevPage = this._elSpanPrevPage.cloneNode(true);
		if (this._elSpanNextEndPage) this._elSpanNextEndPage = this._elSpanNextEndPage.cloneNode(true);
		if (this._elSpanNextPage) this._elSpanNextPage = this._elSpanNextPage.cloneNode(true);
		jindo.$Element(this._elPageList).empty();
	}
}).extend(nhn.Component);

