/**
 * JS for CFD Design Page
 * author:  Grace Pok
 * version 1.0
 */

//CFD namespace -- if it's been defined in global script, don't do it again.
var CFD = {};

/* 
 * Project Image -- Constructor
 *   id (str) -- ID of the thumbnail's <A> element (generates the click event)
 *   thumb (str) -- thumbnail file
 *   big (str) -- big image file
 *   
 */
CFD.Pimg = function(id, big, description, link){
	this.id = id;
	this.big = big;
	this.thumb = big;
	this.desc = description;	//text
	this.hlink = link;			//hyperlink
};

CFD.Pimg.prototype = {
	//returns the big image file name
	_img : function() {
		return this.big;
	},
	
	//returns the HTML A element
	_anchor : function() {
		return $(this.id);
	},
	
	// thumbnail click event hander
	//	imgselobj -- PimgSelect object that contains this image
	//	swapText (bool) pass in true if text (title/desc) should also be swapped
	click: function(imgselobj, swapText) {
		
		//do nothing if same image is clicked
		if (imgselobj.lastimg == this) {
			return;
		}
		
		var last_anch;
		var last_img;
		var cur_anch;
		var cur_img;
		
		//last clicked A and IMG elements... only act on it if it's defined
		if (imgselobj.lastimg) {

		last_anch = $(imgselobj.lastimg._anchor());
			last_img = $(imgselobj.lastimg.getThumbImg());

			//restore the last thumbnail class
			if (last_anch.hasClassName('cur')) {
				last_anch.removeClassName('cur');
				last_img.removeClassName('cur');
			}

		}
		
		//currently clicked A and IMG elements
		cur_anch = $(this._anchor());
		cur_img = $(this.getThumbImg());
		if (!cur_anch.hasClassName('cur')) {
			cur_anch.addClassName('cur');
			cur_img.addClassName('cur');
		}

		//set the last-clicked image to current one, and load the big picture
		imgselobj.lastimg = this;
		imgselobj.loadImage(this.big);
		
		if (swapText) {
			imgselobj.loadText(this.title, this.desc);
		}
		return this.big;
	},
	
	//return the thumbnail's IMG HTML element
	getThumbImg: function() {
		var children = this._anchor().childElements();
		if (children.length == 1 && (children[0].tagName == "IMG")) {
			return children[0];
		}
		else
		{
			//return the first IMG element that's inside the A tag
			//this will return undefined if no IMG tag is found
			return children.find( function(el) { 
				if (el.tagName == "IMG")
					return true;
				return false;
			});
		}
	},
	//setup each thumbnail for click event
	//  imgselobj -- PimgSelect object that contains this image
	setClickEvent: function(imgselobj) {
		$(this.id).observe("click", this.click.bind(this, imgselobj, false));
	},
	
	//same as setClickEvent, but clicking on thumbnail will also swap out the text
	setClickEventwText: function(imgselobj) {
		$(this.id).observe("click", this.click.bind(this, imgselobj, true));
	},
	
	//Sets the title & description for this image.
	//For archive projects.
	setTitleDesc: function(title,desc) {
		this.title = title;
		this.desc = desc;
	}
	
};
/*--------------------------------------------------------------
END of Pimg class */


/* 
 * PimgSelect - Widget that lets you select from an array of Project Images
 * Removed BLIND effect b/c of problem with height set to 0
 * config members:
 * 		imgID - big image ID 
 * 		images - array of Pimg objects
 * 		l_desc - long description HTML element ID
 * 		s_desc - short description HTML element ID
 * 		a_link - link A tag ID
 */
CFD.PimgSelect = function(config){
	this.imgID = config.imgID;
	this.images = config.images;
	
	this.l_desc = config.l_desc;
	this.s_desc = config.s_desc;
	this.a_link = config.a_link;
	
	this.lastimg;    //Pimg object that was clicked last
	
	this.titleID = null;  //for archive only - title text container
	this.descID = null;	  //for archive only - desc text container
};

