//I can't assign this to object prototype or jquery gets mad
function superior(name) {
	var that=this, method=that[name];
	return function() {
		return method.apply(that, arguments);
	};
};
String.prototype.capitalize = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
};


var SDL = {
	events: $({})
};

//PLUGINS
SDL.availableplugins = {
	simpledownload: function(that, my) {
		var parentInitialize = that.superior("initialize");
		that.initialize = function() {
			parentInitialize();
			if(1||that.item.downloadable) {
				$.tmpl( SDL.getTemplate('popup.download'), {files:[]}).appendTo( "#sdlviewer #sdlviewer_rightextras");
				$("#sdlviewer #sdlviewer_rightextras div.downloads a").click(function() {
					SDL.events.triggerHandler('item.download',[$(this).attr("id").replace("related_",""), that.item.id]);
				});
			} 
		};
	},
	relateditems: function(that, my) {
		var parentInitialize = that.superior("initialize");
		that.initialize = function() {
			parentInitialize();
			that.item.relatedItems(function(results) {
				$.tmpl( SDL.getTemplate('popup.related'),{items: results.docs.slice(0,5)}).appendTo( "#sdlviewer #sdlviewer_rightextras");
				$("#sdlviewer #sdlviewer_rightextras div.related a").click(function() {
					SDL.events.triggerHandler('item.related',[$(this).attr("id").replace("related_",""), that.item.id]);
				});
			});
		};
	},
	useagerights: function(that,my) {
		var parentInitialize = that.superior("initialize");
		that.initialize = function() {
			parentInitialize();
			if(item.usageRights) {
				$.tmpl( SDL.getTemplate('popup.usagerights'), {}).appendTo( "#sdlviewer #sdlviewer_rightextras");
			} 
		};
	}
		
};





SDL.plugins ={
	viewer: {
		defaults: [
//		       SDL.availableplugins.simpledownload,
		       SDL.availableplugins.relateditems
		],
		base: [
		]
	},
	search: [],
	asset: {
		base: []
	},
	route: []
};
SDL.server = "http://"+window.location.hostname+"/api/";
SDL.accessKey = "";
SDL.asset = {};
SDL.viewer = {};
SDL.viewers = {};
SDL.viewers.close = function() {
	if(SDL.currentViewer) SDL.currentViewer.close();
	SDL.currentViewer = null;
	$("#sdlviewer_overlay").hide();
	$("#sdlviewer").hide();
};
SDL.viewers.resize = function () {
	$("#sdlviewer_container").css("top",parseInt($(document).scrollTop()) + 30);
	$("#sdlviewer_container").css("width",Math.max(950, parseInt($(document).width())) - 90);
	$("#sdlviewer_container #sdlviewer_main").css("width",parseInt($("#sdlviewer_container").width() - 359));
	$("#sdlviewer_container, #sdlviewer_container #sdlviewer_main").css("height",parseInt($(window).height()) - 60);
	$("#sdlviewer_container #sdlviewer_rightextras, #sdlviewer_container #sdlviewer_leftnav").css("height",parseInt($(window).height()) - 60 - 42/*padding*/);
	$("#sdlviewer").css("height",Math.max(parseInt($(window).height()), parseInt($(document).height())));
	if(SDL.currentViewer) {
		SDL.currentViewer.resize();
	}
};
SDL.viewers.open = function(parts) {
	var attributes = parts.slice(3);
	if(SDL.currentViewer && SDL.currentViewer.item && SDL.currentViewer.item.id == parts[1]) {
		SDL.currentViewer.openPage(parts[2],attributes);
	} else {
		var item = SDL.asset.base(parts[1]);	
		item.getViewer(function(viewer) {
			viewer.open(parts[2],attributes);
		});
	}
};

