Projector = function(clientsElm, viewElm){
	
	proj = this;
	
	proj.clientsElm = clientsElm;
	proj.viewElm = viewElm;
	
	this.init = function(){
		proj.pages = {};
		proj.projects = {};
		proj.projectImages = [];
		proj.currentHref = '/projects/';
		proj.isExpanded = false;
		proj.projectImageIndex = 0;
		
		proj.thumbsScrolled = 0; // amount of projects revealled from scrolling
		proj.totalPages = 1; // amount of thumb page fragments
		proj.totalThumbs = 0; // amount of thumbnails
		
		proj.imagesLoaded = 0;
		proj.totalImages = 0;
		proj.isLoading = false;
		
		// element selectors
		proj.wrapperClassName = 'wrapper';
		proj.largeImageSelector = '#project-display';
		proj.nextButtonSelector = '#next-page';
		proj.previousButtonSelector = '#previous-page';
		
		proj.amountScrolled = 0;
		proj.totalThumbnails = 0;
		
		proj.settings = {
			baseURL: '/projects/',
			
			horizontalSpacing: 23,
			thumbsPerPage: 6,
			scrollSpeed: 800,
			
			inactiveThumbOpacity: 0.35
		};
		
		proj.jScrollOptions = { arrowSize:13, scrollbarWidth:15, scrollbarMargin:0, showArrows:true };
		
		proj.build();
	};
	this.build = function(){
		// main banner
		proj.infoElm = proj.viewElm.find('#projector-desc div.section');
		proj.logoGalleryElm = proj.clientsElm.find('ol');
		proj.clientsElm.addClass('dynamic');
		$('#footer').addClass('dynamic');
		
		proj.largeImageElm = proj.viewElm.find(proj.largeImageSelector);

		// wrappers
		proj.thumbWrapElm = $(document.createElement('div')).attr('class', proj.wrapperClassName);
		proj.infoWrapElm = $(document.createElement('div')).attr('class', proj.wrapperClassName).prepend(proj.infoElm.find('*'));

//		proj.infoWrapElm = $('<div class="wrapper"></div>').prepend(proj.infoElm.find('*'));

		// project thumbnail gallery
		proj.projectGalleryElm = $(document.createElement('ol')).attr('id', 'project-gallery');
		proj.projectGalleryElm.appendTo(proj.viewElm);
		proj.projectGalleryElm.hide();
		
		// loading
		proj.loadingElem = $('<p id="project-loading">&nbsp;</p>');
		proj.viewElm.after(proj.loadingElem);
		proj.loadingElem.hide();

		// navigation
		proj.imageNav = $(document.createElement('ul')).attr('class', 'nav');
		proj.expandElm = $('<li id="expand-project"><a href="#" title="View more information on this project">More</a></li>');
		proj.nextImageElm = $('<li id="next-gallery-image"><a href="#" title="View next image in this project gallery">Next</a></li>');
		proj.imageNav.append(proj.nextImageElm);
		proj.imageNav.append(proj.expandElm);
		
		// TODO: Clean-up
		proj.currentPage = 1;
		proj.totalPages = 2;
		
		// proj.preloadPage(proj.currentPage + 1);
				
		// proj.infoElm.css('overflow', 'scroll');
		// proj.infoElm.css('overflow-y', 'scroll');
		// proj.infoElm.css('overflow-x', 'hidden');

		proj.thumbWidth = proj.logoGalleryElm.find('li').width();
		
		proj.prepareProjects(proj.logoGalleryElm);

		// get tallest elements for expanding into
		var contentHeight = $('#content').height();
		var projectHeight = $('#projects').height();
		proj.origHeight = proj.largeImageElm.height();
		proj.expandToHeight = (contentHeight > projectHeight ? contentHeight : projectHeight) + proj.origHeight;
		proj.descPaddingHeight = parseInt(proj.infoElm.css('paddingTop'), 10) + parseInt(proj.infoElm.css('paddingBottom'), 10);
			
		// click events	
		proj.expandElm.click(proj.toggleExpansion);
		proj.nextImageElm.click(proj.nextBanner);

		// put everything together
		proj.infoWrapElm.prependTo(proj.infoElm);
		proj.imageNav.appendTo(proj.largeImageElm);
		proj.logoGalleryElm.prependTo(proj.thumbWrapElm);
		proj.thumbWrapElm.prependTo(proj.clientsElm);

		// arrange project gallery ready for sliding
		proj.listWidth = proj.logoGalleryElm.width();
		var wrapperOffsetLeft = proj.listWidth * (proj.currentPage - 1);
		var projectViewLeft = (proj.currentPage > 1 ? wrapperOffsetLeft : 0);
		proj.thumbWrapElm.css('left', -projectViewLeft);
		proj.leftOffset = 0;
		if (proj.currentPage > 1) {
			proj.leftOffset = ((proj.currentPage - 1) * proj.listWidth);
			proj.preloadPage(proj.currentPage - 1);
		}
		// set initial offset
		proj.logoGalleryElm.css('marginLeft', (proj.currentPage - 1) * proj.listWidth);

		// load selected project
		proj.loadProjectByHref(proj.clientsElm.find('.selected').attr('href'), true);
		proj.pages[proj.currentPage] = proj.logoGalleryElm;
		
		// fade out non-active items
		proj.clientsElm.find('a').not('.selected').find('img').css({ opacity: proj.settings.inactiveThumbOpacity });
		proj.totalThumbnails = proj.thumbWrapElm.find('li').length - 1;
		
		// prepare for sliding arrows
		proj.imageNavLeft = parseInt(proj.imageNav.css('left'), 10);
		proj.imageNavWidth = 18;
		
		// thumbnail scrolling navigation
		proj.navigationElm = $('<ul class="nav"><li id="previous-page" class="disabled"><a href="#" title="View previous projects">Previous</a></li><li id="next-page" class="disabled"><a href="#"  title="View next projects">Next</a></li></ul>');
		proj.galleryNextElm = proj.navigationElm.find(proj.nextButtonSelector);
		proj.galleryPrevElm = proj.navigationElm.find(proj.previousButtonSelector);
		proj.galleryNextElm.click(this.next);
		proj.galleryPrevElm.click(this.previous);
		// hide if there are not enough thumbnails
		if (proj.totalThumbnails <= proj.settings['thumbsPerPage']) {
			proj.navigationElm.css('visibility', 'hidden');
		}
		proj.navigationElm.appendTo(proj.clientsElm);
		
		proj.insertPlaceholders();
		proj.updateControls();
		
	};
	this.canScrollNext = function(){
		return proj.totalThumbnails > (proj.amountScrolled + proj.settings['thumbsPerPage']) ;
	};
	this.canScrollPrevious = function(){
		return proj.amountScrolled > 0;
	};
	this.next = function(e){
		e.preventDefault();
		if (proj.canScrollNext()) {
			proj.amountScrolled += proj.settings['thumbsPerPage'];
			proj.leftOffset += (proj.thumbWidth + proj.settings.horizontalSpacing) * proj.settings['thumbsPerPage'];
			proj.thumbWrapElm.animate({ left: -proj.leftOffset }, proj.settings['scrollSpeed']);
			proj.preloadPage(proj.currentPage + 1);
			proj.updateControls();
		}
	};
	this.previous = function(e){
		e.preventDefault();
		if (proj.canScrollPrevious()) {
			proj.amountScrolled -=  proj.settings['thumbsPerPage'];
			proj.leftOffset -= (proj.thumbWidth + proj.settings.horizontalSpacing) * proj.settings['thumbsPerPage'];
			proj.thumbWrapElm.animate({ left: -proj.leftOffset }, proj.settings['scrollSpeed']);
			proj.preloadPage(proj.currentPage - 1);
			proj.updateControls();
		}
	};
	// return true if next thumbnail available
	this.hasNext = function(){
		var nextIndex = proj.thumbsScrolled + proj.settings['thumbsPerPage'];
		return nextIndex < proj.totalThumbs;
	};
	// return true if previous thumbnail available
	this.hasPrevious = function(){
		var previousIndex = proj.thumbsScrolled + proj.settings['thumbsPerPage'] - proj.settings['thumbsPerPage'];
		return previousIndex > 0;
	};
	// refresh thumbnail navigation to reflect available controls
	this.updateControls = function(){
		if (!proj.canScrollPrevious()) {
			proj.galleryPrevElm.addClass('disabled');
		}
		else {
			proj.galleryPrevElm.removeClass('disabled');
		}
		if (!proj.canScrollNext()) {
			proj.galleryNextElm.addClass('disabled');
		}
		else {
			proj.galleryNextElm.removeClass('disabled');
		}
	};	
	this.prepareProjects = function(elm){
		var links = elm.find('a');
		elm.find('a').not('.selected').find('img').animate({ opacity: proj.settings['inactiveThumbOpacity'] }, 700);
		links.click(function(e){
			var elm = $(this);
			var pageElm = elm.parent().parent().parent();
			e.preventDefault();
			
			proj.logoGalleryElm.find('img').css('opacity', proj.settings['inactiveThumbOpacity']);
			pageElm.find('a.selected').removeClass('selected');
			
			elm.addClass('selected');
			elm.find('img').css('opacity', '1.0');
			proj.loadProjectByHref(elm.attr('href'));
		});
		// links.dblclick(proj.toggleExpansion);
		links.find('img').hover(proj.highlightLogo,proj.fadeLogo);
	};
	this.highlightLogo = function(e){
		var elm = $(this);
		elm.css('opacity', '1');
	};
	this.fadeLogo = function(e){
		var elm = $(this);
		if (!elm.parent().is('a.selected')) {
			elm.css('opacity', proj.settings['inactiveThumbOpacity']);			
		}
	};
	this.loadProjectByHref = function(href, skipTransition){
		if (proj.currentHref != href) {
			proj.currentHref = href;
			if (typeof proj.projects[proj.currentHref] != 'undefined') {
				proj.setProject(proj.projects[proj.currentHref], skipTransition);
			}
			else {
				$.getJSON(proj.currentHref + '?type=ajax', function(json){
					proj.projects[proj.currentHref] = json;
					proj.projects[proj.currentHref].imgCache = [];
					proj.setProject(proj.projects[proj.currentHref], skipTransition);
				});
			}
		}
	};
	this.setProject = function(project, skipTransition){
		proj.totalImages = project.images.length;
		proj.imagesLoaded = 0;
		proj.projectImageIndex = 0;
		proj.projectImages = project.images;
		
		var sectionWrapped = $('<div class="wrapper"></div>').append($(project.description));
		
		proj.projectGalleryElm.empty();
		proj.projectGalleryElm.append($(project.gallery));
		
		var images = proj.projectGalleryElm.find('img');

		for (var i=0; i < proj.projectImages.length; i++) {
			var img = new Image();
			img.onload = proj.imageHasLoaded;
			img.src = proj.projectImages[i];
			project.imgCache[i] = img;
		}
		proj.setBanner(0, skipTransition);
		
		var updatedElm = proj.infoElm.empty().append(sectionWrapped);
		if (updatedElm.innerWidth() < 230) {
			updatedElm.width(245);
		}
		updatedElm.jScrollPane(proj.jScrollOptions);
	};
	// insert placeholders to complete block
	// if there are empty spaces in the row
	this.insertPlaceholders = function(){
		var incompletePages = proj.totalThumbnails / proj.settings['thumbsPerPage'];
		var totalPages = Math.ceil(incompletePages);
		if (incompletePages != totalPages) {
			var totalSpaces = totalPages * proj.settings['thumbsPerPage'];
			var emptySpaces = totalSpaces - proj.totalThumbnails;
			for (var i=0; i < emptySpaces; i++) {
				var placeholderImage = $('<img src="/images/empty.gif" />').animate({ opacity: proj.settings['inactiveThumbOpacity'] });
				var placeholder = $('<li class="empty"></li>').append(placeholderImage);
				proj.logoGalleryElm.append(placeholder);
			};
		}
	};
	this.imageHasLoaded = function(e){
		if (!proj.isLoading) {
			proj.loadingElem.fadeIn();
			proj.isLoading = true;
		}
		proj.imagesLoaded++;
		if (proj.imagesLoaded == proj.totalImages) {
			proj.loadingElem.fadeOut();
			proj.isLoading = false;
		}
	};
	this.setBanner = function(index, skipTransition){
		var cache = proj.projects[proj.currentHref].imgCache;
		var images = proj.projectGalleryElm.find('img');
		var selection = proj.projectGalleryElm.find('#project-image-' + index);
		
		if (typeof cache[index] != 'undefined') {
			var css = 'url(' + cache[index].src + ')';
			if (!skipTransition) {
				proj.imageNav.animate({ left: proj.imageNavLeft + proj.imageNavWidth }, 250);
				proj.largeImageElm.fadeOut(300, function(){
					proj.largeImageElm.css('background-image', css);
					proj.largeImageElm.fadeIn(300);
				});
				proj.imageNav.animate({ left: proj.imageNavLeft }, 250);		
			}
			else {
				proj.largeImageElm.css('background-image', css);
			}
			images.removeClass('selected');
			// images.css('opacity', 0.4);
			selection.addClass('selected');
			selection.css('opacity', 1.0);
		}
	};
	this.nextBanner = function(e){
		e.preventDefault();
		if (proj.projectImages.length > 0) {
			proj.projectImageIndex++;
			if (proj.projectImageIndex >= proj.projectImages.length) {
				proj.projectImageIndex = 0;
			}
			proj.setBanner(proj.projectImageIndex);
		}
	};
	this.preloadPage = function(no){
		if (no <= proj.totalPages && no > 0 && typeof proj.pages[no] == 'undefined') {
			$.get(proj.settings['baseURL'] + '?type=ajax&page=' + no, function(r){
				if ($.trim(r) != '') {
					proj.insertPage($(r), no);
				}
			});
		}
	};
	this.insertPage = function(html, insertAt){
		return;
		var insertMarginLeftOffset = proj.listWidth * (insertAt - 1);
		html.css('marginLeft', insertMarginLeftOffset);		
		proj.prepareProjects(html);
		html.prependTo(proj.thumbWrapElm);
		proj.pages[insertAt] = html;
		if (insertAt > proj.totalPages) {
			proj.totalPages = insertAt;
		}
		proj.updateControls();
	};
	this.toggleExpansion = function(e){
		e.preventDefault();
		var heightTo = 0;
		if (!proj.isExpanded) {
			
			var section = $('.section');
			var scrollContainer = $('div.jScrollPaneContainer');
			
			proj.isExpanded = true;
			proj.viewElm.addClass('expanded');
			proj.viewElm.css('height', 900);	
			proj.projectGalleryElm.show();
			proj.projectGalleryElm.css('opacity', 0.0);
			var offset = ($.browser.msie ? 6 : 4);
			heightTo = parseInt(proj.projectGalleryElm.height(), 10) + parseInt(scrollContainer.height(), 10) - offset;
			
			$('#projector').height(heightTo);
			$('#content').hide();
			$('#search').hide();
			
			// remember previous size
			proj.infoPanelWidth = scrollContainer.width();
			proj.infoPanelHeight = scrollContainer.height();
			// reset scroll
			section.css('top', 0);
			// remove scrollbars
			section.appendTo('#projector-desc');
			scrollContainer.remove();
			section.css('width', 230);
			section.animate({ height: heightTo });
			
			var wrapper = $('.section');
			wrapper.appendTo('#projector-desc');
						
			proj.projectGalleryElm.animate({ opacity: 1.0 });
			proj.infoElm.find('section').animate({ height: heightTo }, 800);
			proj.expandElm.addClass('selected');
		}
		else {
			var newHeight = proj.origHeight - proj.descPaddingHeight;			
			proj.isExpanded = false;
			proj.projectGalleryElm.fadeOut('slow');
			proj.infoElm.animate({'height': 270}, 500, function(){
				proj.viewElm.removeClass('expanded');
				$('#search').fadeIn('fast');
				$('#content').fadeIn();
				proj.expandElm.removeClass('selected');
				proj.viewElm.css('height', proj.infoPanelHeight);
				proj.viewElm.css('width', proj.infoPanelWidth);
				proj.viewElm.removeClass('expanded');
				$('.section').jScrollPane(proj.jScrollOptions);
			});
		}
	};
	this.init();
};

$(document).ready(function(){
	new Projector($('#projects'), $('#projector'));
});