//TODO: add chapter views updating functionality
//constant for bidirectional buffer size
var fBlockSize = 5;
var pBlockSize = 3;
var nhref = '';
var phref = '';
var executing = 0; //semaphore to indicate executing
var currBlock = {};
var prevBlock = {};
var currPageObj = null;
var currChapter;
var currPage
var chapters;
var update;
var series;
var chapterList;
var pageList;

//last page lightbox html
var lastPageHTML = '<div id="facebox" style="background: transparent url(/img/popup_bg2.png) no-repeat scroll 0% 0%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; position: absolute; z-index: 400; height: 312px; width: 495px; text-align: center; display: none;"><p style="font-size: 1.3em; color: white; text-align: left; font-weight: bold; margin-top: 120px; margin-left: 100px; margin-bottom: 10px; width: 290px;">You have reached last page of this series. Click <a href="/mangas/" class="overlaylink">here</a> to read more!</p><div class="content"></div><a href="#" class="bluebutton close">Cancel<span class="bluebutton_left"/></a></div>';
//these happen when the url is initialized or changed
$(document).ready(function(){
	updateAll(window.location.hash);
	//navigation stuff
	$(document).keypress(function (e){
		if(e.keyCode==37)
			window.location.hash = phref;
		else if(e.keyCode==39)
			window.location.hash = nhref;
	});
	$("#mangaPage").click(function(){
		window.location.hash = nhref;
	});
});
//begin history event capturing:
//uses jquery.history plugin from http://plugins.jquery.com/project/history-hashchange
$(init);
function init(){
	$(window).history(function(e,ui){
		updateAll(ui.value);
	});
};
//end history event capturing

//called when url changes or when user enters the page
function updateAll(hash){
	if(series=="FAIL"){
		showFAIL();
		return;
	}
	//putting current block elements into previous block. for gc later
	$.each(currBlock,function(k,v){
		prevBlock[k]=v;
	});
	currBlock = {};
	if(!hash)
		hash = firstChapter;
	
	//sometimes window.location.hash contains the hash char as well
	if(hash.charAt(0)=="#")
		hash = hash.substr(1);
	
	//setting page and chapter
	if(hash.indexOf("/")!=-1){
		hashArr = hash.split("/");
		chap = hashArr[0];
		currPage = hashArr[1];
	}
	else{
		chap = hash;
		currPage = 1;
	}
	//chapter selector UI updates
	updateChapterSelectors(chap);

	//chapter data updates
	chapterList[chap].getPageList();
	//page selector UI update
	chapterList[chap].fillPageSelect(chap);
	currChapter = chap;
	//get the blocks
	currPageObj = chapterList[currChapter].pageList[currPage];
	//update chapter view data, user shelf data
	if(currPageObj==chapterList[chap].lastpage)
		updateDBInfo(chap,currPage);
	if(!currPageObj){
		showFAIL();
		return;
	}
		
	//load page image
	currPageObj.loadImage(function(){
		$("#mangaPage").empty().append(currPageObj.img);
		$.scrollTo("#mangaRead",0);
		currBlock[currPageObj.id] = currPageObj;
		startFillBlock();
	});
	//get links asap
	nextPageObj = currPageObj.getNext();
	prevPageObj = currPageObj.getPrev();
	nhref = phref = "";
	if(nextPageObj)
		nhref="#"+nextPageObj.hash;
	else{
		//nhref="javascript:$.facebox(lastPageHTML)";
		nhref = "#block";
		//we hack facebox plugin's html settings to get our own lightbox
		$(".nextBtn").facebox({faceboxHtml:lastPageHTML});
	}
	$(".nextBtn").attr("href",nhref);
	if(prevPageObj)
		phref="#"+prevPageObj.hash;
	$(".prevBtn").attr("href",phref);
}

function updateDBInfo(chap,currPage){
	//send series id, chapter id
	data = {"data[Chapter][series_id]":series,"data[Chapter][chapter_id]":chapterList[chap].id};
	$.post("/mangas/updateChapterStats",data);
}