SDL.templates = {
	'popup.fielddisplay': '<div class="scrollholder"><div class="metadata"><h1>${title}</h1>{{if author.length > 0}}<h3><span>by </span>${author}</h3>{{/if}}'+
		'{{if description.length>0}}<h4><label>DESCRIPTION</label>${description}</h4>{{/if}}'+
		'<table></table>'+
		'</div></div>',
	'popup.mainnav': '<div class="sdlviewer_mainnav">'+
		'{{each links}}{{if $value.visible !== false}}<a id="sdlviewer_link_${$value.name}" href="#item/${itemid}/${$value.name}"><span class="icon icon_${$value.name}">${$value.name.capitalize()}</span>${$value.name.capitalize()}</a>{{/if}}{{/each}}'+
		'</div>',
//	'popup.searchform': '<form id="sdlviewer_form" action="#item/${itemid}/search/">'+
//		'<input type="search" class="search" placeholder="search this book" /><input type="submit" class="btn btn-go" />' +
//		'</form>',
	'popup.searchform': ' ',
	'popup.subnav': '<div class="sdlviewer_subnav">'+
		'<h2>Table of Contents</h2>'+
		'{{each links}}<a href="#" data-page="${$value.data}" style="margin-left: ${($value.level -1) * 20}px" '+ 
		'class="{{if $value.level > 1}}sublevel{{/if}} {{if $index == 0}}selected{{/if}}">${$value.title}</a>{{/each}}'+
		'</div>',
	'popup.usagerights': '<div class="usage">' +
		'<h2>Usage Rights</h2>'+
		'<p>${usage}</p>'+
		'</div>',
	'popup.download': '<div class="downloads">'+
		'<h2>Download</h2>{{each files}}'+
		'<a href="${url}">${name}<span>${filesize}</span></a>'+
		'{{/each}}</div>',
	'popup.downloadfiles': '{{each files}}'+
		'<a href="${url}">${name}<span>${filesize}</span></a>'+
		'{{/each}}',
	'popup.related': '<div class="related">'+
		'<h2>Related Links</h2>'+
		'{{each items}}<a href="#item/${$value.id}/view" id="related_${$value.id}"><img src="${$value.asset.thumb.url}"/>${$value.fields.title}</a>{{/each}}'+
		'</div>',
	imagezoom: '<div class="seadragonimage"><div class="controls">'+
		'<a href="#" class="control zoomout icon icon_zoomout" title="Zoom out (you can also use your mouse\'s scroll wheel)">Zoom Out</a>'+
		'<a href="#" class="control zoomin icon icon_zoomin" title="Zoom in (you can also use your mouse\'s scroll wheel">Zoom In</a>'+
		'<a href="#" class="control fullscreen icon icon_fullscreen" title="Full Screen">Full Screen</a>'+
		'<a href="#" class="control home icon icon_home" title="Home View">Home View</a>'+
		'</div></div>',
	movie: '<div id="videoplayer"><span class="loading">please wait loading</span></div>',
	book: '<div class="bookviewer"><div class="bookviewer_inner"></div></div>'+
		'<div class="controls">'+
		'<a href="#" class="control prev icon icon_prev" title="Previous Page">Previous Page</a>'+
		'<a href="#" class="control zoomout icon icon_zoomout" title="Zoom out">Zoom Out</a>'+
		'<a href="#" class="control zoomin icon icon_zoomin" title="Zoom in">Zoom In</a>'+
		'<a href="#" class="control fullscreen icon icon_fullscreen" title="Toggle Full Screen View">Full Screen View</a>'+
		'<a href="#" class="control home icon icon_home" title="Return to Starting View">Return to Starting View</a>'+
		'<a href="#" class="control next icon icon_next" title="Next Page">Next Page</a>'+
		'</div>',
	'book.preview': '<a class="img_preview" href="#${page}" id="page_${page}">'+
		'<span>${title}<br/>${page} of ${total}</span>' +
		'</a>',
	'book.searchresult': '<a href="#${page}" id="result_${page}">'+
		'<img src=${src} width="${width}" height="${height}" />' +
		'<h1><span class="result">#${result} of ${total} results</span> ${title} <span class="page">page ${page} of ${pages}</span> </h1>' +
		'<p>{{html snippet}}</p>'+
		'</a>',
	'search.item': '<li>'+
		'<div class="notes"><label>Genre</label><p>${fields.genre}</p><label>Collections</label><p>${fields.collections}</p></div>'+
		'<a class="img_wrap ajax" href="/item/${id}/view"><img src="${asset.thumb.url}" /></a>'+
		'<div class="content"><h1><a class="ajax" href="/item/${id}/view">${fields.title}</a></h1><h3>{{if fields.creator}}<span>by </span>${fields.creator}{{else}}&nbsp;{{/if}}</h3>'+
		'<p>${fields.description}</p>' +
		'</div></li>',
	'search.facet': '{{each facets}}{{if $value.name !=""}}'+
		'<input type="checkbox" name="" {{if $value.selected}}checked="checked"{{/if}}> <a href="${$value.href}" {{if $value.selected}}class="selected"{{/if}}> ${$value.name} <span>(${$value.count})</span></a>{{/if}}'+
		'{{/each}}'+
		'{{if total > facets.length}}<a class="seeall" href="#">Show All</a> <span class="more">(${total} more)</span>{{/if}}'
};
SDL.templateCache = {};

SDL.getTemplate = function(name) {
	if(name in SDL.templates) {
		if(!(name in SDL.templateCache)) {
			SDL.templateCache[name] = $.template( null,  SDL.templates[name]);
		}
		return SDL.templates[name];
	} else {
		return false;
	}
};

