/**
 * @class HD.community.Photo
 * @description The purpose of community.Photo is to provide a photo object. 
 * 				Registered as hd_photo.
 * @constructor
 * @extends HD.Widget
 * @see HD.community.Photo.hooks
 * @see HD.community.Photo.templates
 * @see HD.community.Media.hooks
 * @property {object} 	config
 *                    	The configuration for the widget.
 * @property {object} 	[config.hooks=HD.community.Photo.hooks]
 *                 		Customized subset of hooks (merged with the defaults).
 * @property {object} 	[config.templates=HD.community.Photo.templates]
 *                 		Customized subset of templates (merged with the defaults).
 * @property {object}	data
 * 						Media response
 * @property {array)	ratings
 * 						Ratings array                
 */
HD.community.Photo = function(photo) {
	this.data = photo;
	this.ratings = [];
};

/**
 * The collection of default templates.
 * @fieldOf HD.community.Photo
 */
HD.community.Photo.templates = {
	
	/**
	 * Label for the photo author
	 * @memberOf HD.community.Photo
	 */	
	authorLabel       : "Submitted by: ",
	
	/**
	 * Label for the photo date
	 * @memberOf HD.community.Photo
	 */	
	dateLabel         : "",
	
	/**
	 * Label for the photo tags
	 * @memberOf HD.community.Photo
	 */	
	tagsLabel         : "Tags: ",
	
	/**
	 * Label for the photo category
	 * @memberOf HD.community.Photo
	 */	
	categoryLabel     : "Category: ",
	
	/**
	 * Photo more text
	 * @memberOf HD.community.Photo
	 */	
	moreText          : "Read the Story",
	
	/**
	 * Blog first comment text
	 * @memberOf HD.community.Photo
	 */	
	commentsTextFirst : "Comments ({number})",
	
	/**
	 * Photo comments text
	 * @memberOf HD.community.Photo
	 */	
	commentsText      : "Comments ({number})",
	
	/**
	 * Next label for photo
	 * @memberOf HD.community.Photo
	 */	
	nextLabel         : "Next",
	
	/**
	 * Previous label for photo
	 * @memberOf HD.community.Photo
	 */	
	previousLabel     : "Previous",
	
	/**
	 * Photo average votes text
	 * @memberOf HD.community.Photo
	 */	
	averageVotesText  : "(Average of ${num_of_votes}&nbsp;ratings:&nbsp;${text_rating}&nbsp;stars)",
	
	/**
	 * Photo send to a friend text
	 * @memberOf HD.community.Photo
	 */	
	emailText         : "Send to a friend",
	
	/**
	 * @constant
	 * @return {string} Author label for the widget: authorLabel
	 * @memberOf HD.community.Photo
	 */
	getAuthorLabel : function(){
		return this.authorLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Date label for the widget: dateLabel
	 * @memberOf HD.community.Photo
	 */
	getDateLabel : function(){
		return this.dateLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Tags label for the widget: tagsLabel
	 * @memberOf HD.community.Photo
	 */
	getTagsLabel : function(){
		return this.tagsLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Category label for the widget: categoryLabel
	 * @memberOf HD.community.Photo
	 */
	getCategoryLabel : function(){
		return this.categoryLabel;
	},
	
	/**
	 * @constant
	 * @return {string} More text for the widget: moreText
	 * @memberOf HD.community.Photo
	 */
	getMoreText : function(){
		return this.moreText;
	},
	
	/**
	 * @constant
	 * @return {string} Comments text for the widget: commentsText
	 * @memberOf HD.community.Photo
	 */
	getCommentsText : function(numOfComments) {
		var text = this.commentsTextFirst.replace(/\{number\}/, numOfComments);
		if(numOfComments != null && numOfComments > 0) {
			text = this.commentsText.replace(/\{number\}/, numOfComments);
		}
		return text;
	},
	
	/**
	 * @constant
	 * @return {string} Next label for the widget: nextLabel
	 * @memberOf HD.community.Photo
	 */
	getNextLabel : function(){
		return this.nextLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Previous label for the widget: previousLabel
	 * @memberOf HD.community.Photo
	 */
	getPreviousLabel : function(){
		return this.previousLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Average votes text for the widget: averageVotesText
	 * @memberOf HD.community.Photo
	 */
	getAverageVotesText : function(numOfVotes, textRating) {
		return this.averageVotesText.replace(/\$\{num_of_votes\}/, numOfVotes).replace(/\$\{text_rating\}/, textRating);
	},
	
	/**
	 * @constant
	 * @return {string} Send to a friend text for the widget: emailText
	 * @memberOf HD.community.Photo
	 */
	getEmailText : function() {
		return this.emailText;
	},
	
	/**
	 * @constant
	 * @return {string} Main template for the widget
	 * @memberOf HD.community.Photo
	 */
	getHtml : function() {
		return this.html;
	},
	
	/**
	 * @constant
	 * @return {string} Votes class text for the widget
	 * @memberOf HD.community.Blog
	 */
	getVotesText : function(){
		return HD.util.StarRating.CSS_CLASSES.NUM_OF_VOTES + ' ' + HD.community.Photo.hooks.MEDIA_VOTES;
	},
	
	/**
	 * @constant
	 * @return {string} Ratings class text for the widget
	 * @memberOf HD.community.Blog
	 */
	getRatingText : function(){
		return HD.util.StarRating.CSS_CLASSES.TEXT_RATING + ' ' + HD.community.Photo.hooks.MEDIA_RATING_TEXT;
	},
	
	/** 
	 * Main template for the widget
	 * @memberOf HD.community.Photo
	 * @type jst_template
	 */	
	html :  '\
		<div class="${classes.ITEM} ${classes.PHOTO}{if !photo.previous} ${classes.FIRST}{/if}{if !photo.next} ${classes.LAST}{/if} ${hooks.MEDIA_ITEM}">\
			<div class="${classes.SMALL_THUMB_WRAPPER}">\
				<div class="${classes.SMALL_THUMB} ${hooks.MEDIA_THUMB}" style="background: transparent url(${photo.thumbUrl}) no-repeat 50% 50%;">\
					<div class="${classes.THUMB_OVERLAY}"></div>\
				</div>\
			</div>\
			<div class="${classes.LARGE_THUMB_WRAPPER}">\
				<div class="${classes.LARGE_THUMB}" style="background: transparent url(${photo.url}) no-repeat 50% 50%;"></div>\
				<div class="${classes.THUMB_OVERLAY}"></div>\
			</div>\
			<div class="${classes.LEFT}">\
				<div class="${classes.TITLE} ${hooks.MEDIA_TITLE}">${photo.title|ellipse:config.titleLength || photo.title.length}</div>\
				<div class="${classes.CATEGORIES}">\
				{if photo.category}\
					<div class="${classes.LABEL}">${templates.getCategoryLabel()}</div>\
					<div class="${classes.VALUE}"><a class="${classes.CATEGORY} ${hooks.MEDIA_CATEGORY}" href="javascript:void(0)">${photo.category}</a></div>\
				{/if}\
				</div>\
				<div class="${classes.TAG_LIST}">\
				{if hasTags}\
					<div class="${classes.LABEL}">${templates.getTagsLabel()}</div>\
					<div class="${classes.VALUE}">\
					{for tag in photo.tags}{if tag_index > 0}${", "}{/if}<a class="${classes.TAG} ${hooks.MEDIA_TAG}" href="javascript:void(0)">${tag}</a>{/for}\
					</div>\
				{/if}\
				</div>\
				<div class="${classes.AUTHOR} ${hooks.MEDIA_AUTHOR}">\
				{if !photo.hiddenAuthor}\
					<div class="${classes.LABEL}">${templates.getAuthorLabel()}</div>\
					<div class="${classes.VALUE}">${photo.author}</div>\
				{/if}\
				</div>\
				<div class="${classes.DATE}">\
					<div class="${classes.LABEL}">${templates.getDateLabel()}</div>\
					<div class="${classes.VALUE}">${photo.uploadedDate|date}</div>\
				</div>\
				<div class="${classes.RATING}">\
					<div class="${ratingClasses.AVERAGE_RATING} ${hooks.MEDIA_RATING_AVG}">\
						<div class="${ratingClasses.STAR_RATING} ${hooks.MEDIA_RATING_STAR}"></div>\
						<div class="${classes.WRAPPER}">\
							(<div class="${ratingClasses.NUM_OF_VOTES} ${hooks.MEDIA_VOTES}"></div>)\
						</div>\
					</div>\
					<div class="${ratingClasses.MY_RATING} ${hooks.MEDIA_RATING_MY}">\
						<div class="${ratingClasses.CAPTION} ${hooks.MEDIA_CAPTION}"></div> \
						<div class="${ratingClasses.STAR_RATING}  ${hooks.MEDIA_RATING_STAR}"></div>\
						<br/><div class="${classes.RATING}Wrapper">\
							${templates.getAverageVotesText(\'<div class="\'+templates.getVotesText()+\'"></div>\',\'<div class="\'+templates.getRatingText()+\'"></div>\')}\
						</div>\
					</div>\
				</div>\
			</div>\
			<div class="${classes.RIGHT}">\
				<div class="${classes.NAVIGATION}">\
					<div class="${classes.PREVIOUS} ${hooks.MEDIA_PREVIOUS}">${templates.getPreviousLabel()}</div>\
					<div class="${classes.NEXT} ${hooks.MEDIA_NEXT}">${templates.getNextLabel()}</div>\
				</div>\
				<a class="${classes.COMMENTS}Button ${hooks.MEDIA_COMMENTS_BTN}" id="${commentsButtonId}">${templates.getCommentsText(photo.numberOfComments)}</a>\
				<div class="${classes.EMAIL}">${templates.getEmailText()}</div>\
			</div>\
			<div class="${classes.DESCRIPTION}">\
				<div>${photo.description}</div>\
			</div>\
			{if config.embedShare}\
				${shareWidget|html}\
			{/if}\
			{if config.embedSendFriend}\
				${sendFriendWidget|html}\
			{/if}\
		</div>'
};

(function() {
	
	/**
	 * The collection of hooks
	 */
	HD.community.Photo.hooks = HD.clone(HD.community.Media.hooks);
})();


HD.community.Photo.prototype = {
		
	/**
	 * Renders the HTML for the widget based on dynamic data.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 * @returns {string} HTML for the widget
	 */
	getHtml : function(config) {
		var photo = this.data;
		if(photo == null) {
			return "";
		}
		
		// Load templates from the dynamic config.
		this.loadTemplates(HD.community.Photo.templates, HD.community.Photo.hooks, { config: config, templates: 'photoTemplates', hooks: 'photoHooks'});
		
		this.commentsButtonId = HD.util.Common.generateElementId();
		
		// Embed share/send friend widgets.
		if (config.embedShare) {
			this.shareWidget = new HD.ShareWidget(HD.merge(config.shareConfig, { embedMode: true }));
		}
		if (config.embedSendFriend) {
			this.sendFriendWidget = new HD.SendFriendWidget(HD.merge(config.sendFriendConfig, { embedMode: true }));
		}
		
		return this.processTemplate(this.config.templates.getHtml(), {
			photo            : photo,
			config           : config,
			shareWidget      : this.shareWidget || null,
			sendFriendWidget : this.sendFriendWidget || null,
			commentsButtonId : this.commentsButtonId,
			hasTags          : photo.tags && photo.tags.length > 0,
			ratingClasses    : HD.util.StarRating.CSS_CLASSES,
			_MODIFIERS       : {
				html         : function(widget) { return widget.getHtml(photo); }
			}
		});
	},
	
	/**
	 * Removes tooltip
	 */
	destroy : function() {
		if (this.tooltip) {
			this.tooltip.destroy();
			delete this.tooltip;
		}
	},
	
	/**
	 * Sets event listener for the widget.
	 * @param {HTMLElement} photoEl
	 *                 		Container for the photo display
	 * @param {object} 		widget
	 * 						Widget object calling the photo
	 */
    setListener : function(photoEl, widget) {
		
    	var photo = this.data;
		if(photo == null) {
			return "";
		}
		
		var classes = HD.CSS_CLASSES;
		var ratingClasses = HD.util.StarRating.CSS_CLASSES;
		
		var config = widget.config;
		
		// Decide whether the entire widget is clickable or just the thumb
		var isWholeElClickable = config.type.match(/^(hd_gallery_widget|hd_carousel_widget)$/);
		
		if(isWholeElClickable) {
			photoEl.onclick = function() {
				widget.notifyObservers.call(widget, "itemSelected", photo);
				widget.model.setActiveItem.call(widget.model, photo);
			};
		}
		
		var thumbEls = HD.getByClass(this.config.hooks.MEDIA_THUMB, '*', photoEl);
		
		if(thumbEls.length > 0) {
		
			var thumbEl = thumbEls[0];
			
			if(!isWholeElClickable) {
				thumbEl.onclick = function() {
			
					widget.notifyObservers.call(widget, "itemSelected", photo);
					widget.model.setActiveItem.call(widget.model, photo);
				};
			}
			
			// TODO abstract tooltip into an HD method
			if(config.isShowPopups) {
				this.tooltip = new YAHOO.widget.Tooltip(HD.util.Common.generateElementId(), 
						{ context:thumbEl, 
						  text:'<div class="' + HD.CSS_CLASSES.TOOL_TIP + '">' + photo.description.substring(0,200) + '</div>',
						  autodismissdelay:60000}); // show tooltip for up to 1 minute
			}
		}
		
		// Update the comments
		var cb = this;
		widget.model.addObserver({
			update : function(eventName, eventData) {
				if(eventName == "submitComment_Finish" || eventName == "getComments_Finish") {
					if(eventData.mediaId == photo.mediaId) {
						cb.data = eventData;
						var buttonEl = HD.get(cb.commentsButtonId);
						if(buttonEl != null) {
							buttonEl.innerHTML = HD.community.Photo.templates.getCommentsText(eventData.numberOfComments);
						}
					}
				}
			}
		});
		
		// Attach category clicked events
		if (!!photo.category) {
			var catEl = HD.getByClass(this.config.hooks.MEDIA_CATEGORY, '*', photoEl);
			if (catEl[0]) {
				catEl[0].onclick = function() {
					widget.model.setCategories([photo.category]);
				};
			}
		}

		// Attach tag clicked events
		if (photo.tags && photo.tags.length > 0) {
			var tagEls = HD.getByClass(this.config.hooks.MEDIA_TAG, '*', photoEl);
			for (var i = 0, len = tagEls.length; i < len; i++) {
				(function() {
					var tag = photo.tags[i];
					tagEls[i].onclick = function() {
						widget.model.setTags([tag]);
					};
				})();
			}
		}
		
    	/////////// RATING ////////////////
    	var myRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_MY, '*', photoEl)[0] || null;
    	var avgRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_AVG, '*', photoEl)[0] || null;
    	var ratingObserver = {
    		update : function(eventName, eventData) {
    			widget.model.rateMedia.call(widget.model, photo.mediaId, photo.contentType, eventData);
    		}
    	};
		var isRated = photo.currentUserRating > 0;
		var myRating = null;
		if(isRated) {
			myRating = parseInt(photo.currentUserRating);
		}
		
		if (avgRatingEl) {
			var captionEl = HD.getByClass(this.config.hooks.MEDIA_CAPTION, '*', avgRatingEl)[0] || null;
			var starRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_STAR, '*', avgRatingEl)[0] || null;
			var textRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_TEXT, '*', avgRatingEl)[0] || null;
			var numOfVotesEl = HD.getByClass(this.config.hooks.MEDIA_VOTES, '*', avgRatingEl)[0] || null;
			
			var staticRating = new HD.util.StarRating({
				// elements to render data in
				captionParent : captionEl,
				textRatingParent : textRatingEl,
				starRatingParent : starRatingEl,
				numOfVotesParent : numOfVotesEl,
		
				// data values
				numOfVotes : photo.numberOfVotes,
				averageRating : photo.rating,
	    		isStatic : true,
	    		itemId : photo.mediaId,
	    		myRating : myRating,
	    		isRated : isRated,
   		
	    		// config options
	    		numOfDecimals : 1,
	    		requiresLogin : config.requiresRatingLogin,
				showRatingHalves : config.showRatingHalves || false,
	    		showYourRatingText : config.showYourRatingText || false
	    	});
			this.ratings.push(staticRating);
		}
		
		if (myRatingEl) {
			var captionEl = HD.getByClass(this.config.hooks.MEDIA_CAPTION, '*', myRatingEl)[0] || null;
			var starRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_STAR, '*', myRatingEl)[0] || null;
			var textRatingEl = HD.getByClass(this.config.hooks.MEDIA_RATING_TEXT, '*', myRatingEl)[0] || null;
			var numOfVotesEl = HD.getByClass(this.config.hooks.MEDIA_VOTES, '*', myRatingEl)[0] || null;
			
			var dynamicRating = new HD.util.StarRating({
				// elements to render data in
				captionParent : captionEl,
				textRatingParent : textRatingEl,
				starRatingParent : starRatingEl,
				numOfVotesParent : numOfVotesEl,
		
				// data values
				numOfVotes : photo.numberOfVotes,
				averageRating : photo.rating,
	    		isStatic : false,
	    		itemId : photo.mediaId,
	    		myRating : myRating,
	    		isRated : isRated,
   		
	    		// config options
	    		numOfDecimals : 1,
	    		requiresLogin : config.requiresRatingLogin,
				showRatingHalves : config.showRatingHalves || false,
	    		showYourRatingText : config.showYourRatingText || false
	    	});
			this.ratings.push(dynamicRating);
			dynamicRating.addObserver(ratingObserver);
		}
		
		widget.model.addObserver({
			update : function(eventName, eventData) {
				if(eventName == "rateMedia_Finish") {
					if(eventData.mediaId == photo.mediaId) {
						photo.numberOfVotes = eventData.numberOfVotes;
						photo.rating = eventData.rating;
						
						cb.updateRatingWidgets.call(cb, eventData);
					}
				}
			}
		});
		
		var model = widget.model;
		
		var previousEl = HD.getByClass(this.config.hooks.MEDIA_PREVIOUS, '*', photoEl)[0];
		var nextEl = HD.getByClass(this.config.hooks.MEDIA_NEXT, '*', photoEl)[0];
		
		if(previousEl){
			if(model.hasPreviousItem()) {
				previousEl.onclick = function() {
					widget.view.notifyObservers.call(widget.view, "itemChange_Start", photo);
					model.getPreviousItem.call(model);
				};
			} else {
				HD.addClass(previousEl, classes.HIDDEN);
			}
		}
		
		if (nextEl){
			if(model.hasNextItem()) {
				nextEl.onclick = function() {
					widget.view.notifyObservers.call(widget.view, "itemChange_Start", photo);
					model.getNextItem.call(model);
				};
			} else {
				HD.addClass(nextEl, classes.HIDDEN);
			}
		}
		
		var commentButton = HD.get(cb.commentsButtonId);
		if (commentButton){
			commentButton.onclick = function() {
				var commentsEl = HD.get("commentsDiv");
				if(commentsEl != null) {
					HD.util.Common.scrollTo(commentsEl);
				}
			};
		}
		
		// Update share/send friend widgets.
		if (widget.config.embedShare && this.shareWidget) {
			this.shareWidget.config.parent = photoEl;
			this.shareWidget.setListeners(photo);
		}
		if (widget.config.embedSendFriend && this.sendFriendWidget) {
			this.sendFriendWidget.config.parent = photoEl;
			this.sendFriendWidget.setListeners(photo);
		}
    }
};

HD.extend(HD.community.Photo, [HD.community.Media]);

HD.register('hd_photo', 'HD.community.Photo', {version: "1.0", build: "1"});