function startFillBlock(){
	//fill block
	//executing+=2;
	if(nextPageObj){
		currBlock[nextPageObj.id] = nextPageObj;
		setTimeout("nextPageObj.loadImage(function(){fillBlock(nextPageObj,fBlockSize-1,'getNext');});",1);
	}
	if(prevPageObj){
		currBlock[prevPageObj.id] = prevPageObj;
		setTimeout("prevPageObj.loadImage(function(){fillBlock(prevPageObj,pBlockSize-1,'getPrev');});",1);
	}

}

//fills block in either direction
function fillBlock(pageObj,count,functor){
	if(count==0||!pageObj){
		executing--;
		//debug("executing " + executing,true);
		if(executing==0){
			removeRefuse();
		}
		return;
	}
	count--;
	pageObj = pageObj[functor]();
	if(pageObj){
		pageObj.loadImage(fillBlockCallbackCreator(pageObj,count,functor));
	}
}

//returns a callback function that will call fillBlock again
function fillBlockCallbackCreator(pageObj,count,functor){
	return function(){
		currBlock[pageObj.id] = pageObj;
		fillBlock(pageObj,count,functor);
	};
}

//deferred implementation because of concurrency issues
function removeRefuse(){
	/*$.each(prevBlock,function(k,v){
		if(currBlock[k]==undefined){
			debug("killing " + v.id,true);
			v.unloadImage();
		}
	});
	prevBlock = {};*/
}

//display FAIL
function showFAIL(){
	$("#mangaPage").html('<img src="/img/failsnail.png" />');
}

//get next and previous images
function weBeFronting(){
}

function updateChapterSelectors(chapter){
	var ids = ['#ChapterNumberTop','#ChapterNumberBottom'];
	for(i=0;i<ids.length;i++){
		changeSelected(ids[i],chapter);
	}
}

//match an option's value to val and makes it selected
function changeSelected(selectId,checkText){
	if($(selectId + " :selected").text() == checkText)
		return;
	options = $(selectId+" > option");
	for(j=0;j<options.length;j++){
		if($(options[j]).text()==checkText){
			options[j].selected = true;
			break;
		}
	}
}

//event callbacks for the chapter and page selectors
//these basically change the url.
function gotoPageTop(){
	window.location.hash = $("#PageNumberTop").val();
}

function gotoPageBottom(){
	window.location.hash = $("#PageNumberBottom").val();
}

function gotoChapterTop(){
	window.location.hash = $("#ChapterNumberTop :selected").text()+"/1";
}

function gotoChapterBottom(){
	window.location.hash = $("#ChapterNumberBottom :selected").text()+"/1";
}
//end chapter selectors event callbacks

//end event callbacks for chapter and page selectors

//object prototypes

