/*******************************************************************
*
*	Creative + Communications Portfolio
*	
*	Main script that handles the display of the portfolio
*
*	*** PARTS ***
*	There are several parts to this implementation, the portfolio is 
*	the main object that keeps track of the rest. The size is the meta
*	category. The categories are self explanatory. The piece is the main 
*	portfolio exhibit. The slide is each image that is part of the piece.
*	(for example the front and back of a brochure would be the slides,
*	 whie the entire brochure is the piece)
*
*	Pieces, Panels and the Portfolio are objects.	
*	
*	Andrew Karpenko
*	206-221-4564
*	akarpy@u.washington.edu	
*
********************************************************************/

function Portfolio() {
	/* 
	 *	Setup the main variables
	 *	These SHOULD NOT be set directly at runtime, instead, 
	 *	the helper functions defined below should be used.
	 */
	
	//ID
	this.ident				= "portfolio";
	//The id of the div where the portfolio should be constructed
	this.playground			= "portfolio";
	this.container			= "container";
	this.navDivID			= "navigation";
	//the maximum piece height in pixels
	this.maxHeight			= 0;
	
	this.interval			= 0;
	//whether or not to run the portfolio in fullscreen
	this.fullscreen			= 0;
	this.autotransition		= 0;
	this.transitiontimer 	= 0;
	this.count1				= 0;
	//interval for auto switching
	this.present			= 0;
	/*
	 *	size is the array with size names
	 */
	this.sizes 				= [];
	
	/*
	 *	category is a multi dimensional array with first level
	 *	being the size key, and second level being the category name
	 */
	this.categories 		= [];
	
	/*
	 *	Keepts track of the numerical index for our state
	 */
	this.currentState		= {
		size		: 0,
		category	: 0,
		piece		: 0,
		slide		: 0
	}
	this.prevState			= {
		size		: 0,
		category	: 0,
		piece		: 0,
		slide		: 0
	}
	
	/*
	 *	portfolio map - this will be constructed for easy navigation,
	 * 		after the portfolio has been setup. it will be a multidimensional 
	 *		array. With the last node pointing to the piece object
	 */
	this.map				= [];
	this.map[0]				= new Array();
	this.map[0][0]			= new Array();
	 
	/*
	 *	Helper functions
	 */
	 
	/*
	 *	Sets the size of projects we are looking at
	 *	Grabs the content for the desired size and loads it into the page
	 *	Returns -1 if the desired size was not found or could not be loaded
	 *	Returns the passed size if it was successfully saved
	 */
	this.setSizeToIndex = function(to) {
		var p = this;
		if(to<0 || to>=p.sizes.length){
			return -1;
		}
		p.currentState.size = to;
		p.setCategoryToIndex(0);
		
		//the code that actually does this would go here
		
		p.update();
		
		return p.currentState.size;
	}
	// this function is more expensive as it runs in o(n)
	this.setSizeToStr = function(to){
		var p = this;
		var index = p.sizes.indexOf(to);
		return p.setSizeToIndex(index);
	}
	
	/*
	 *	Sets category to the specified index or string for the current size
	 * 	Grabs the content for the specified category and loads it into the page
	 *	Returns -1 if the desired category is out of range or not found
	 *	Returns the category index if successfull
	 */
	this.setCategoryToIndex = function(to) {
		var p = this;
		if(to<0 || to>=p.categories[p.currentState.size].length){
			return -1;
		}
		p.currentState.category = to;
		
		p.leave();
		
		setTimeout('document.location = "index.php?cat='+to+'&size='+p.currentState.size+'&big='+(p.fullscreen ? 1 : 0)+'&auto='+(p.autotransition ? 1 : 0)+'"',1500);
		
		return p.currentState.category;
	}
	// this function is more expensive as it runs in o(n)
	this.setCategoryToStr = function(to){
		var p = this;
		var index = p.categories.indexOf(to);
		return p.setCategoryToIndex(index);
	}
	
	/*
	 *	Sets piece to the specified index or string for the current size
	 *		and category
	 *	Returns -1 if the desired piece is out of range or not found
	 *	Returns the piece index if successfull
	 */
	this.setPieceToIndex = function(to) {
		var p = this;
		if(to<0 || to>=p.map[p.currentState.size][p.currentState.category].length){
			return -1;
		}
		if(p.currentState.slide!=p.prevState.slide || p.currentState.piece!=to){
			p.setSlideToIndex(0);
		}
		p.currentState.piece = to;
		
		$(".nextLink,.prevLink").fadeIn(100);
		
		if(p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slides[p.currentState.slide].img.length==0){
            $("#"+p.container).height(0);
            //$(".nextLink,.prevLink").animate({top: "100px"});
		}else{
            $("#"+p.container).height("480px");
            //$(".nextLink,.prevLink").animate({top: "210px"});
		}
		
		p.update();
		p.destroyEvents();
		p.stopSlide();
		
		var offset = 18;
		if(p.fullscreen){
			var widthWin = $(window).width();
			var offset = (widthWin-835)/2-60;
		}
		
		$("#"+p.container).animate({left: ""+(-1*p.map[p.currentState.size][p.currentState.category][p.currentState.piece].offsetLeft+offset)+"px"},{ duration: 2500});
		
		$("#"+p.container+" > img").attr("class","").fadeTo(1000,0.25);
		$("#"+p.container+" > img:eq("+(p.currentState.piece)+")").attr("class","current").stop(true,false).fadeTo(400,1.0);
		
        //Video Embeds
        $(".videoEmbed").fadeTo(0,0);
        setTimeout('$("#'+p.map[p.currentState.size][p.currentState.category][p.currentState.piece].htmlID+' .videoEmbed").fadeTo(250,1.0);',2500);
        
		return p.currentState.piece;
	}
	/*
	 *	Goes to the prev piece in the set
	 *	If at the first piece, goes to the prev category
	 * 	If at the first category, goes to the prev size
	 *	If at the first size, goes to the last size
	 */
	this.prevPiece = function() {
		var p = this;
		if(p.setSlideToIndex(p.currentState.slide-1)==-1){
			if(p.setPieceToIndex(p.currentState.piece-1)==-1){
				if(p.setCategoryToIndex(p.currentState.category-1)==-1){
					if(p.setSizeToIndex(p.currentState.size-1)==-1){
						p.setSizeToIndex(p.sizes.length-1);
					}
				}
			}
		}
	}
	/*
	 *	Goes to the next piece in the set
	 *	If at the last piece, goes to the next category
	 * 	If at the last category, goes to the next size
	 *	If at the last size, goes to the first size
	 */
	this.nextPiece = function() {
		var p = this;
		if(p.setSlideToIndex(p.currentState.slide+1)==-1){
			if(p.setPieceToIndex(p.currentState.piece+1)==-1){
				if(p.setCategoryToIndex(p.currentState.category+1)==-1){
					if(p.setSizeToIndex(p.currentState.size+1)==-1){
						p.setSizeToIndex(0);
					}
				}
			}
		}
	}
	
	
	/*
	 *	Sets the slide of the shown piece to the specified index
	 *	Returns -1 if the desired slide is out of range or not found
	 *	Returns -2 if there was a problem switching to the image
	 *	Returns -3 if no action was necessary
	 *	Returns the slide index if successfull
	 */
	this.setSlideToIndex = function(to) {
		var p = this;
				
		if(to<0 || to>=p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slides.length){
			return -1;
		}
		
		var imgOrig = p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slides[p.currentState.slide].img;
				
		p.currentState.slide = to;
		p.update();
		
		var img = p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slides[p.currentState.slide].img;
		
		if(img.attr("src")==imgOrig.attr("src")){
			return -3;
		}
		
		if(img.width()!=0){
			var widthDiff = img.width() - imgOrig.width();
			
			var imgContainer = p.map[p.currentState.size][p.currentState.category][p.currentState.piece].img;
			
			//if the new image is bigger than the original
			if(widthDiff>0){
				speed = 0;
			}else{
				speed = 1000;
			}
			
			$("#"+p.container).animate({ width: $("#"+p.container).width()+widthDiff+"px"},speed);
			
			imgContainer.stop(true,false).animate({ width: img.width()+"px"},500).attr("src",img.attr("src"));
			
			return p.currentState.slide;
		}
		
		return -2;
	}
	
	/*
	 * 	Sets the previous state to the current state values
	 */
	this.setPrevState = function(){
		var p = this;
		
		p.prevState.size = p.currentState.size;
		p.prevState.category = p.currentState.category;
		p.prevState.piece = p.currentState.piece;
		p.prevState.slide = p.currentState.slide;
	}
	
	/*
	 *	Update html elements with the current state
	 */
	this.update = function () {
		var p = this;
		p.map[p.prevState.size][p.prevState.category][p.prevState.piece].setActive(false);
		
		if(p.currentState.slide==p.prevState.slide){
			p.map[p.currentState.size][p.currentState.category][p.currentState.piece].setActive(true);
		
		}else{
			p.map[p.currentState.size][p.currentState.category][p.currentState.piece].setCurrentSlide(p.currentState.slide);
		}
		
		var height = $("#"+p.container).height() + p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slide.self.height()+20;
		
		$("#portfolio_pieces_list > a:eq("+p.prevState.piece+")").removeClass("current");
		$("#portfolio_pieces_list > a:eq("+p.currentState.piece+")").addClass("current");
		
		var piece = p.map[p.currentState.size][p.currentState.category][p.currentState.piece];
		$("#"+piece.htmlID+" > .seemore > a:eq("+p.prevState.slide+")").removeClass("current");
		$("#"+piece.htmlID+" > .seemore > a:eq("+p.currentState.slide+")").addClass("current");
		
		//Updates height to accomodate slides
		$("#"+p.playground+"").animate({
			height: height+"px"
		},{ duration: "slow" });
		
		p.setPrevState();
	}
	
	/*
	 *	Use this function when changing pages, if u want to have a transition
	 */
	this.leave = function () {
		var p = this;
		p.map[p.prevState.size][p.prevState.category][p.prevState.piece].setActive(false);
		
		$("#"+p.playground+"").fadeTo("slow",0.0)
		
		if(!p.fullscreen){
			if(p.map[p.prevState.size]!=null && p.map[p.prevState.size][p.prevState.category]!= null && p.map[p.prevState.size][p.prevState.category][p.prevState.piece] != null){
				var height = p.map[p.prevState.size][p.prevState.category][p.prevState.piece].slide.self.height()+([p.currentState.size] == 1 ? 500 : 500);
			}
		}
		
		if(p.fullscreen){
			$("#"+p.playground+"").animate({
				height: "-="+height+"px"
			},{ duration: "slow" });
		
			
			var dist = 80;
			$("#wrap").animate({width: 800+"px"});
			$("#portfolio_sizes_list").add("h1").animate({ paddingLeft: (dist)+"px" });
			$("#portfolio_categories_list").animate({ marginLeft: (dist-5)+"px", marginRight: (dist)+"px" });
			$("#portfolio_pieces_list").animate({ marginLeft: (dist-5)+"px" });
			$(".portfolio_piece").animate({ marginLeft: (dist-3)+"px" });
		}
		
		$("#portfolio_pieces_list").fadeOut("slow",
			function() {
				$("#portfolio_categories_list").fadeOut("slow");
			}
		);
	}
	
	/*
	 *	use this function when entering the page to fade in the controls
	 */
	this.enter = function () {
		var p = this;
		
		$("#"+p.playground+"").fadeTo(1,0);
		$("#"+p.container+"").fadeTo(1,0);
		
		var height = p.map[p.currentState.size][p.currentState.category][p.currentState.piece].slide.self.height()+500;
		
		if(!p.fullscreen){
			$("#"+p.playground+"").css("height",($("#"+p.playground+"").height()+height)+"px");
		}
		
		$("#portfolio_categories_list").fadeIn("slow",
			function() {
				$("#portfolio_pieces_list").fadeIn("slow", 
					function() {
						if(p.fullscreen){
							$("#"+p.playground+"").animate({
								height: "+="+height+"px"
							},{ duration: "slow" });
						}
						$("#"+p.playground+"").fadeTo("slow",1.0);
						$("#"+p.container+"").fadeTo("slow",1.0);
					}
				);
			}
		);
	}
	
	/*
	 *	Creates the helper map from scratch using the current variable values
	 */
	this.createMap = function () {
		var p = this;
		p.map = [];
		for(var s = 0; s < p.sizes.length; s++){
			var categories = [];
			for(var c = 0; c < p.categories[s].length; c++){
				categories[c] = [];
			}
			p.map.push(categories);
		}
	}
	
	/*
	 *	Adds the given piece to the portfolio under the provided size
	 *	and category
	 *	Expects the size and category to be indexes
	 *	Expects the createMap function to have been called already
	 *	Returns -1 if the provided size or category were not found
	 *	Returns -2 if the given object is not a piece
	 */
	this.addPiece = function(piece, size, category) {
		var p = this;
		
		if(piece==null || piece.ident==null || piece.ident!="piece"){
			return -2;
		}
		
		if(size>=p.map.length || category>=p.map[size].length){
			return -1;
		}
		
		p.map[size][category].push(piece);
	}
	
	/*
	 *	Sets up the navigation on the page to use javascript
	 */
	this.setupNavigation = function() {
		var p = this;
		var nav = document.getElementById(p.navDivID);
		
		if(nav==null){
			return -1;
		}
		
		var sizes = document.getElementById("portfolio_sizes_list");
		if(sizes==null){
			var sizes = document.createElement("div");
			sizes.id = "portfolio_sizes_list";
			nav.appendChild(sizes);
		}
		
		var cats = document.getElementById("portfolio_categories_list");
		if(cats==null){
			var cats = document.createElement("div");
			cats.id = "portfolio_categories_list";
			nav.appendChild(cats);
		}
		
		var pieces = document.getElementById("portfolio_pieces_list");
		if(pieces==null){
			var pieces = document.createElement("div");
			pieces.id = "portfolio_pieces_list";
			nav.appendChild(pieces);
		}
		
		// SIZES
		for(var s=0; s<p.sizes.length; s++){
			var a = document.createElement("a");
			a.s = s;
			a.id = "portfolio_sizes_a_"+s;
			a.setAttribute("href","javascript:void(0)");
			if(s==p.currentState.size){
				a.setAttribute("class","current");
			}
			a.onclick = function() { portfolio.setSizeToIndex(this.s); };
			a.innerHTML = p.sizes[s];		   
			sizes.appendChild(a);
		}
		
		// CATEGORIES
		for(var c=0; c<p.categories[p.currentState.size].length; c++){
			var a = document.createElement("a");
			a.c = c;
			a.id = "portfolio_categories_a_"+c;
			a.setAttribute("href","javascript:void(0)");
			if(c==p.currentState.category){
				a.setAttribute("class","current");
			}
			a.onclick = function() { portfolio.setCategoryToIndex(this.c); };
			var ca = p.categories[p.currentState.size][c];
			if(ca.indexOf(".")!=-1){
                ca = ca.substring(ca.indexOf(".")+1);
			}
			a.innerHTML = ca;		   
			cats.appendChild(a);
		}
				
		// PIECES
		for(var x=0; x<p.map[p.currentState.size][p.currentState.category].length; x++){
			var piece = p.map[p.currentState.size][p.currentState.category][x];
			
			var a = document.createElement("a");
			a.x = x;
			a.id = "portfolio_pieces_a_"+(x);
			a.setAttribute("title",$("#"+piece.htmlID+" h2:first").text());
			a.setAttribute("href","javascript:void(0)");
			a.onclick = function() { portfolio.setPieceToIndex(this.x); };
			a.innerHTML = x>=9 ? x+1 : "0"+(x+1) ;		   
			pieces.appendChild(a);
		}
		
		$("#portfolio_pieces_list > a:eq("+p.currentState.piece+")").addClass("current");
		
		//PREV/NEXT links
		$("#"+p.playground).prepend('<a href="javascript:void(0)" class="prevLink" onclick="portfolio.prevPiece()">Prev</a>');
		
		$("#"+p.playground).prepend('<a href="javascript:void(0)" class="nextLink" onclick="portfolio.nextPiece()">Next</a>');
		
		$(".nextLink,.prevLink").fadeOut(0);
		
		//Setup Key presses
		$(document).keyup(function(event) {
			if(event.keyCode == "37") { //Left Arrow
				p.prevPiece();
			}else if(event.keyCode == "39"){ //Right Arrow
				p.nextPiece();
			}
		});
	}
	
	/*
	 *	Scan the current document for pieces and add them to the portfolio
	 *
	 */
	 this.setupPieces = function() {
	 	var p = this;
	 	var playground = document.getElementById(p.playground);
	 	var container = $("#"+p.container+"");
	 	
	 	var pieces = getElementsByClassName("portfolio_piece","",playground);
	 	for (var i=0; i<pieces.length; i++) {
	 		var piece = new Piece(pieces[i].id);
	 		if(pieces[i].id==""){
	 			pieces[i].id = piece.htmlID;
	 		}
	 		
	 		var slides = getElementsByClassName("portfolio_slide","",pieces[i]);
	 		
	 		//setup the See More info div
	 		if(slides.length>1){
	 			$('<div class="seemore"><span class="instructions">see more ></span></div>').prependTo("#"+piece.htmlID);
	 		}
	 		
	 		for (var s=0; s<slides.length; s++){
	 			var slide = new Slide(slides[s].id);
	 			var img = $("#"+p.playground+" > div.portfolio_piece:eq("+i+") > div.portfolio_slide:eq("+s+") > img:first");
	 			
	 			slide.self = $("#"+p.playground+" > div.portfolio_piece:eq("+i+") > div.portfolio_slide:eq("+s+")");
	 			
	 			slide.img = img;
	 			slide.imgWidth = img.width();
	 			
	 			//pull out only the first image
	 			if(s==0){
					var imgNew = $('<img src="" />');
					imgNew.attr("src",img.attr("src"));
					piece.img = imgNew;
					p.setupEvents(imgNew);
					imgNew.appendTo(container);
				}
				
				
				//hide the image
				img.hide();
				
				//if there are more than one piece set it up
				if(slides.length>1){
					$('<a href="javascript:void(0)" onclick="portfolio.setSlideToIndex('+s+')">'+(s+1)+'</a>').appendTo("#"+piece.htmlID+" > .seemore");
				}
				
	 			var height = slide.self.height();
	 			if(p.maxHeight < height){
	 				p.maxHeight = height;	
	 			}
	 			
	 			piece.addSlide(slide);
	 		}
	 		p.addPiece(piece,p.currentState.size,p.currentState.category);
	 	}
	 }
	 
	 /*
	  *		Setup images
	  *		Has to be done after they have all loaded, so we can get the width
	  *	
	  */
	 this.setupImages = function() {
	 	var p = this;
	 	var container = $("#"+p.container);
	 	
	 	//container.css("width",0);
	 	
	 	$("#"+p.container+" > img").each(
	 		function (i) {
	 			p.map[p.currentState.size][p.currentState.category][i].offsetLeft = container.width()-30;
	 			
	 			//why can't i use 'this'
	 			var newWidth = container.width()+30+$("#"+p.container+" > img:eq("+i+")").width();
	 			
	 			container.css("width",newWidth);
			}
		);
	 }
	 
	 /*
	  *		Setup events for the image, like hover and clicks
	  */
	 this.setupEvents = function(img) {
		var p = this;		
		
		//hover over
		img.mouseover(function(){
			portfolio.stopSlide();
			/*$(this).stop(true,false).animate({
				left: "+=3px",
				width: "-=6px",
				top: "+=3px",
				height: "-=6px"
			},{duration: "slow"},{},
				$(this).dropShadow({
					left    : -30,
					top     : 0,
					blur    : 5,
					opacity : 1.0,
					color   : "#E6D794"
				})
			);*/
		});
		
		//hover out
		img.mouseout(function(){
			/*$(this).stop(true,false).css("border","0px solid #666666").animate({borderWidth: "0px"});*/
			/*$(this).removeShadow();
			$(this).stop(true,false).animate({
				left: "-=3px",
				width: "+=6px",
				top: "-=3px",
				height: "+=6px"
			},{duration: "slow"});*/
			portfolio.startSlide();
		});
		
		img.mousedown(function(){
			/*$(this).stop(true,false).css("border","0px solid #666666").animate({borderWidth: "3px"});*/
		});
		
		//click
		img.click(function() {
			portfolio.stopSlide();
			portfolio.setPieceToIndex($("img").index(this));
			/*$(this).stop(true,false).css("border","0px").animate({
				borderWidth: "0px"});*/
			/*$(this).removeShadow();
			$(this).stop(true,false).animate({
				left: "-=3px",
				width: "+=6px",
				top: "-=3px",
				height: "+=6px"
			},{duration: "slow"});*/
		});
	 }
	 
	 /*
	  * 	Destroy any events that may have been setup for the image
	  *		And then setup new events for when the sliding has stopped
	  */
	 this.destroyEvents = function(img) {
	 	var p = this;
	 	$("#"+p.container+" > img").unbind();
	 	$("#"+p.container+" > img:not(:animated)").mouseover(function() {
	 		if($(this).attr("class")!="current"){
	 			$(this).stop(true,false).fadeTo(400,0.5);
	 		}
	 	}).mouseout(function(){
	 		if($(this).attr("class")!="current"){
	 			$(this).stop(true,false).fadeTo(400,0.25);
	 		}
	 	});
	 	$("#"+p.container+" > img").click(function() {
	 		if(p.currentState.piece==$("img").index(this)){
                portfolio.nextPiece();
            }else{
                portfolio.setPieceToIndex($("img").index(this));
            }
	 		if(portfolio.autotransition){
				portfolio.setAutoTransition(false);
				setTimeout("portfolio.setAutoTransition(true);",60*1000);
				//p.countdown(60*1000);
			}
            
	 	});
	 }
	 
	 /*
	  *	Do some sliding
	  */
	 this.startSlide = function() {
	 	var p = this;
	 	
	 	if(p.map[p.currentState.size][p.currentState.category].length==1){
            $("#portfolio_pieces_list").fadeOut("slow");
            p.setPieceToIndex(0);
	 	}
	 	
	 	if(p.autotransition){
	 		p.destroyEvents();
	 		return;
	 	}
	 	
	 	var width 		= $("#"+p.container).width();
	 	var widthPlay 	= $("#"+p.playground).width();
	 	var maxLeft 	= width - widthPlay;
	 	var left 		= $("#"+p.container).position().left;
	 	
	 	var fct 		= ((width-widthPlay-Math.abs(left))/widthPlay);
	 	var spd			= 20000; //how long for one screen width to go by
	 	var dur		 	= spd * fct;
	 	
	 	//alert((width-Math.abs(left)) +"px in "+dur+" microseconds");
	 	
	 	$("#"+p.container).fadeTo(1000,1.0);
	 	
	 	if(left<=0 && left>=maxLeft){
	 		//p.stopSlide();
	 	}else if(width <= widthPlay){
	 		$("#"+p.container).animate({left: "47px"},{ duration: 1000});
	 	}else{
	 		$("#"+p.container).animate({left: "-"+maxLeft+"px"},{ duration: dur, easing: "linear"});
	 	}
	 }
	 this.stopSlide = function() {
	 	var p = this;
	 	$("#"+p.container).stop(true,false);
	 }
	 
	 /*
	  *	Changes the layout to better fit a full screen viewing experience
	  */
	 this.setFullscreen = function(to) {
	 	var p = this;
	 	
	 	p.fullscreen = to;
	 	
	 	if(to){	 	
			var widthWin = $(window).width();
			var dist = (widthWin-976)/2;
			
			$("#close_button").fadeTo({},0.0);
			
			$("#wrap").animate({width: (widthWin-20)+"px"});
			$("#portfolio_sizes_list").add("h1").animate({ paddingLeft: (dist)+"px" });
	 		$("#portfolio_categories_list").animate({ marginLeft: (dist-5)+"px", marginRight: (dist)+"px" });
	 		$("#portfolio_pieces_list").animate({ marginLeft: (dist-5)+"px" });
	 		$(".portfolio_piece").animate({ marginLeft: (dist-3)+"px" });
		}else{
			$("#wrap").animate({width: "976px"});
		}
		
	 }
		
	 /*
	  *	Stops or starts the automatic transitions
	  */
	 this.setAutoTransition = function(to) {
	 	var p = this;
	 	
	 	p.autotransition = to;
		
		if(to){
			p.transitiontimer = setInterval("portfolio.nextPiece()",10000);
		}else{
			clearInterval(p.transitiontimer);
		}
	 	
	 }
}