$("body").bind("sdl-viewer-opened", function(e, viewer) {
	SDL.viewers.resize();
	SDL.currentViewer = viewer;
});
SDL.asset.base = function(id, my) {
	var that = {
		id: id,
		downloadable: false,
		filesize: '200MB',
		shortTitle: 'Untitled',
		usageRights: null
	};
	var itemData=null, fields=null, metadata=null;
	
	my = my || {};
	
	
	that.itemdata = function(callback) {
		if(itemData === null) {
			$.get(SDL.server+SDL.clientId+"/asset/"+id+"/fields", function(data) {
				fields = data.fields;
				
				if(!fields.title) {
					fields.title = "Untitled";
				}
				else if(fields.title.length > 100) {
					that.shortTitle = fields.title.slice(0,72) + "...";
				} else {
					that.shortTitle = fields.title;
				}
				
				try {
					that.filesize = (data.filesize / (1024 * 1024)).toFixed(2) + " MB";
				} catch(e) {
					that.filesize = '?? MB';
				}
				
				itemData = data;
    			callback(itemData);
    		},'jsonp');
    	} else {
    		callback(itemData);
    	}
	};
	
	that.metadata = function(callback) {
		//Temporary hack for older versions
		if(itemData.asset && itemData.asset.image_zoom) {
			callback(itemData.asset);
		}
		else if(metadata === null) {
			$.get(SDL.server+SDL.clientId+"/asset/"+id+"/metadata", function(data) {
				metadata = data;
				
				//legacy code @todo
				if(!metadata.base_url) {
					metadata.base_url = itemData.asset.base_url;
				}
				
				if(metadata.sizes)  {
					var sizes = {};
					for(var size in metadata.sizes) {
						sizes[size] = [];
						for(var dimensions in metadata.sizes[size]) {
							var d = dimensions.split('x'); 
							var dims = {w: d[0], h: d[1]};
							for(var i =0; i < metadata.sizes[size][dimensions].length; i++) {
								sizes[size][metadata.sizes[size][dimensions][i]] = dims;
							}
						}
					}
					metadata.sizes = sizes;
				}
    			callback(metadata);
    		},'jsonp');
    	} else {
    		callback(metadata);
    	}
    };
    
    that.relatedItems = function(callback) {
		$.get(SDL.server+SDL.clientId+"/related/"+id, function(results) {
			callback(results);
		},'jsonp');	
	};
	that.displayFields = function() {
		var title = "";
		if(fields['title']) {
			title = fields['title'];
		}
	
		var author = '';
		ignoreFields = {"description":1,"title":1,"author":1};
		if(!fields['author']) {
			if(fields['creator']) {
				ignoreFields.creator = 1;
				author = fields['creator'];
			}
		} else {
			author = fields['author'];
		}
		
		var description = "";
		if(fields['description']) {
			description = fields['description'];
		}
		
		var otherfields = [];
		for(var name in fields) {
			if(ignoreFields[name] || name.indexOf('_')===0 || $.trim(fields[name])=='') continue;
			otherfields.push({name: name, value: fields[name]});
		}
		
		return {
			title: title,
			author: author,
			description: description,
			fields: otherfields
		};
	};
	that.getViewer = function(callback) {
		that.itemdata(function(itemdata) {
			if(itemdata.type == "image_zoom") {
				itemdata.type = "image";
			}
		
			if(itemdata.type in SDL.viewer) {
				callback(SDL.viewer[itemdata.type](that));
			} else {
				callback(SDL.viewer.base(that));
			}
		});
	};
	
	if(SDL.plugins.asset && SDL.plugins.asset.base) {
		for(var i = 0; i < SDL.plugins.asset.base.length; i++) {
			SDL.plugins.asset.base[i](that, my);
		}
	}
	return that;
};
SDL.viewer.base = function(item,my) {
	var that = {
		item: item,
		events: $({})
	};
	that.superior = superior;
	my = my || {};
	my.links = [
		{name: 'about', func: 'showData'}
	];
	that.pageDefault = 'about';
	
	function hasView(view) {
		for(var i = 0; i < my.links.length; i++) {
			if(my.links[i].name == view) {
				return my.links[i].func;
				break;
			}
		}
		return false;
	};
	that.hasView = hasView;
	
	that.initialize = function() {
		$("#sdlviewer_leftnav").append($("<h2>").append(item.shortTitle));
		$.tmpl( SDL.getTemplate('popup.mainnav'), {itemid: that.item.id, links: my.links}).appendTo( "#sdlviewer #sdlviewer_leftnav");
	},
	that.open = function(startview,attributes) {
		$("#sdlviewer_overlay").height(parseInt($(document).height())).show();
		$("html").css({
			overflowX: "hidden",
			overflowY: "hidden",
			paddingRight: '15px'
		});
		$(".sdlviewer_mainnav a").each(function() {
			var view = $(this).attr("id").replace("sdlviewer_link_","");
			if(hasView(view)) {
				$(this).attr("href", "#item/" + item.id +"/" + view);
				$(this).show();	
			} else {
				$(this).hide();
			}
		});
		$("#sdlviewer_rightextras").empty();
		$("#sdlviewer_leftnav").empty();
		that.clearMain();
		
		that.initialize();
		
		
		//Setup correctly, now we can start showing it
		$("#sdlviewer").show();
		$("body").triggerHandler('sdl-viewer-opened', [that]);
		if(hasView(startview)) {
			this.openPage(startview,attributes);
		} else {
			this.openPage(that.pageDefault,attributes);
		}
	};
	that.openPage = function(page,attributes) {
		attributes = attributes || {};
		var viewFunction = hasView(page);
		if(!viewFunction) {
			viewFunction = hasView(that.pageDefault);
		}
		$(".sdlviewer_mainnav a").removeClass('current');
		$(".sdlviewer_mainnav a#sdlviewer_link_"+page).addClass("current");
		that.clearMain();
		that[viewFunction](attributes);
	};
	that.showData = function() {
		var tableBody = $("<tbody />");
		fields = item.displayFields();
		$.tmpl( SDL.getTemplate('popup.fielddisplay'), fields).appendTo( "#sdlviewer #sdlviewer_main");
		
		var columnCount = 0;
		var tr = $('<tr class="first"/>');
		var maxFieldLength = 50;
		for(var i=0; i < fields.fields.length; i++) {
			var td = $("<td />").append($("<label />").append(fields.fields[i].name)).append(fields.fields[i].value);
			tr.append(td);
			if(columnCount == 1 || fields.fields[i].value.length > maxFieldLength || (fields.fields[i+1] && fields.fields[i+1].value.length > maxFieldLength)) {
				if(columnCount == 0) {
					td.attr("colspan",2);
				}
				tableBody.append(tr);
				tr = $("<tr />");
				columnCount = 0;
			} else {
				td.addClass("left");
				columnCount = 1;
			}
		}
		tableBody.append(tr);
		
		tableBody.find("tr:odd").addClass("alt");
		$("#sdlviewer #sdlviewer_main div.metadata table").append(tableBody);
		that.resize();
	};
	
	that.clearMain = function() {
		$("#sdlviewer_main").unbind();
		$("#sdlviewer #sdlviewer_main").empty();
	};
	
	that.close = function() {
		that.clearMain();
		that.item = null;
		$("html").css({
			overflowX: "hidden",
			overflowY: "scroll",
			paddingRight: '0px'
		});
	};
	
	that.resize = function() {
		var viewerdiv = $("#sdlviewer #sdlviewer_main .scrollholder");
		viewerdiv.height(parseInt(viewerdiv.parent().height()));
	};
	
	if(SDL.plugins.viewer && SDL.plugins.viewer[my.type] && SDL.plugins.viewer[my.type].length > 0) {
		for(var i = 0; i < SDL.plugins.viewer[my.type].length; i++) {
			SDL.plugins.viewer[my.type][i](that, my);
		}
	} else if(SDL.plugins.viewer && SDL.plugins.viewer.defaults) {
		for(var i = 0; i < SDL.plugins.viewer.defaults.length; i++) {
			SDL.plugins.viewer.defaults[i](that, my);
		}
	}
	return that;
};
SDL.viewer.data = function(item, my) {
	var my = my || {};
	my.type = my.type || 'data';
	var that = SDL.viewer.base(item,my), viewer=null;
	for(var i=0; i < my.links.length; i++) {
		if(my.links[i].name == 'about') {
			my.links[i].name = 'view';
		}
	}
	return that;
};
SDL.viewer.image = function(item, my) {
	var my = my || {};
	my.type = my.type || 'image';
	
	var that = SDL.viewer.base(item,my), viewer=null;
	my.links = [
		{name: 'view', func: 'showItem'}
	].concat(my.links);
	that.pageDefault = 'view';
	
	var parentClearMain = that.superior("clearMain");
	that.clearMain = function() {
		if(viewer) {
			viewer.close();
			viewer = null;
		}
		parentClearMain();
	};

	var parentresize = that.superior("resize");
	that.resize = function() {
		parentresize();
		
		var imagediv = $("#sdlviewer #sdlviewer_main .seadragonimage");
		imagediv.height(parseInt(imagediv.parent().height()));
	};
	
	that.showItem = function() {
		$("#sdlviewer #sdlviewer_main").append(SDL.templates.imagezoom);
		item.metadata(function(metadata) {
			var imagediv = $("#sdlviewer #sdlviewer_main .seadragonimage");
			that.resize();
			viewer = new Seadragon.Viewer(imagediv);
			$("#sdlviewer #sdlviewer_main").find('div.controls').click(function(e) {
				e.stopPropagation();
				e.preventDefault();
				var target = $(e.target);
				if(target.is(".zoomin")) {
					viewer.zoomIn(e);
				} else if(target.is(".zoomout")) {
					viewer.zoomOut(e);
				} else if(target.is(".home")) {
					viewer.goHome();
				} else if(target.is(".fullscreen")) {
					viewer.expandFullPage();
				} 
			});
			viewer.open(new Seadragon.DziTileSource(metadata.image_zoom.width,metadata.image_zoom.height, metadata.image_zoom.tilesize, metadata.image_zoom.overlap,metadata.image_zoom.url, 'png', []));
		});
	};
	return that;
};
SDL.viewer.movie = function(item, my) {
	var my = my || {};
	my.type = my.type || 'movie';
	var that = SDL.viewer.base(item,my);
	my.links = [
		{name: 'view', func: 'showItem'}
	].concat(my.links);
	that.pageDefault = 'view';
	
	var parentClearMain = that.superior("clearMain");
	that.clearMain = function() {
		if($("object#videoplayer").length >=1) {
			jwplayer("videoplayer").remove();
		}
		parentClearMain();
	};
	var parentresize = that.superior("resize");
	that.resize = function() {
		parentresize();
		var height = Math.min(500, parseInt($(window).height()) - 60);
		var margin = Math.floor((parseInt($("#sdlviewer_container").height()) - height) / 2);
		if(margin >= 0) {
			$("#sdlviewer_main #videoplayer").css("margin-top",margin);
		}
	};
	
	that.showItem = function() {
		$("#sdlviewer #sdlviewer_main").append(SDL.templates.movie);
		var height = Math.min(500, parseInt($(window).height()) - 60);
		var width = Math.min(890, parseInt($("#sdlviewer_container").width()) - 353);
		
		item.itemdata(function(itemData) {
			jwplayer("videoplayer").setup({
				flashplayer: "/static/1/flash/jwplayer.swf",
				file: "/",
				height: height,
				width: width,
				provider: "http",
				streamer: itemData.asset.movie_url_flv,
				"http.startparam":"start",
				allowfullscreen: true,
				allowscriptaccess: "always",
				autostart:true,
				stretching:"uniform",
				events: {
					onReady: function() {
						//This is important to remove after the fact so that it forces the browser to redraw
						//and doesn't show a blank screen
						loading.remove();
					}
				}
			});
			that.resize();
		});
	};
	return that;
};
SDL.viewer.book = function(item, my) {
	var my = my || {};
	my.type = my.type || 'book';
	var that = SDL.viewer.base(item,my);
		my.links = [
		{name: 'view', func: 'showItem'},
		{name: 'preview', func: 'showPreview'},
		{name: 'search', func: 'showSearch','visible':false}
	].concat(my.links);
	that.pageDefault = 'view';
	that.selectednav = $([]);
	
	var parentClearMain = that.superior("clearMain");
	that.clearMain = function() {
		$("#sdlviewer #sdlviewer_main").empty();
		$("#sdlviewer_leftnav .sdlviewer_subnav").unbind();
		parentClearMain();
	};
	
	var parentInitialize = that.superior("initialize");
	that.initialize = function() {
		parentInitialize();
		
		
		$.tmpl( SDL.getTemplate('popup.searchform'), {itemid: that.item.id}).appendTo( "#sdlviewer_leftnav");
		
		$("#sdlviewer_form").submit(function(e) {
			e.preventDefault();
			window.location = $(this).attr("action") + $(this).find("input").val();
		});
		item.metadata(function(metadata) {
			$.tmpl( SDL.getTemplate('popup.subnav'), {links: metadata.navigation}).appendTo( "#sdlviewer_leftnav");
			that.resize();
			that.events.triggerHandler("navchanged", [$("#sdlviewer_leftnav .sdlviewer_subnav a:first")] );
		});
		$("#sdlviewer_leftnav .sdlviewer_subnav").live('click',function(e) {
			e.stopPropagation();
			e.preventDefault();
			var target = $(e.target);
			if(target.is("a")) {
				window.location = "#/item/" + that.item.id +"/view/" +parseInt($(target).attr("data-page"));
			}
		});
	};
	
	var parentClose = that.superior("close");
	that.close = function() {
		$("#sdlviewer_leftnav .sdlviewer_subnav").die();//remove all live event listeners
		parentClose();
	};
	
	var previewWidth;
	var parentresize = that.superior("resize");
	that.resize = function() {
		parentresize();
		if($("#sdlviewer_leftnav .sdlviewer_subnav").length) {
			$("#sdlviewer_leftnav .sdlviewer_subnav").height($("#sdlviewer_leftnav").outerHeight() - 21 - $("#sdlviewer_leftnav .sdlviewer_subnav").position().top);
		}
		if( $('#sdlviewer_main .imagepreviewer').length) {
			previewWidth = $('#sdlviewer_main .imagepreviewer').width();
		}
		var viewerdiv = $("#sdlviewer #sdlviewer_main .bookviewer");
		viewerdiv.height(parseInt(viewerdiv.parent().height()));
	};
	
	that.showItem = function(attributes) {
		jumpToPageNumber = attributes[0];
		item.metadata(function(metadata) {
			$("#sdlviewer #sdlviewer_main").append(SDL.templates.book);
			
			var viewerdiv = $("#sdlviewer #sdlviewer_main .bookviewer");
			var viewerinnerdiv = viewerdiv.find(".bookviewer_inner");
			viewerdiv.height(parseInt(viewerdiv.parent().height()));
			
			var pageOffsets = [];
			
			var pageSpacing = 30;
			var totalHeight = 0;
			var pageOffsets = [];
			var maxWidth = 0;
			var halfAveragePageHeight = 0;
			
			var imagesUrl = metadata.base_url + "/m/";
			var pages = metadata.sizes.m ;
			
			var baseHeight = Math.min(viewerdiv.height(), pages[0].h);
			var baseRatio = ( baseHeight / pages[0].h);
			var baseRatio = 1;
			
			
			var ratio = 1;
			
			var findCurrent = function() {
				var scrollTop = viewerdiv.scrollTop();
				var closestPage = 1;
				for(var i=0; i < pageOffsets.length; i++) {
					if(pageOffsets[i] <= scrollTop) {
						closestPage = i+1;
					} else {
						break;
					}
				}
				return closestPage;
			};
			
			var refreshPages = function() {
				var currentPages = {};
				viewerinnerdiv.find("img").each(function() {
					currentPages[$(this).attr("id").replace("page_","")] = 1;
				});
				
				var currentPage = findCurrent() - 1;
				
				var currentNavs = $("#sdlviewer_leftnav .sdlviewer_subnav a.selected");
				var firstPageNav = $(currentNavs.get(0)).attr("data-page");
				//Figure out which nav page we are on
				var navPage = 0;
				for(var i = 0; i < metadata.navigation.length; i++) {
					if(metadata.navigation[i].data > (currentPage+1)) break;
					navPage = metadata.navigation[i].data;
				}
				
				if(navPage != firstPageNav) {
					currentNavs.find("span").remove().end().removeClass("selected");
					var navSelectedElements = $("#sdlviewer_leftnav .sdlviewer_subnav a[data-page="+navPage+"]");
					
					if(navSelectedElements.length > 0) {
						var top  = $("#sdlviewer_leftnav .sdlviewer_subnav a[data-page="+navPage+"]").addClass("selected").first().prepend('<span class="icon icon_nav_arrow" />').position().top +
							$("#sdlviewer_leftnav .sdlviewer_subnav").scrollTop();
						
						$("#sdlviewer_leftnav .sdlviewer_subnav").scrollTop(Math.max(top - 75, 0));
					}
					that.selectednav = $(navSelectedElements.get(0));
					that.events.triggerHandler("navchanged", [that.selectednav]);
				}
				var topPage = Math.min(currentPage+3, pageOffsets.length - 1);
				var bottomPage = Math.max(0, currentPage - 2);
				for(var i = currentPage ; i <= topPage; i++) {
					if(!(i in currentPages)) {
						var img = $('<img id="page_'+i+'" style="position: absolute" />');
					} else {
						img = $("#page_"+i);
					}
					var left = Math.floor((viewerinnerdiv.width() - pages[i].width) / 2);
					if(img.attr("src") != imagesUrl +(i+1)+ ".png") {
						img.attr("src", imagesUrl +(i+1)+ ".png");
					}
					img.css({
						width: pages[i].width,
						height: pages[i].height,
						top: pageOffsets[i],
						left: left
					});
					if(!(i in currentPages)) {
						viewerinnerdiv.append(img);
					}
				}
				//Add these later so that the current page shows up first
				if(bottomPage < currentPage) {
					for(var i = currentPage - 1 ; i >= bottomPage; i--) {
						if(!(i in currentPages)) {
							var img = $('<img id="page_'+i+'" style="position: absolute" src="' + imagesUrl +(i+1)+'.png" />');
						} else {
							img = $("#page_"+i);
						}
						var left = Math.floor((viewerinnerdiv.width() - pages[i].width) / 2);
						img.css({
							width: pages[i].width,
							height: pages[i].height,
							top: pageOffsets[i],
							left: left
						});
						if(!(i in currentPages)) {
							viewerinnerdiv.append(img);
						}
					}
				}
				
				for(var pageNum in currentPages) {
					if(pageNum < bottomPage || pageNum > topPage) {
						$("#page_" + pageNum).remove();
					}
				}
			};
			
			var resize = function(newRatio) {
				var ratioChange = 0;
				if(newRatio && newRatio != ratio) {
					ratioChange = ( baseRatio * newRatio)/ (baseRatio * ratio);
					ratio = newRatio;
				}
				var oldTotalHeight = totalHeight;
				totalHeight = 0;
				
				//Check which version of the images should we be using
				var newRatio = baseRatio * ratio;
				pageSpacing = Math.floor(30 * newRatio);
				if(metadata.sizes.l.length > 0 && pages[0].h * newRatio > 1000) {
					imagesUrl = metadata.base_url + "/l/";
				} else if(metadata.sizes.s.length > 0 && pages[0].h * newRatio < 400 ) {
					imagesUrl = metadata.base_url + "/s/";
				} else if(pages[0].h * newRatio < 100 ) {
					imagesUrl = metadata.base_url + "/t/";
				} else {
					imagesUrl = metadata.base_url + "/m/";
				}
				
				
				pageOffsets = [];
				maxWidth = 0;
				for(var i = 0; i < pages.length; i++) {
					pageOffsets[i] = totalHeight;
					pages[i].height = Math.floor(pages[i].h * newRatio);
					pages[i].width = Math.floor(pages[i].w * newRatio);
					maxWidth = Math.max(maxWidth, parseInt(pages[i].width));
					totalHeight += pages[i].height + pageSpacing;
					
				}
				viewerinnerdiv.width("auto");
				viewerinnerdiv.height(totalHeight).width(Math.max(maxWidth,parseInt(viewerinnerdiv.width())));
				viewerdiv.scrollLeft(Math.max(0, (maxWidth - viewerdiv.width()) / 2));
				halfAveragePageHeight = totalHeight / pageOffsets.length /2;
				
				if(oldTotalHeight != totalHeight) {
					viewerdiv.scrollTop( Math.floor(viewerdiv.scrollTop() * ( totalHeight / oldTotalHeight)));
				}
			};
			
			var jumpToPage = function(page) {
				viewerdiv.scrollTop(pageOffsets[page-1]);
			};
			
			$("#sdlviewer #sdlviewer_main").find('div.controls').click(function(e) {
				e.stopPropagation();
				e.preventDefault();
				var target = $(e.target);
				if(target.is(".zoomin")) {
					resize(ratio+.25);
					refreshPages();
				} else if(target.is(".zoomout")) {
					resize(ratio-.25);
					refreshPages();
				} else if(target.is(".home")) {
					resize(1);
					jumpToPage(1);
					refreshPages();
				} else if(target.is(".fullscreen")) {
					if(viewerdiv.is(".bookviewerfullscreen")) {
						viewerdiv.removeClass("bookviewerfullscreen");
						viewerdiv.parent().append($(this));
						resize();
						refreshPages();
					} else {
						viewerdiv.append($(this));
						viewerdiv.addClass("bookviewerfullscreen");
						resize();
						refreshPages();
					}
				} else if(target.is(".prev")) {
					jumpToPage(Math.max(findCurrent() - 1, 1));
				} else if(target.is(".next")) {
					jumpToPage(Math.min(findCurrent() + 1, pages.length));
				}
			});
			
			resize();
			
			var lastUpdateHeight = -1000;
			var lastDate = new Date();
			var timeoutDelay = null;
			viewerdiv.scroll(function() {
				var scrollTop = $(this).scrollTop();
				if(Math.abs(scrollTop - lastUpdateHeight) > halfAveragePageHeight) {
					lastUpdateHeight = scrollTop;
					//then I want to schedule an update to occur
					if(timeoutDelay) {
						clearTimeout(timeoutDelay);
					}
					timeoutDelay = setTimeout(function() {
						lastDate = new Date();
						refreshPages();
						$(this).dequeue();
					}, 100);
				}
			});
			
			if(jumpToPageNumber) {
				jumpToPage(jumpToPageNumber);
			}
			viewerdiv.trigger("scroll");
			
			$("#sdlviewer_leftnav .sdlviewer_subnav").click(function(e) {
				e.stopPropagation();
				e.preventDefault();
				var target = $(e.target);
				if(target.is("a")) {
					jumpToPage(parseInt($(target).attr("data-page")));
				}
			});
		});
	};
	
	that.showPreview = function() {
		item.metadata(function(metadata) {
			var pages = metadata.sizes.t;
			var maindiv = $("#sdlviewer #sdlviewer_main");
			var scrollview = $('<div class="scrollholder"/>');
			maindiv.append(scrollview);
			var bookviewer = $('<div class="imagepreviewer" />');
			bookviewer.click(function(e) {
				e.stopPropagation();
				e.preventDefault();
				
				var target = $(e.target).closest('a');
				if(target.is("a")) {
					window.location = "#/item/" + that.item.id +"/view/" +parseInt($(target).attr("href").replace("#",""));
				}
			});
			var baseUrl =  metadata.base_url + "/t/";
			for(var i = 0; i < Math.min(40, pages.length); i++) {
				var data = {
					page: i+1,
					title: $("#sdlviewer_leftnav .sdlviewer_subnav a[data-page="+(i+1)+"]:last").text(),
					total: pages.length
				};
				$.tmpl( SDL.getTemplate('book.preview'), data).appendTo(bookviewer);
			};
			scrollview.append(bookviewer);
			that.resize();
			
			var thumbWidth = bookviewer.find("a:first").outerWidth(true);
			var thumbHeight = bookviewer.find("a:first").outerHeight(true);
			var perLine = Math.floor(previewWidth / thumbWidth);
			
			bookviewer.width((thumbWidth * perLine));
			
			//calculate total height
			bookviewer.height(thumbHeight * Math.ceil((pages.length / perLine)));
			function loadImages(top) {
				var showFirst = Math.floor(top / thumbHeight) * perLine;
				var showLast = Math.min(pages.length, showFirst + 20);
				for(var i = bookviewer.children().length; i < Math.min(pages.length, showLast + 40); i++) {
					var data = {
						page: i+1,
						title: $("#sdlviewer_leftnav .sdlviewer_subnav a[data-page="+(i+1)+"]:last").text(),
						total: pages.length
					};
					$.tmpl( SDL.getTemplate('book.preview'), data).appendTo(bookviewer);
				};
				
				var a = bookviewer.find("a:nth-child(" + (showFirst+1)+")");
				for(var i = showFirst; i < showLast; i++) {
					if(!a.find("img").length) {
						var img = $("<img />");
						img.width(pages[i].w);
						img.height(pages[i].h);
						img.attr("src", baseUrl + (i+1) + ".png");
						a.prepend(img);
					} 
					a = a.next();
				}
			}
			loadImages(scrollview.scrollTop());
			
			var timeout = null;
			scrollview.scroll(function(e) {
				var top = scrollview.scrollTop();
				if(timeout) clearTimeout(timeout);
				timeout = setTimeout(function() {
					loadImages(top);
				}, 100);
			});
			
		});
	};
	
	
	that.showSearch = function(attributes) {
		searchString = attributes[0];
		item.metadata(function(metadata) {
			/*
			 * @todo Fetch real search results
			 */
			var results = [
			  {
				  page: 1,
				  snippet: 'This is the snippet with <strong>stuff highlighted</strong> to make it really easy to see what is going on. I searched for' +searchString 
			  },
			  {
				  page: 2,
				  snippet: 'This is the snippet with <strong>stuff highlighted</strong> to make it really easy to see what is going on. I searched for' +searchString 
			  },
			  {
				  page: 3,
				  snippet: 'This is the snippet with <strong>stuff highlighted</strong> to make it really easy to see what is going on. I searched for' +searchString 
			  },
			  {
				  page: 4,
				  snippet: 'This is the snippet with <strong>stuff highlighted</strong> to make it really easy to see what is going on. I searched for' +searchString 
			  },
			  {
				  page: 5,
				  snippet: 'This is the snippet with <strong>stuff highlighted</strong> to make it really easy to see what is going on. I searched for' +searchString 
			  }
			];
			
			
			//@todo This should eventually go into a callback from the search results
			{
				var maindiv = $("#sdlviewer #sdlviewer_main");
				var scrollview = $('<div class="scrollholder"/>');
				maindiv.append(scrollview);
				that.resize();
				
				var h1 = $("<h1>Search results for </h1>").append($("<span/>").text(searchString));
				var searchresults = $('<div class="searchresults">');
				var rowHeight = 159;
				searchresults.append(h1);
				
				scrollview.append(searchresults);
				searchresults.height((rowHeight * results.length) + h1.outerHeight(true));
				
				var pages = metadata.sizes.t;
				var baseUrl =  metadata.base_url + "/t/";
				
				function loadResults(top) {
					var showFirst = Math.floor(top / rowHeight);
					var showLast = Math.min(results.length, showFirst + 10);
					for(var i = searchresults.children().length-1; i < showLast; i++) {
						var data = {
							result: (i+1),
							total: results.length,
							page: results[i].page,
							pages: pages.length,
							
							title: $("#sdlviewer_leftnav .sdlviewer_subnav a[data-page="+(results[i].page)+"]:last").text(),
							snippet: results[i].snippet,
							
							width: pages[i].w,
							height: pages[i].h,
							src:  baseUrl + results[i].page + ".png"
						};
						$.tmpl( SDL.getTemplate('book.searchresult'), data).appendTo(searchresults);
					};
				}
				loadResults(scrollview.scrollTop());
				
				
				
				searchresults.click(function(e) {
					e.stopPropagation();
					e.preventDefault();
					
					var target = $(e.target).closest('a');
					if(target.length == 1) {
						window.location = "#/item/" + that.item.id +"/view/" +parseInt(target.attr("href").replace("#",""));
					}
				});
				
				var timeout = null;
				scrollview.scroll(function(e) {
					var top = scrollview.scrollTop();
					if(timeout) clearTimeout(timeout);
					timeout = setTimeout(function() {
						loadResults(top);
					}, 100);
				});
			}
		});
	};
	return that;
};
SDL.viewer.toolkit = function(item, my) {
	var my = my || {};
	my.type = my.type || 'toolkit';
	var that = SDL.viewer.book(item,my);
	
	that.events.bind("navchanged", function(event, newnav) {
		item.metadata(function(metadata) {
			var files = [];
			var section = $.trim(newnav.text());
			
			if(section in metadata.filespersection) {
				var origFiles = metadata.filespersection[section];
				for(var i = 0; i < origFiles.length; i++) {
					files.push({
						url: "test",
						name: origFiles[i].replace(section+"/", ""),
						filesize: ''
					});
				}
			}
			
			$("#sdlviewer #sdlviewer_rightextras .downloads a").remove();
			$.tmpl( SDL.getTemplate('popup.downloadfiles'), {files:files}).appendTo( "#sdlviewer #sdlviewer_rightextras .downloads");
			$("#sdlviewer #sdlviewer_rightextras div.downloads a").click(function(e) {
				e.preventDefault();
				SDL.events.triggerHandler('item.download',[$(this).attr("id").replace("related_",""), that.item.id]);
			});
		});
	});
	
	return that;
};
SDL.search = function(mainDiv, navDiv, my) {
	var my = my || {};
	var that = {};
	
	my.limit = my.limit || 10;
	my.showResults = function(results) {
		alert("Show results must be defined");
	};
	
	my.search = [];
	
	my.findSearchParam = function(params, name, value) {
		for(var i = 0; i < params.length; i++) {
			if(params[i].name == name && (!value || 
				value == params[i].value ||
				$.inArray(value,  params[i].value) != -1
			)) {
				return i;
			}
		}
		return -1;
	};
	
	that.hasSearchParam = my.hasSearchParam = function(name, value) {
		return  my.findSearchParam(my.search,name, value) != -1;
	};
	
	that.addSearchParam = my.addSearchParam = function(modifications, update) {
		//clone
		var copy = [];
		for(var i = 0; i < my.search.length; i++) {
			//Unless they are setting the page, I want to start over anyway
			if(my.search[i].name == 'page') continue;
			
			if(my.search[i].isarray) {
				copy.push({name: my.search[i].name, value: my.search[i].value.slice(0), isarray: true});
			} else {
				copy.push({name: my.search[i].name, value: my.search[i].value});
			}
		}
		for(i = 0; i < modifications.length; i++) {
			var mod = modifications[i];
			if(mod.name == 'q') {
				var param = my.findSearchParam(copy, mod.name);
				if(param !=-1) copy.splice(param,1);
				copy.push({name: 'q', value: mod.value});
			} else if(mod.name == 'c') {
				var param = my.findSearchParam(copy, mod.name);
				if(param != -1) {
					var index = $.inArray(mod.value, copy[param].value);
					if(index != -1) {
						copy[param].value.splice(index,1);
						if(copy[param].value.length ==0 || copy[param].value.length==1 && copy[param].value[0] == '') {
							copy.splice(param,1);
						}
					} else {
						copy[param].value.push(mod.value);
					}
				} else {
					copy.push({name: 'c', isarray: true, value: [mod.value]});
				}
			} else if(mod.name == 'page') {
				var param = my.findSearchParam(copy, mod.name);
				if(param !=-1) copy.splice(param,1);
				copy.push({name: 'page', value: mod.value});
			} else if(mod.name.indexOf("facet_") === 0) {
				copy.push({name: mod.name, value: mod.value});
			}
		}
		if(update) {
			my.search = copy;
		}
		
		//turn this into a # string
		var uri = "#search/";
		for(var x = 0; x < copy.length; x++) {
			if(copy[x].isarray && copy[x].value.length > 0) {
				uri += copy[x].name +':'+ encodeURIComponent(copy[x].value.join(';'))+"/";
			} else if(!copy[x].isarray && copy[x].value != ''){
				uri += copy[x].name +':'+ encodeURIComponent(copy[x].value)+"/";
			}
		}
		return uri;
	};
	
	that.removeSearchParam = my.removeSearchParam = function(name, value, update) {
		//clone
		var copy = [];
		for(var i = 0; i < my.search.length; i++) {
			//Unless they are setting the page, I want to start over anyway
			if(my.search[i].name == 'page') continue;
			
			if(my.search[i].isarray) {
				copy.push({name: my.search[i].name, value: my.search[i].value.slice(0), isarray: true});
			} else {
				copy.push({name: my.search[i].name, value: my.search[i].value});
			}
		}
		var param = my.findSearchParam(copy, name, value);
		if(param != -1) {
			copy.splice(param,1);
		}
		if(update) {
			my.search = copy;
		}
		
		//turn this into a # string
		var uri = "#search/";
		for(var x = 0; x < copy.length; x++) {
			if(copy[x].isarray && copy[x].value.length > 0) {
				uri += copy[x].name +':'+ encodeURIComponent(copy[x].value.join(';'))+"/";
			} else if(!copy[x].isarray && copy[x].value != ''){
				uri += copy[x].name +':'+ encodeURIComponent(copy[x].value)+"/";
			}
		}
		return uri;
	};
	
	
	
	that.search = function(searchparams) {
		var url = SDL.server +SDL.clientId+ "/search"+"?";
		my.search = [];
		for(var i = 0; i < searchparams.length; i++) {
			if(searchparams[i].name == 'c') {
				my.search.push({name: searchparams[i].name, value: searchparams[i].value.split(/\s*;\s*/), isarray: true});
			} else {
				my.search.push({name: searchparams[i].name, value: searchparams[i].value});
			}
			if(searchparams[i].name == 'c') {
				url += "&collections=" + encodeURIComponent(searchparams[i].value);
			}
			else if(searchparams[i].name == 'q') {
				url += "&query="+encodeURIComponent(searchparams[i].value);
			}
			else {
				url += "&" + searchparams[i].name +"="+encodeURIComponent(searchparams[i].value);
			} 
		}
		url+= "&limit="+my.limit;
		if(my.skipFacets) {
			url += "&skipfacets=1";
		}
		url += "&callback=?";
		
		$.ajax({
			  type: "GET",
			  url: url,
			  dataType: "jsonp",
			  statusCode: {
				  200: function(results) {
					  if(results.err) {
						  if(results.err == 401) {
							  my.showLogin();
						  }
					  } else {
						  my.showResults(results);
					  }
				  }
			  }
		});
	};
	
	if(SDL.plugins.search && SDL.plugins.search) {
		for(var i = 0; i < SDL.plugins.search.length; i++) {
			SDL.plugins.search[i](that, my);
		}
	}
	return that;
};

