/*
================================================================================
 .............     ......                                                       
    ....   .....     ....                                                       
    ....    ....     ....                                                       
    ....     ....    ....                                                       
    ....     ....    ....                                                       
    ....     ....    ....                                                       
    ....    ....     ....      ......        ......... .....  .....     ...  .  
    ....   ....      ....    ..   ....     .... ....    ....   ....    ..  ...  
    ..........       ....   ...    ....   ....   ....   ....   ....   ...   ..  
    ....   .....     ....   ....   ....   ....   ....   ....   ....   ....   .  
    ....     ....    ....    ..    ....   ....   ....   ....   ....   ......    
    ....     .....   ....        ......   ....   ....   ....   ....    ......   
    ....     .....   ....      ..  ....   ....   ...    ....   ....      .....  
    ....     .....   ....    ...   ....    .... ...     ....   ....       ..... 
    ....     .....   ....   ....   ....     ......      ....   ....   .    .... 
    ....    .....    ....   ....  .....    .            ....  .....   ..    ... 
    ....   .....     ....   ...... .....  ..            ...........   ...   ..  
 .............     ........  ....   ...   ..........     ..... .....  .  ....   
                                          ............                          
                                            ...........                         
                                           ..        ..                         
                                           ..        ..                         
                                           ...      ..                          
                                             .......                            
================================================================================
W e b         S y s t e m s         A r c h i t e c t          P o r t f o l i o
================================================================================
*/
// Aplication settings
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
var settings = {};
	// preferences
	settings.prefs = {};
	settings.prefs.enableScroller = true;
	settings.prefs.pauseScrollerOnShowCase = true;
	settings.prefs.refreshRate   = 33; // 33=30fps, 83=12fps
	settings.prefs.phaseDisplace =  2; // in pixels
	settings.prefs.retrieveHashInterval = 250;
	/* Above: the interval of the function that will retrieve the location hash 
	                                       (for AJAX history/bookmarking) in mS */
	// Site files
	settings.uris = {}; 
		settings.uris.data         = "contents.xml" + "?" + (Math.floor(Math.random() * 0xFFFFFF).toString(16));
		settings.uris.scroller     = "scroller.html";
		settings.uris.iconsPath    = "works/icons-200px/";
		settings.uris.workImgsPath = "works/screenshots/";
	
	// UI HTML id's
	settings.ids = {}; 
		settings.ids.canvasScroller   = "trailScroller";
		settings.ids.tagLoading       = "tagLoading";
		settings.ids.showCase         = "showCase1";
		settings.ids.showCaseImage    = "imgShowCase";
		settings.ids.info             = "info1";
		settings.ids.infoContents     = "info3";
		settings.ids.labelLoading     = "labelTagLoading";

		settings.ids.linkShowCasePrevious = "linkShowCasePrevious";
		settings.ids.linkShowCaseNext     = "linkShowCaseNext";
		settings.ids.linkShowCaseClose    = "linkShowCaseClose";
		settings.ids.linkShowCaseInfo     = "linkShowCaseInfo";
		settings.ids.linkInfoBackward     = "linkInfoPrevious";
		settings.ids.linkInfoForward      = "linkInfoNext";
		settings.ids.linkInfoClose        = "linkInfoClose";

	// texts used in UI
	settings.texts = {}; 
		// loading tag
		settings.texts.siteContents                  = "loading site contents...";
		settings.texts.preparing = function(a){ return "preparing " + a + "..."; };
		settings.texts.creating  = function(a){ return "creating "  + a + "..."; };
		settings.texts.rendering = function(a){ return "rendering " + a + "..."; };
		settings.texts.attachingImage                = "Loading image...";
		// alert boxes error
		settings.texts.articleNotFound               = "Error: this showcase was not found !";
		settings.texts.articlePageNotFound           = "Error: this showcase page was not found !";
		settings.texts.articleImageNotFound          = "Error: this showcase image was not found !";
	
	// HTML code to be dinamically generated
	settings.code = {}; 
		settings.code.icon = function(intIconWidth, strLinkHRef, strImgSrc, strAltText) {
			var output = "";
			output += "<div";
			output += " class=\"scrollerShadow\"";
			output += " style=\"width:" + intIconWidth + "px;\"";
			output += ">";
			output += "<div";
			output += " class=\"scrollerItem\">";
			output += "<a";
			output += " href=\"" + strLinkHRef + "\"";
			output += ">";
			output += "<img";
			output += " src=\"" + settings.uris.iconsPath + strImgSrc + "\"";
			output += " alt=\"" + strAltText + "\"";
			output += " title=\"" + strAltText + "\"";
			output += " width=\"200\"";
			output += " height=\"200\"";
			output += " />";
			output += "</a>";
			output += "</div>";
			output += "</div>";
			return output;
		};