CFD.PimgSelect.prototype = {
	//hooks up the event handler
	load: function() {
		//convert string ID to object
		this.l_desc = $(this.l_desc);
		this.s_desc = $(this.s_desc);
		this.a_link = $(this.a_link);
		
		for (var ii=0; ii < this.images.length; ii++) {
			this.images[ii].setClickEvent(this);
			$(this.images[ii].id).observe("click", this.handleClick.bind(this, ii));
		}
		this.l_desc.observe("click", this.handleTextHide.bind(this));
		//$(this.l_desc).setOpacity(0.9);
		//by default the first image
		this.handleClick(0);
	},
	
	//index - index into the images array
	handleClick: function(clickindex){
		var curimg = this.images[clickindex];
		var cutlen = 60;

		if (!curimg.hlink || curimg.hlink == '') {
			this.a_link.hide();
		}
		else {
			this.a_link.href=curimg.hlink;
			this.a_link.show();
		}
		
		this.l_desc.hide();
		if (curimg.desc){
			if (curimg.desc.length > cutlen){
				this.l_desc.update(curimg.desc);
				this.s_desc.update(truncate_string(curimg.desc, cutlen));
				this.s_desc.addClassName('clickable');
				this.enableclick_shortdesc(clickindex);
			}
			else {
				this.s_desc.update(curimg.desc);
				this.s_desc.stopObserving('click');
				this.s_desc.removeClassName('clickable');
			}
			this.s_desc.show();
		}
		else {
			this.s_desc.hide();
		}
	},
	enableclick_shortdesc: function(clickindex){
		this.s_desc.observe("click", this.handleTextClick.bind(this));
	},
	enableclick_longdesc: function(clickindex){
		this.l_desc.observe("click", this.handleTextHide.bind(this));
		
	},
	handleTextClick : function (){
		this.l_desc.show();
		//Effect.BlindDown(this.l_desc, {duration: 0.8} );
	},
	handleTextHide : function (){
		this.l_desc.hide();
		//Effect.BlindUp(this.l_desc, {duration: 0.8});
	},
	
	
	//returns the HTML IMG element
	_img: function() {
		return $(this.imgID);
	
	},
	//define the area where the text goes
	//only for archive projects
	//  titleID (str) - ID of HTML element where title should be displayed
	//	descID (str) - ID of HTML element where description should be displayed
	setTextArea: function(titleID, descID) {
		this.titleID = titleID;
		this.descID = descID;
	},
	
	//loads the given Image into big IMG's element
	loadImage: function(imagefile) {
		this._img().src = imagefile;
	},
	
	//loads the given Images's title/desc into specified elements
	//only for archive projects
	loadText: function(title, desc) {
		$(this.titleID).update(title);
		$(this.descID).update(desc);
	},
	
	
	
	//hook up event handler
	// when image is clicked, the big image is shown, and title/desc is also loaded
	load_wTitleDesc: function() {

		for (var ii=0; ii < this.images.length; ii++) {
			this.images[ii].setClickEventwText(this);
		}
		
		//by default the first image
		this.images[0].click(this, true);
	}
};
/*---------------------------------------------------------------
END of PimgSelect class  */

/**
//string truncation that does not end in the middle of the word
// modified from: Patrick Fitzgerald | http://www.barelyfitz.com/
 * @param {string} trunc
 * @param {int} len
 */
function truncate_string(trunc, len) {
    if (trunc.length > len) {

      /* Truncate the content of the P, then go back to the end of the
         previous word to ensure that we don't truncate in the middle of
         a word */
      trunc = trunc.substring(0, len);
      trunc = trunc.replace(/w+$/, '');

      /* Add an ellipses to the end and make it a link that expands
         the paragraph back to its original size */
      trunc += '...';
    }
  	return trunc;
}






/*
 * Pmenu -- Project menu widget
 *   Constructor
 *		div (str) -- div where project selections are stored
 *		handle (str)
 *		track (str)
 *		wrap (str)
 *		direction (str:optional) -- 'v' or 'h' default: 'h'
 */
CFD.Pmenu = function(config){
	this.div = config.div;
	this.handle = config.handle;  //scrollbar handle ID
	this.track = config.track;		//scrollbar track ID
	this.wrap = config.wrapper;
	this.direction = config.direction ? config.direction : 'h';
	
	//calculate the initial position of the slider & menu
	this.initPos = (config.curPos/config.totalCount).toFixed(2);  //round to 1 decimal place
	
	this.sliderObj = null;

	//pointer to the actual DIV objects
	this.imgDiv = null;
	this.handleDiv = null;
	this.trackDiv = null;
	this.wrapDiv = null;
};

