/*! Copyright (c) 2009 Hiroshi Seo (http://www.aerialline.com/)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 0.1
 * 
 */
(function(){

var AppID = "MangView";
var container,book,spread,control;

// main　エントリーポイント
function main(event) {
	event.preventDefault();

	// 各種オブジェクト作成
	container			= new Container();			
		book			= new Book(container);
			spread		= new Spread(book);
			control		= new ControlPanel(book);
			
	// イベントリスナの登録
	$(book).bind("BOOK_UPDATED",bookUpdated);
	$(container).bind("QUIT",quit);
	$(control.$).bind('slide',function(event, ui){pageChange(ui.value);});
	$(control).bind('NEXT',function(event){next();});
	$(control).bind('PREV',function(event){prev();});
	$(control).bind('NEXT1',function(event){next1();});
	$(control).bind('PREV1',function(event){prev1();});
	$(control).bind('QUIT',function(event){quit();});
	$(spread).bind('PAGE_CHANGE',function(event, pageNum){pageChange(pageNum);});
	
	//　ブックデータのロード
	book.load($(this).attr("href"));
	
};

// イベントハンドラ
function bookUpdated (){
	spread.init(book.pages,book.pageNum,book.mode,book.direction,book.startSide);
	control.init(book.title,book.author,book.description,book.pages.length-1,book.pageNum,book.mode);

}
function pageChange (pageNum){
	if (pageNum < 0 || pageNum > book.pages.length -1) { return;}
	book.pageNum = pageNum;
	spread.show(pageNum);
	control.page(pageNum);
}
function quit(){
	spread.finalize(); 		spread 		= null;
//	slider.finalize(); 		slider 		= null;
	book.finalize();		book 		= null;
	container.finalize(); 	container 	= null;
}
function next(){
	spread.next();
}
function prev(){
	spread.prev();
}
function prev1(){
	pageChange(book.pageNum-1);
}
function next1(){
	pageChange(book.pageNum+1);
}


//Container
//コンストラクタ
function Container(){
	// オーバーレイとコンテナのHTML挿入
	this.$ 		= $("<div id='" + AppID + "_Container'></div>").appendTo("body");
	this.$background = $("<div id='" + AppID + "_BG'></div>").appendTo(this.$);
//	this.$overlay.fadeIn("slow");
	this.$.fadeIn("slow");
	
	//　イベントリスナ登録
	// クリック時
	(function(self){
		self.$.one("click",function(e){$(self).trigger("QUIT");})  
	;})(this);	
}
Container.prototype.finalize = function(){
	(function(o){  o.$.fadeOut("nomal",function(){o.$.remove();}) ;})(this);
};



//Book
//コンストラクタ
function Book (parentObj){
	this.$ 			= $("<div id='" + AppID + "_Book'></div>").prependTo(parentObj.$);
	this.title 			= "No Title";
	this.description 	= "No Description";
	this.author 		= "Unknown";
	this.mode			= 2;
	this.direction		= 2;
	this.startSide		= "left";
	this.pages;
	this.pageNum		= 0;
	
};
Book.prototype.load = function(url){
 	(function(self){
		$.getJSON(url,null,function (data,status){self.update(data);});
	})(this);
};
Book.prototype.update = function(data){
	$.extend(this,data);
	this.pageNum = 0;
	$(this).trigger("BOOK_UPDATED");
};
Book.prototype.finalize = function(){
	this.$.remove();
};



// Spread
//　コンストラクタ
function Spread(parentObj){
	// 生成時に決定される変数
	this.id = AppID + "_Spread";
	this.$ = $("<div id='" + this.id + "'>").appendTo(parentObj.$);
	this.$loading	= $("<div/>").appendTo(this.$).attr("id",AppID + "_Loading");
	
	// 情報読み込み時に更新される変数
	this.mode		= 2;
	this.direction 	= "rtl";	// 読み方向
	this.startSide	= "left";	// 
	this.pageNum	= 0;		// 表示されている最初のページ番号
	this.pageList	= [];		// ページデータ

	this.pages 		= [];		// ページオブジェクトのリスト
	this.pageIndex;				//　表示されている最後のページ番号
	
	this.loadingCue = [];		//
	
	this.preloader;
	
	//　スプレッドをリサイズ
//	this.resizeSpread();
	
	// イベントリスナの登録
	// リサイズ
	(function(o){  $(window).resize(function(e){o.resizePages();})  ;})(this);	// リサイズ時
	// マウスホイール
	(function(o){  
		o.$.mousewheel( function(event, delta){
			if (delta > 0) { o.prev(); event.preventDefault();} else { o.next();event.preventDefault();}
		});
	;})(this);
	(function(o){  o.$.bind("PAGE_LOADING",function(e,target){o.showLoading(target);})  ;})(this);
	(function(o){  o.$.bind("PAGE_LOADED",function(e,target){o.hideLoading(target);})  ;})(this);

};
// パブリックメソッド
Spread.prototype.init= function(pageList,pageNum,mode,direction,startSide){
	//　プロパティを設定
	this.mode	 	= mode || this.mode;
	this.direction 	= direction || this.direction;
	this.startSide 	= startSide || this.startSide;
	this.pageList 	= pageList;
	
	// プリローダ
	var sources = $.map(this.pageList, function(page, i){ return page.source; });
	this.preloader  = new Preloader(sources);
	
	//　ページを表示
	this.show(pageNum);
};
Spread.prototype.show = function(pageNum){

//	// 存在しないページの場合終了
//	if (pageNum < 0 || pageNum > this.pageList.length -1) { return;}
	
	this.preloader.load(pageNum);
	
	// 表示枚数を決定
	var total;
	if (this.mode == 1){
		total = 1;
	} else if (this.mode == 2){
		switch(pageNum){
			//　最初のページの場合
			case 0:
				if ((this.direction == "rtl" && this.startSide == "left")|| (this.direction == "ltr" && this.startSide == "right")) {
					total = 1;
				} else {
					total =2;
				}
				break;
			// 最後のページの場合
			case this.pageList.length -1:
				total = 1;
				break;
			// それ以外
			default:
				total = 2;
		}
	}
	
	// 表示枚数に応じて、ページオブジェクトの数をリセット
	if (this.pages.length != total) {
		this.removeAllPages();
		this.insertPages(total);
	}
	
	// 表示
	for ( var i = 0; i < total; i++) {
		this.pages[i].show(this.pageList[pageNum+i]);
		
	}
	
	
	// ページのインデックス更新
	this.pageNum = pageNum;
	this.pageIndex = pageNum + total -1;

	
};
Spread.prototype.next = function(){
	var nextPage = this.pageIndex + 1;
	if (nextPage <= this.pageList.length-1){
	$(this).trigger("PAGE_CHANGE",[nextPage]);
		
	}
};
Spread.prototype.prev = function(){
	var prevPage =  this.pageNum - this.mode;
	if (prevPage < 0){ prevPage = 0 ;}
	$(this).trigger("PAGE_CHANGE",[prevPage]);
};
Spread.prototype.insertPages = function(total){
	// 読み方向に応じてページを挿入
	var maxWidth = parseInt(this.$.width() / total) ;
	var maxHeight = this.$.height();
	if (this.direction == "ltr") {
		for (var i = 0; i < total; i++) {
			this.pages.push( new Page(this.$,i,maxWidth,maxHeight));
		}
	} else if (this.direction == "rtl") {
		for (var i = total; i > 0; i--) {
			this.pages.unshift( new Page(this.$,i,maxWidth,maxHeight));
		}
	}
	// Next/Prevのイベントを設置
	(function(o){  o.pages[o.pages.length-1].$.click(function(e){o.next();e.stopPropagation();})  ;})(this);
	(function(o){  o.pages[0].$.click(function(e){o.prev();e.stopPropagation();})  ;})(this);

};
Spread.prototype.removeAllPages = function(){
	while (this.pages.length) {
		var page = this.pages.pop();
		page.finalize();
	}		
};
Spread.prototype.resizePages = function(){	
	var maxWidth = parseInt(this.$.width() / this.pages.length);
	var maxHeight = this.$.height();
	for (var i = 0; i < this.pages.length;i++){
		var page = this.pages[i];
		page.maxWidth = maxWidth;
		page.maxHeight = maxHeight;
		page.resize();
	}
};
Spread.prototype.showLoading = function(target){
	this.loadingCue.push(target);
	this.$loading.show();
};
Spread.prototype.hideLoading = function(target){
	var index = $.inArray(target,this.loadingCue);
	if (index === -1) { return;}
	this.loadingCue.splice(index,1);
	if (this.loadingCue.length == 0) {
		this.$loading.hide();
	}

};

Spread.prototype.finalize = function(){
	$(window).unbind("resize",this.update);
	if (this.pages) { this.removeAllPages(); }
	this.$.remove();
};


// Page
function Page($parent,idNum,maxWidth,maxHeight){
	this.source = "";
	this.id = AppID + "_Page" + idNum;
	this.$ = $("<img src='" + this.source + "' id='" + this.id + "' class='" + AppID + "_Page" + "'/>").appendTo($parent);
	this.maxWidth = maxWidth;
	this.maxHeight = maxHeight;
	
};

Page.prototype.show = function(page){
	if (!page || !page.source){ return;}
	var source = page.source;
	this.image = new Image();
    this.image.src = source;
    
    if (this.image.complete == true) { 
        // 画像のロードが完了していれば、次へ
    	this.loaded();
     } else {
    	 this.$.css("display","none");
    	 this.$.trigger("PAGE_LOADING",[this]);
    		
  	 //　ロード完了時のイベント
    	 (function(o){ o.image.onload = function(e){o.loaded(e);}  ;})(this);
    }
};
Page.prototype.loaded = function(){
	this.$.trigger("PAGE_LOADED",[this]);
	this.resize();
	this.$.attr("src",this.image.src);
	this.$.css("display","inline");

};
Page.prototype.resize = function(){

	var maxWidth = (this.maxWidth < this.image.width)? this.maxWidth : this.image.width;
	var maxHeight = (this.maxHeight < this.image.height)? this.maxHeight : this.image.height;
	var ratioX,ratioY;
	var scale;
	var newWidth,newHeight;

	// 比率
	ratioX = maxWidth /  this.image.width;
	ratioY = maxHeight / this.image.height;
	scale = ratioX < ratioY ? ratioX : ratioY;

	// 新しいサイズを計算して設定
	newWidth = parseInt(this.image.width * scale, 10);
	newHeight = parseInt(this.image.height * scale, 10);
	this.$.attr({ "width": newWidth,"height": newHeight });
	
};
Page.prototype.finalize = function(){
	this.$.remove();
//	this.$loading.remove();
};

// Preloader
function Preloader(souces){
	this.sources = souces || [];
	this.pos;
	this.preNum		= 6;
	this.postNum	= 6;
	
	this.images;
}
Preloader.prototype.load = function(pos){

	if (pos < 0 || pos > this.sources.length-1){ return; }
	this.pos = pos;

	var start = pos - this.preNum;
	if (start < 0) { start = 0 ;}
	var end = pos + this.postNum;
	if (end > this.sources.length-1) { end = this.sources.length-1;}
	
	this.images = [];
	for (var i = start; i<= end; i++){
		var image = new Image;
		image.src = this.sources[i];
		this.images.push(image);
	}
};

//Control Panel

function ControlPanel(parentObj){
	this.$ 					= $("<div id='" + AppID + "_ControlPanel'/>").appendTo(parentObj.$);

	this.$containerAll		= $("<div id='" + AppID + "_ControlPanel_Container'/>").appendTo(this.$);
		this.$leftContainer 	= $("<div id='" + AppID + "_ControlPanel_LCT'/>").appendTo(this.$containerAll).addClass(AppID+"_ControlPanel_CT");
		this.$centerContainer 	= $("<div id='" + AppID + "_ControlPanel_CCT'/>").appendTo(this.$containerAll).addClass(AppID+"_ControlPanel_CT");
		this.$rightContainer 	= $("<div id='" + AppID + "_ControlPanel_RCT'/>").appendTo(this.$containerAll).addClass(AppID+"_ControlPanel_CT");
	this.$background 		= $("<div id='" + AppID + "_ControlPanel_BG'/>").appendTo(this.$);
	this.$title 			= $("<div id='" + AppID + "_Title'/>").appendTo(this.$centerContainer);
	this.$author 			= $("<div id='" + AppID + "_Author'/>").appendTo(this.$centerContainer);
	this.$description 		= $("<div id='" + AppID + "_Description'/>").appendTo(this.$centerContainer);
	this.$slider 			= $("<div id='" + AppID + "_Slider'/>").appendTo(this.$centerContainer);

	
	// 左コンテナ
//	var $left				= $("<div/>").appendTo(this.$centerContainer).attr("id",AppID+"_LeftButtons");

	
	//　中央コンテナ
	var $pButtons			= $("<div/>").appendTo(this.$centerContainer).attr("id",AppID+"_PrevButtons");
	this.$prev 				= $("<span/>").appendTo($pButtons)
									.attr("id",AppID+"_Icon_Prev").addClass( AppID + '_Icon');
	this.$prev1				= $("<span/>").appendTo($pButtons)
									.attr("id",AppID+"_Icon_Prev1").addClass( AppID + '_Icon');
	var $nButtons			= $("<div/>").appendTo(this.$centerContainer).attr("id",AppID+"_NextButtons");
	this.$next1 				= $("<span/>").appendTo($nButtons)
									.attr("id",AppID+"_Icon_Next1").addClass( AppID + '_Icon');
	this.$next				= $("<span/>").appendTo($nButtons)
									.attr("id",AppID+"_Icon_Next").addClass( AppID + '_Icon');
							
	this.$pageNum 			= $("<span id='" + AppID + "_PageNum'/>").appendTo(this.$centerContainer);

	// 右コンテナ
	var $right				= $("<div/>").appendTo(this.$rightContainer).attr("id",AppID+"_RightButtons");
	this.$quit				= $("<span/>").appendTo($right)
									.attr("id",AppID+"_Icon_Quit").addClass( AppID + '_Icon');

//	this.containerAll 		= $("."+AppID+"_ControlPanel_CT");

	
	this.total 	= 0;
	//　イベントリスナ
	(function(self){
		self.$.bind("click",function(e){ return false;});
		self.$.bind("mouseenter",function(e){ self.show();});
		self.$.bind("mouseleave",function(e){ self.hide();});
		self.$next.bind("click",function(e){ $(self).trigger("NEXT");});
		self.$prev.bind("click",function(e){ $(self).trigger("PREV");});
		self.$next1.bind("click",function(e){ $(self).trigger("NEXT1");});
		self.$prev1.bind("click",function(e){ $(self).trigger("PREV1");});
		self.$quit.bind("click",function(e){ $(self).trigger("QUIT");});
	})(this);	

}
ControlPanel.prototype.init = function(title,author,description,total,pageNum,mode){
	
	// 
	this.$title.text(title);
	this.$author.text(author);
	this.$description.text(description);
	this.$slider.slider({
		animate	: true ,
		max		: total ,
		value	: pageNum,
		step	: 1
	});
	this.$pageNum.text((pageNum+1)+" / "+total);
	
	this.total = total;
	
	// アニメーション
	this.$.animate({height: "+=0px"},{duration:1000,queue:true});
	this.$.animate({bottom:-25},{duration:"slow"});
	this.$centerContainer.animate({height: "+=0px"},{duration:1000,queue:true});
	this.$centerContainer.fadeOut("slow");
	this.$rightContainer.animate({height: "+=0px"},{duration:1000,queue:true});
	this.$rightContainer.fadeOut("slow");
	this.$background.animate({height: "+=0px"},{duration:1000,queue:true});
	this.$background.fadeOut("slow");
	
};
ControlPanel.prototype.show = function(){
	this.$.animate({bottom:0},{duration:"slow",queue:true});
	this.$centerContainer.fadeIn("slow");
	this.$rightContainer.fadeIn("slow");
	this.$background.fadeIn("slow");
};
ControlPanel.prototype.hide = function(){
	this.$.animate({bottom:-25},{duration:"slow",queue:true});
	this.$centerContainer.fadeOut("slow");
	this.$rightContainer.fadeOut("slow");
	this.$background.fadeOut("slow");
};
ControlPanel.prototype.finalize = function(){
	this.$.remove();
};
ControlPanel.prototype.page = function(pageNum){
	this.$slider.slider("value",pageNum);
	this.$pageNum.text((pageNum+1)+ " / " +(this.total+1));
};



// アンカータグのクリックイベントをフックして起動
$(document).ready(function(){ $("a[class=" + AppID + "]").click(main);});

})();