//Chapter object
function Chapter(){
	this.prev = null;
	this.next = null;
	this.id = null;
	this.firstpage = null;
	this.lastpage = null;
	this.name = "";
	this.pageArray = [];
	this.pageList = {};
	this.pageBuilt = false;

	if(arguments.length>0)
		this.prev = arguments[0];
	if(arguments.length>1)
		this.id = arguments[1];
	if(arguments.length>2)
		this.name=arguments[2];

	//post request to get page list
	this.getPageList = function(){
		if(this.pageBuilt){
			return;
		}
		options = {
			async : false,
			timeout : 2000,
			data : {"data[chapter_id]":this.id,"data[name]":this.name},
			type : "POST",
			url : "/mangas/chapterPages",
			success : this.buildPageList,
			error : this.getPageListError,
			dataType : "json"
		};
		$.ajax(options);
	};

	//build page list from server response
	this.buildPageList = function(data,textStatus){
		that = chapterList[data['name']];
		data = data['data'];
		prevpage = null;
		datlen = data.length
		if(that.prev!=null && that.prev.pageBuilt)
			prevpage = that.prev.lastpage;
		for(i=0;i<datlen;i++){
			that.pageArray[i] = new Page(that.name,prevpage,data[i].id,data[i].number,data[i].imagepath);
			if(prevpage!=null)
				prevpage.next = that.pageArray[i];
			pageList[data[i].id] = that.pageArray[i];
			that.pageList[data[i].number] = that.pageArray[i];
			prevpage = that.pageArray[i];
		}
		that.firstpage = that.pageArray[0];
		that.lastpage = that.pageArray[that.pageArray.length-1];
		if(that.next && that.next.pageBuilt){
			that.lastpage.next = that.next.firstpage;
			that.next.firstpage.prev = that.lastpage;
		}
		that.pageBuilt = true;
	};

	//TODO: handle page list server error
	this.getPageListError = function(XMLHttpRequest, textStatus, errorThrown){
		//debug(textStatus);
		//debug(errorThrown.toString(),true);
		showFAIL();
	};

	//build page select
	this.fillPageSelect = function(chap){
		pageSelects = ['#PageNumberTop','#PageNumberBottom'];
		for(i=0;i<pageSelects.length;i++){
			if(currChapter!=chap){
				$(pageSelects[i]).empty();
				for(j=0;j<this.pageArray.length;j++){
					$(pageSelects[i]).append(this.pageArray[j].option);
				}
			}
			changeSelected(pageSelects[i],currPage);
		}
	};
}

//Page object
//Constructor args: chapter,prev,id,chnum,imgpath
function Page(){
	this.next = null;
	this.prev = null;
	this.chnum = 0;//the page's number in the chapter
	this.id = 0;//page id in db
	this.chapter = null;//chapter name
	this.imgpath = null;//image uri
	this.loaded = false;//whether image is loaded in dom
	this.option = "";//text for option dom element
	this.img = "";//image object
	this.imgid = "";//image dom element's id
	this.hash = "";//this page's uri hash component

	arglen = arguments.length;
	if(arglen>0)
		this.chapter = arguments[0];
	if(arglen>1)
		this.prev = arguments[1];
	if(arglen>2)
		this.id = arguments[2];
	if(arglen>3)
		this.chnum = arguments[3];
	if(arglen>4)
		this.imgpath = arguments[4];
	
	this.hash = ""+this.chapter+"/"+this.chnum;
	this.imgid = this.id + 'img';
	this.option = '<option value="#'+this.hash+'">'+this.chnum+'</option>';
	//initialize but don't load image
	this.initImage = function(){
		this.img = new Image();
		this.img.id = this.id+'img';
		this.loaded = false;
	};

	//destroy image
	this.unloadImage = function(){
		$("#"+this.imgid).remove();
		this.initImage();
	};

	//returns a callback function that also changes our loaded status: closures rock
	this.housekeeping = function(cb){
		pageId = this.id;
		return function(){
			pageList[pageId].loaded = true;
			if($.isFunction(cb))
				cb();
		};
	};
			

	//load image
	this.loadImage = function(callback){
		if(this.loaded){
			callback();
			return;
		}
		callback = this.housekeeping(callback);
		$(this.img).load(callback);
		$(this.img).attr("src",this.imgpath);
	}

	this.initImage();

	//get next Page
	this.getNext = function(){
		if(this.next!=null)
			return this.next;
		if(chapterList[this.chapter].next==null)
			return null;
		chapterList[this.chapter].next.getPageList();
		return this.next;
	};
	//get prev Page
	this.getPrev = function(){
		if(this.prev!=null)
			return this.prev;
		if(chapterList[this.chapter].prev==null)
			return null;
		chapterList[this.chapter].prev.getPageList();
		return this.prev;
	};
}
//end object prototypes
//debug function
function debug(){
	var dbg="";
	var append=false;
	if(arguments.length>0)
		dbg = arguments[0];
	if(arguments.length>1)
		append = arguments[1];
	prefix = append?$("#debug").html():"";

	$("#debug").html("<pre>" + prefix + dbg + "</pre>");
}