CFD.Pmenu.prototype = {

	// scroll the element horizontally based on its width and the slider maximum value
	scrollHorizontal: function(value, element, slider) {
		element.scrollLeft = Math.round(value/slider.maximum*(element.scrollWidth-element.offsetWidth));
	},
	
	scrollVertical: function(value, element, slider) {
		element.scrollTop = Math.round(value/slider.maximum*(element.scrollHeight-element.offsetHeight));
	},
	
	load: function() {
		
		
		this.imgDiv = $(this.div);
		this.handleDiv = $(this.handle);
		this.trackDiv = $(this.track);
		this.wrapDiv = $(this.wrap);
		
		/* Slider -------need to init after page is done loading-- */
		/* otherwise the slider will be hidden...  not sure why    */
		var that = this;

		// horizontal slider control
		if (this.direction == 'h'){
				this.sliderObj = new Control.Slider(this.handle, this.track , {
				onSlide: function(v) { that.scrollHorizontal(v, that.imgDiv, that.sliderObj);  },
				onChange: function(v) { that.scrollHorizontal(v, that.imgDiv, that.sliderObj); }
			});
			
			// disable scrolling if text doesn't overflow the div
			if (this.imgDiv.scrollWidth <= this.imgDiv.offsetWidth) {
				this.sliderObj.setDisabled();
				this.wrapDiv.hide();
			}
		}
		//vertical slider control
		else {
			this.sliderObj = new Control.Slider(this.handle, this.track , {
				axis: 'vertical',
				onSlide: function(v) { that.scrollVertical(v, that.imgDiv, that.sliderObj);  },
				onChange: function(v) { that.scrollVertical(v, that.imgDiv, that.sliderObj); }
			});
			
			// disable scrolling if text doesn't overflow the div
			if (this.imgDiv.scrollHeight <= this.imgDiv.offsetHeight) {
				this.sliderObj.setDisabled();
				this.wrapDiv.hide();
			}
		}
		// todo -- find out where my project is and scroll appropriately
		//this.scrollHorizontal(0.5, this.imgDiv, this.sliderObj);
		this.sliderObj.setValue(this.initPos);  //Goes from 0 to 1
	}
};

/*---------------------------------------------------------------
END of Pmenu class  */


/* 
 * Pinfo - Project Info Widget that lets you toggle the long description
 *  btn_toggle (str, or array-of-str) 
 *			- btns that triggers toggle event.  If more than 1, then pass as array of strings
 * 								
 *  descDiv (str) div that holds the long description
 */
CFD.Pinfo = function(btn_toggle, descDiv){
	this.btn = btn_toggle;
	this.descDiv = descDiv;
};

CFD.Pinfo.prototype = {
	
	_ishidden: function() {
		if ($(this.descDiv).hasClassName('hidden'))
			return true;
	},
	//return the main toggle button in case there is more than 1
	_mainbtn: function() {
		if (typeof this.btn == "string") {
			return $(this.btn);
		}
		else {
			return $(this.btn[0])
		}
	},
	//toggle event handler:  makes the long desc visible/invisible
	toggleDesc: function(){
		var div = $(this.descDiv);
		var btn = this._mainbtn();
		
		if (this._ishidden())
			div.removeClassName('hidden');
		else
			div.addClassName('hidden');
			
		if (btn.hasClassName('cur')) {
			btn.removeClassName('cur');
		}
		else {
			btn.addClassName('cur');
		}
	},
	
	//hook up the event handler, set the opacity
	load: function() {
		
		if (typeof this.btn == "string") {
			$(this.btn).observe("click", this.toggleDesc.bind(this));
		}
		else {  //assume array
			for (var ii=0; ii < this.btn.length; ii++) {
				$(this.btn[ii]).observe("click", this.toggleDesc.bind(this));
			}
		}
		$(this.descDiv).setOpacity(0.8);
	}
};