// trace highlight color
var mC = "#309"; // mc stands for main color

// Global variables
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
var jklXMLsiteContents = false;
var objSiteContents    = false;
var worksScroller      = false;
var indexLoading       = 0;
var lastAnchor         = "";
var undoLastAnchor     = "";
var docTitle           = "";
var togglerButtonInfo  = undefined;

// =============================================================================
var tagLoading = function(seed, txt){
	// Show or hide the "loading" flyout
	trace("tagLoading(" + getInfo(arguments) + ")", mC);
	
	if (seed == 0){ indexLoading = 0;	} else { indexLoading += seed; }
	trace("indexLoading: " + indexLoading);
	
	// change text
	if ( indexLoading > 0 && seed > 0 ) {
		$(settings.ids.labelLoading).innerHTML = txt ? txt : "loading...";
	}
	// show or hide
	if ( indexLoading == 1 ) {
		$(settings.ids.tagLoading).style.display = "";
	} else if ( indexLoading < 1 ) {
		$(settings.ids.tagLoading).style.display = "none";
	}

	return settings.ids.tagLoading;
};

// —————————————————————————————————————————————————————————————————————————————
var checkHashChanges = function(){
	// check for changes in the location hash (#)
	// trace("checkHashChanges(" + getInfo(arguments) + ")", mC);
	
	var currentAnchor = location.hash.replace(/^#/, "");
	// trace("currentAnchor: " + currentAnchor);
	
	if ( currentAnchor != lastAnchor ) {
		trace("A change has occurred");
		lastAnchor = currentAnchor;
		// call action
		link(currentAnchor);
	} else {
		// trace("No changes");
	}
};

// —————————————————————————————————————————————————————————————————————————————
var link = function(label){
	// control all the links in the page
	trace("link(" + getInfo(arguments) + ")", mC);
	
	var arrActions = label.split("/");
	trace("arrActions: [" + arrActions.join(", ") + "]");
	if ( arrActions.length > 0 ){
		if ( arrActions[0] != "" ){
			// open showcase
			showCase(arrActions);
		} else {
			// close showcase
			showCase(0);
		}
	}
	
	// exit function
	return undefined;
};

// =============================================================================
var renderIcons = function(){
	// render icons on the screen based in the XML and activate scroller
	trace("renderIcons(" + getInfo(arguments) + ")", mC);
	tagLoading(1, settings.texts.rendering("icons"));

	if ( objSiteContents ){
		trace("objSiteContents.portfolio.icons.icon.length: " + objSiteContents.portfolio.icons.icon.length);
		// loop through icons in XML file
		var icons = objSiteContents.portfolio.icons.icon;

		// final HTML code
		var htmlIcons = "";
		for (li=0; li<icons.length; li++ ){ // li stands for "loop icons"
				htmlIcons += settings.code.icon(
					211,
					"#" + parseInt(icons[li].id),
					icons[li].src,
					icons[li].name
				);
		}
		// trace("htmlIcons: <pre><code>" + htmlIcons.replace(/</gim, "< ").replace(/>/gim, " >") + "</code></pre>");
		
		// insert code
		document.getElementById(settings.ids.canvasScroller).innerHTML = htmlIcons;
		
		// create scroller
		if (settings.prefs.enableScroller) {
			tagLoading(1, settings.texts.creating("scroller")); // creating scroller
			worksScroller = new Scroller(
				document.getElementById(settings.ids.canvasScroller),
				settings.prefs.refreshRate,
				settings.prefs.phaseDisplace
			);
			tagLoading(-1); // creating scroller
		}

	} else {
		trace("Error: objSiteContents not ready");
	}

	// exit function
	tagLoading(-1); // rendering icons
};

// —————————————————————————————————————————————————————————————————————————————
var showCase = function(arrParameters){
	// exhibit showcase
	trace("showCase(" + getInfo(arguments) + ")", mC);
	
	if ( arrParameters != false ) {
		/* open show case */

		// get article name
		var thisArticleId   = arrParameters[0];
		var thisArticleName = articles.getNameById(thisArticleId);

		if (thisArticleName){
			tagLoading(1, settings.texts.preparing(thisArticleName)); // start exhibit showcase
			
			// stop scroller
			if (settings.prefs.pauseScrollerOnShowCase) { worksScroller.pause(true); }
			
			// change window title 
			document.title = docTitle + ": " + articles.getNameById(thisArticleId);
			
			// article navigation buttons
			if ( articles.qtt() == 1){
				$(settings.ids.linkShowCasePrevious).firstChild.style.display = "none";
				$(settings.ids.linkShowCaseNext).firstChild.style.display = "none";
			} else {
				// retrieve previous article
				if( articles.getIndexById(thisArticleId) == 0 ){
					var previousArticle = articles.getIdByIndex(articles.qtt()-1);
				} else {
					var previousArticle = articles.getIdByIndex(articles.getIndexById(thisArticleId)-1);
				}
				// retrieve next article
				if( articles.getIndexById(thisArticleId) == (articles.qtt()-1) ){
					var nextArticle = articles.getIdByIndex(0);
				} else {
					var nextArticle = articles.getIdByIndex(articles.getIndexById(thisArticleId)+1);
				}
				// set page buttons actions
				$(settings.ids.linkShowCasePrevious).href = "#" + previousArticle;
				$(settings.ids.linkShowCaseNext).href     = "#" + nextArticle
				// display buttons
				$(settings.ids.linkShowCasePrevious).firstChild.style.display = "";
				$(settings.ids.linkShowCaseNext).firstChild.style.display = "";
			}
			
			// get page 
			var thisPage = arrParameters[1] ? parseInt(arrParameters[1]) : 1;
			trace("thisPage: " + thisPage);
			trace("articles.pages.qtt(" + thisArticleId + "): " + articles.pages.qtt(thisArticleId));
			if ( articles.pages.qtt(thisArticleId) >= thisPage ){
				if ( articles.pages.getPageByNumber(thisArticleId, thisPage-1).image ){
					// this page was sucessfully loaded
					undoLastAnchor = arrParameters.join("/");
					trace("undoLastAnchor: " + undoLastAnchor);
					
					// set info button actions (backward page)
					if ( thisPage == 1 || articles.pages.qtt(thisArticleId) == 1 ) {
						$(settings.ids.linkInfoBackward).firstChild.style.display = "none";
					} else if( articles.pages.qtt(thisArticleId) > 1) {
						$(settings.ids.linkInfoBackward).href = "#" + thisArticleId + "/" + (thisPage-1);
						$(settings.ids.linkInfoBackward).firstChild.style.display = "";
					}
					
					// set info button actions (forward page)
					if ( thisPage == articles.pages.qtt(thisArticleId) || articles.pages.qtt(thisArticleId) == 1 ) {
						$(settings.ids.linkInfoForward).firstChild.style.display = "none";
					} else if( articles.pages.qtt(thisArticleId) > 1) {
						$(settings.ids.linkInfoForward).href = "#" + thisArticleId + "/" + (thisPage+1);
						$(settings.ids.linkInfoForward).firstChild.style.display = "";
					}
					
					// attach text
					$(settings.ids.infoContents).innerHTML = articles.pages.getPageByNumber(thisArticleId, thisPage-1)["#text"];

					// attach image
					tagLoading(1, settings.texts.attachingImage); // attaching image
					var imgSrc = 
						settings.uris.workImgsPath + 
						articles.pages.getPageByNumber(thisArticleId, thisPage-1).image;
					trace("imgSrc: " + imgSrc);
					// at this point the callback added at this image will display the canvas
					$(settings.ids.showCaseImage).src = imgSrc;
					$(settings.ids.showCaseImage).alt  = "showcase " + thisArticleName;
					
				} else {
					trace("Error: no image found");
				alert(settings.texts.articleImageNotFound);
				trace("undoLastAnchor: " + undoLastAnchor);
				location.hash = "#" + undoLastAnchor;
				}
				
			} else {
				trace("Error: page does not exist");
				alert(settings.texts.articlePageNotFound);
				trace("undoLastAnchor: " + undoLastAnchor);
				location.hash = "#" + undoLastAnchor;
			}
			
			tagLoading(-1); // start exhibit showcase
		} else {
			trace("Error: article not found !");
			alert(settings.texts.articleNotFound);
			trace("undoLastAnchor: " + undoLastAnchor);
			location.hash = "#" + undoLastAnchor;
		}
	} else {
		/* close show case */
		$(settings.ids.showCase).style.display = "none";
		$(settings.ids.info).style.display = "none";
		location.hash = "#";
		undoLastAnchor = "";
		if (settings.prefs.pauseScrollerOnShowCase) { worksScroller.pause(false); }
	}
};

// —————————————————————————————————————————————————————————————————————————————
var articles = {
	qtt : function(){
		if ( typeof(objSiteContents.portfolio.articles.article.length) == "number" ){
			return objSiteContents.portfolio.articles.article.length
		} else if ( typeof(objSiteContents.portfolio.articles) == "object" ){
			return 1;
		} else {
			return 0;
		}
	},
	
	getIdByIndex : function(articleIndex){
		// get article id by it's index in the contents object
		trace("articles.getIdByIndex(" + getInfo(arguments) + ")", mC);
		if(articles.qtt() == 1 && articleIndex == 0 ){
			return objSiteContents.portfolio.articles.article.id;
		} else if(articles.qtt() > 1) {
			try{
				return objSiteContents.portfolio.articles.article[articleIndex].id;
			} catch(e){
				return false;
			}
		} else {
			return false;
		}
	},

	getArticleById : function(articleId){
		// get article index by it's id in the contents object
		trace("articles.getArticleById(" + getInfo(arguments) + ")", mC);
		if( articles.qtt() == 1 ){
			if( objSiteContents.portfolio.articles.article.id = articleId ){
				return objSiteContents.portfolio.articles.article;
			} else {
				return false;
			}
		} else if( articles.qtt() > 1 ) {
			for( loopArticle=0; loopArticle<articles.qtt(); loopArticle++ ){
				trace("loopArticle: " + loopArticle);
				if( objSiteContents.portfolio.articles.article[loopArticle].id == articleId ){
					return objSiteContents.portfolio.articles.article[loopArticle];
				}
			}
			return false;
		} else {
			return false;
		}
	},

	getIndexById : function(articleId){
		// get article index by it's id in the contents object
		trace("articles.getIndexById(" + getInfo(arguments) + ")", mC);
		if( articles.qtt() == 1 ){
			if( objSiteContents.portfolio.articles.article.id == articleId ){
				return 0;
			} else {
				trace("single article not found");
				return false;
			}
		} else if( articles.qtt() > 1 ) {
			for( loopArticle=0; loopArticle<articles.qtt(); loopArticle++ ){
				trace("loopArticle: " + loopArticle);
				if( objSiteContents.portfolio.articles.article[loopArticle].id == articleId ){
					trace("index: " + loopArticle + ", id: " + articleId);
					return loopArticle;
				}
			}
			trace("not found in articles");
			return false;
		} else {
			trace("no articles");
			return false;
		}
	},

	getNameByIndex : function(articleIndex){
		// get article name by it's index in the contents object
		trace("articles.getNameByIndex(" + getInfo(arguments) + ")", mC);
		if( articles.qtt() == 1 && articleIndex == 0 ){
			try{
				return objSiteContents.portfolio.articles.article.name;
			} catch(e){
				return false;
			}
		} else if( articles.qtt() > 1 ) {
			try{
				return objSiteContents.portfolio.articles.article[articleIndex].name;
			} catch(e){
				return false;
			}
		} else {
			trace("no articles");
			return false;
		}
	},

	getNameById : function(articleId){
		// get article name by it's id in the contents object
		trace("articles.getNameById(" + getInfo(arguments) + ")", mC);
		if (articles.getIndexById(articleId).toString() != "false") {
			return articles.getNameByIndex(articles.getIndexById(articleId));
		} else {
			return false;
		}
	},

	pages : {
		qtt: function(articleId){
			if( typeof(articles.getArticleById(articleId).pages.page.length) == "number" ){
				return articles.getArticleById(articleId).pages.page.length;
			} else if( typeof(articles.getArticleById(articleId).pages.page) == "object" ) {
				return 1;
			} else {
				return 0;
			}
			return articles.getArticleById(articleId).pages.page.length;
		},
		
		getPageByNumber : function(articleId, pageNumber) {
			if( articles.pages.qtt(articleId) > 1 ){
				return articles.getArticleById(articleId).pages.page[pageNumber];
			} else if( articles.pages.qtt(articleId) == 1 ) {
				return articles.getArticleById(articleId).pages.page;
			} else {
				return false;
			}
		}
	}
};

// =============================================================================
var addEvent = function(obj, evType, fn){ 
	// handy event handler
	if (obj.addEventListener){ 
		obj.addEventListener(evType, fn, false); 
		return true; 
	} else if (obj.attachEvent){ 
		var r = obj.attachEvent("on"+evType, fn); 
		return r; 
	} else { 
		return false; 
	} 
};

// —————————————————————————————————————————————————————————————————————————————
var Toggler = function(argFuncCreator, argFuncExpander, argFuncCollapser){
	/*
	// Toggler class definition
	Purpose: Create an toggler object (great for collapsible objects).
	Inputs:  argument name: data type, explanation;
	         argFuncCreator:   function object, the function that creates the new object
	         argFuncExpander:  function object, the function that activate the given object
	         argFuncCollapser: function object, the function that inactivate the given object
	Return:  object Toggler.
	*/
	trace("Class classToggler()", mC);
	
	// Properties
	this.objTarget = undefined;
	this.created   = false;
	this.expanded  = undefined;
	this.id = (Math.floor(Math.random() * 0xFFFFFF).toString(16)).toUpperCase();
	this.funcCreator   = argFuncCreator;
	this.funcExpander  = argFuncExpander;
	this.funcCollapser = argFuncCollapser;

	// Methods
	this.create = function(){
		trace("Toggler.create()", mC);
		if (!this.created) {
			this.funcCreator();
			this.created = true;
		} else {
			trace("Error: object has already been created");
		}
	};
	this.expand = function(){
		trace("Toggler.expand()", mC);
		if(this.created){
			this.funcExpander();
			this.expanded  = true;
		} else {
			trace("Error: object has not been created");
		}
	};
	this.collapse = function(){
		trace("Toggler.collapse()", mC);
		if(this.created){
			this.funcCollapser();
			this.expanded  = false;
		} else {
			trace("Error: object has not been created");
		}
	};

	trace("End Class classToggler()", mC);
};

// —————————————————————————————————————————————————————————————————————————————
var toggle = function(currentToggler, visState){
	// Function to toggle an existen object
	/*
	Purpose: Toggle the state of an a given Toggler object.
	Inputs:  argument name: data type, explanation;
	         currentToggler: object, the created Toggler object
	         visState:       boolean, activate or inactivate the given toggler
	Return:  integer,  representing what has been done:
	                   2 for created toggler object and activated;
	                   1 for activated toggler object;
	                  -1 for inactivated toggler object.
	*/
	// trace("Function toggle();", "black");
	trace("Function toggle(" + getInfo(arguments) + ")", mC);
	var returnValue = undefined;
	if (!currentToggler.created){
		currentToggler.create()
		returnValue=2;
	}
	visState = visState==undefined ? !currentToggler.expanded : visState;
	if (visState > 0){
		currentToggler.expand();
		returnValue = returnValue==2 ? 2 : 1;
	} else {
		currentToggler.collapse();
		returnValue = -1;
	}
	trace("returnValue: " + returnValue);
	return returnValue;
};

// —————————————————————————————————————————————————————————————————————————————
var $ = function(e) {
	return document.getElementById(e);
};

// —————————————————————————————————————————————————————————————————————————————
var myFunction = function(){
	// function description goes here...
	trace("myFunction(" + getInfo(arguments) + ")", mC);
	
	// ...
	
	// exit function
	return undefined;
};

// =============================================================================
addEvent(
	window,
	"load",
	function(){
		tagLoading(1); // window load
		
		// get original window title
		docTitle = document.title;

		// request and parses the site contents XML into an object
		tagLoading(1, settings.texts.siteContents); // retrieve XML
    jklXMLsiteContents = new JKL.ParseXML(settings.uris.data); // hr stands for "http request"
    objSiteContents = jklXMLsiteContents.parse();
		tagLoading(-1); // retrieve XML

		// render icons
		renderIcons();

		// retrieve hash changes, including a link from bookmark
		intervCheckHashChanges = setInterval("checkHashChanges()", settings.prefs.retrieveHashInterval);
		trace("<a href=\"javascript:void(clearInterval(intervCheckHashChanges));\">clear intervCheckHashChanges interval</a> (failsafe)");
		trace("<a href=\"void(intervCheckHashChanges = setInterval(\"checkHashChanges()\", settings.prefs.retrieveHashInterval));\">re-enable intervCheckHashChanges interval</a>");
					
		// showcase image loaded callback
		addEvent(
			$(settings.ids.showCaseImage),
			"load",
			function(){
				trace("$(settings.ids.showCaseImage).onload", mC);
				// display flyout
				$(settings.ids.showCase).style.display = "";
				if (togglerButtonInfo.expanded) {
					toggle(togglerButtonInfo, 1);
				}
				tagLoading(-1); // attaching image
			}
		);

		// showcase info toggler
		togglerButtonInfo = new Toggler(
			function(){
				// hide info
				$(settings.ids.linkShowCaseInfo).firstChild.style.display = "none";
				// set links
				$(settings.ids.linkShowCaseInfo).href = "javascript:void(toggle(togglerButtonInfo,  1));";
				$(settings.ids.linkInfoClose).href    = "javascript:void(toggle(togglerButtonInfo, -1));";
				// set default to show info box
				togglerButtonInfo.expanded = true;
			}, 
			function(){
				$(settings.ids.linkShowCaseInfo).firstChild.style.display = "none";
				$(settings.ids.info).style.display = "";
			},
			function(){
				$(settings.ids.linkShowCaseInfo).firstChild.style.display = "";
				$(settings.ids.info ).style.display = "none";
			}
		);
		togglerButtonInfo.create();

		tagLoading(-1); // window load
	}
);

// =============================================================================