SDL.application = function(options, my) {
	var my = my || {};
	var that = {}, sinceNonItemView = 0, nonItemView= false;
	my.search = SDL.search();
	that.routeEvent = function(event) {
		SDL.events.triggerHandler('page.route',[event.value]);
		if(event.value == "/"){
			SDL.viewers.close();
			sinceNonItemView = 0;
			if(currentSearch != event.value) {
				my.search.search([]);
			}
			currentSearch = event.value;
			nonItemView= true;
			
		}else if(event.value.indexOf("/search/") === 0) {
			SDL.viewers.close();
			sinceNonItemView = 0;
			if(currentSearch != event.value) {
				var searchParams = [];
				$.each(event.pathNames, function(i,e) {
					var parts = decodeURIComponent(e).split(":", 2);
					if($.trim(parts[0]) == '' || parts[0] == "search") return;
					
					searchParams.push({name: parts[0], value: parts[1]});
				});
				my.search.search(searchParams);
			}
			currentSearch = event.value;
			nonItemView= true;
		}else if(event.value.indexOf("/item")===0) {
			sinceNonItemView++;
			SDL.viewers.open(event.pathNames);
		}
	};
	
	that.start = function() {
		$('a.ajax').live('click', function(e) {
			e.preventDefault();
			//replace the first / with a nothing
			var href=$(this).attr("href");
			if(href.indexOf("http") === 0) {
				href = href.substring(href.indexOf("/", 8));
			}
			$.address.value(href.replace("/",""));
		});
		$(function() {
			$("#sdlviewer a.icon_close").click(function(e) {
				e.preventDefault();
				e.stopPropagation();
				if(!nonItemView) {
					$.address.value("/");
				} else {
					history.go(-1*sinceNonItemView);
				}
			});
			$("div.paging a").click(function() {
				$('html, body').animate({scrollTop:0}, 'fast');
			});
		});
		$("#sdl-search").submit(function(e) {
			e.preventDefault();
			window.location = my.search.addSearchParam([{name: 'q', value: $("#sdl-search input.search").val()}]);
			SDL.events.triggerHandler('search.keywords',[$("#sdl-search input.search").val()]);
		});
		$.address.change(that.routeEvent);
	};
	
	if(SDL.plugins.route && SDL.plugins.route) {
		for(var i = 0; i < SDL.plugins.route.length; i++) {
			SDL.plugins.route[i](that, my,options);
		}
	}
	return that;
};

$(window).bind('resize', function () {
	$(window).clearQueue();
	$(window).delay(200);
	$(window).queue(SDL.viewers.resize);
});

