/**
 * @class HD.GalleryWidget
 * @description The purpose of GalleryWidget is to provide a mechanism to display an array of media 
 *              (blog/photo/video/etc), either as a normal list or a matrix of media.
 * @constructor
 * @extends HD.Widget
 * @see HD.GalleryWidget.hooks
 * @see HD.GalleryWidget.templates
 * @property {object} config
 *                 The configuration for the widget.
 * @property {string}  config.dateFormat
 *                 The format that dates for media should be displayed in.
 * @property {object}  [config.hooks=HD.GalleryWidget.hooks]
 *                 Customized subset of hooks (merged with the defaults).
 * @property {boolean} [config.embedSendFriend=false]
 *                 Whether to embed a HD.SendFriendWidget within each media.
 * @property {boolean} [config.embedShare=false]
 *                 Whether to embed a HD.ShareWidget within each media.
 * @property {number}  config.itemsX
 *                 The number of media to display in each row.
 * @property {number}  config.itemsY
 *                 The number of media to display in each column.
 * @property {string}  config.previewLength
 *                 The maximum length of a shortened description for media.
 * @property {object}  [config.sendFriendConfig=false]
 *                 The widget configuration for the embedded HD.SendFriendWidget.
 * @property {object}  [config.shareConfig=false]
 *                 The widget configuration for the embedded HD.ShareWidget.
 * @property {boolean} [config.showPageSizeSwitch=false]
 *                 Whether to provide the ability to change the page size.
 * @property {number}  [config.playerHeight=300]
 *                 Height (in pixels) for an hd_player object.
 * @property {number}  [config.playerWidth=400]
 *                 Width (in pixels) for an hd_player object.
 * @property {array}   [config.sorts=[
 *		{ name: this.config.templates.getSortNewToOldText(), value:HD.SORTS.NEW_TO_OLD, isDefault: false },
 *		{ name: this.config.templates.getSortOldToNewText(), value:HD.SORTS.OLD_TO_NEW, isDefault: true }
 *	]]
 *                 The list of sorting options for the gallery.
 * @property {boolean} [config.showMatrix=false]
 *                 Whether to render the gallery as a matrix (overrides contentType defaults).
 * @property {object}  [config.templates=HD.GalleryWidget.templates]
 *                 Customized subset of templates (merged with the defaults).
 * @property {number}  [config.titleLength=0]
 *                 The maximum character length for a media's title (0 = no maximum).
 * @property {number}  [config.viewAllMax=50]
 *                 The maximum page size (when using config.showPageSizeSwitch=true).
 * @property {object}  [config.blogHooks]
 *                 Customized subset of hooks for HD.community.Blog media.
 * @property {object}  [config.blogTemplates]
 *                 Customized subset of templates for HD.community.Blog media.
 * @property {object}  [config.pagingHooks]
 *                 Customized subset of hooks for HD.util.Paging.
 * @property {object}  [config.pagingTemplates]
 *                 Customized subset of templates for HD.util.Paging.
 * @property {object}  [config.photoHooks]
 *                 Customized subset of hooks for HD.community.Photo media.
 * @property {object}  [config.photoTemplates]
 *                 Customized subset of templates for HD.community.Photo media.
 * @property {object}  [config.videoHooks]
 *                 Customized subset of hooks for HD.community.Video media.
 * @property {object}  [config.videoTemplates]
 *                 Customized subset of templates for HD.community.Video media.
 */
HD.GalleryWidget = function(config) {
    this.config = config || {};
	this.config.titleLength = this.config.titleLength || 0;
	this.config.viewAllMax = this.config.viewAllMax || 50;
	this.config.embedShare = this.config.embedShare || false;
	this.config.shareConfig = this.config.shareConfig || {};
	this.config.embedSendFriend = this.config.embedSendFriend || false;
	this.config.sendFriendConfig = this.config.sendFriendConfig || {};
	this.config.showMatrix = this.config.showMatrix || false;
	this.config.showPageSizeSwitch = this.config.showPageSizeSwitch || false;
    this.observers = [];
	this.loadTemplates(arguments.callee);
	
	// Default sorts uses templates, defining last.
	this.config.sorts = this.config.sorts || [
		{ name: this.config.templates.getSortNewToOldText(), value:HD.SORTS.NEW_TO_OLD, isDefault: false },
		{ name: this.config.templates.getSortOldToNewText(), value:HD.SORTS.OLD_TO_NEW, isDefault: true }
	];
};

/**
 * The collection of default templates.
 */
HD.GalleryWidget.templates = {
	/**
	 * Label for the sorting control
	 * @memberOf HD.GalleryWidget
	 */
	sortByLabel      : "Sort By",
	/**
	 * Label for the new-to-old default sorting type
	 * @memberOf HD.GalleryWidget
	 */
	sortNewToOldText : "Newest To Oldest",
	/**
	 * Label for the old-to-new default sorting type
	 * @memberOf HD.GalleryWidget
	 */
	sortOldToNewText : "Oldest To Newest",
	
	/**
	 * @constant
	 * @return {string} Label for the sorting control
	 * @memberOf HD.GalleryWidget
	 */
	getSortByLabel : function() {
		return this.sortByLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Label for the new-to-old default sorting type
	 * @memberOf HD.GalleryWidget
	 */
	getSortNewToOldText : function() {
		return this.sortNewToOldText;
	},
	
	/**
	 * @constant
	 * @return {string} Label for the old-to-new default sorting type
	 * @memberOf HD.GalleryWidget
	 */
	getSortOldToNewText : function() {
		return this.sortOldToNewText;
	},
	
	/**
	 * @constant
	 * @return {string} Main template for the widget
	 * @memberOf HD.GalleryWidget
	 */
	getHtml : function() {
		return this.html;
	},
	
	/** 
	 * Main template for the widget
	 * @memberOf HD.GalleryWidget
	 * @type jst_template
	 */
	html :  '\
		<div class="${classes.GALLERY} ${classes.WIDGET}">\
		{if community.isBoth(contentType) || community.isPhoto(contentType) || community.isVideo(contentType) || config.showMatrix}\
			<div class="${classes.CONTROL_PANEL}">\
				<span class="${classes.SORT}">\
					<span>${templates.getSortByLabel()}</span>\
					<select class="${hooks.SORTING}">\
						{for sort in config.sorts}\
							{if selectedSort == sort.value || sort.isDefault}\
								<option value="${sort.value}" selected>${sort.name}</option>\
							{else}\
								<option value="${sort.value}">${sort.name}</option>\
							{/if}\
						{/for}\
					</select>\
				</span>\
				<span class="${hooks.PAGING}"></span>\
			</div>\
			<div class="${classes.CONTENT_PANEL}">\
				<table>\
					<tr class="{if rows == 1}${classes.LAST}{else}${classes.FIRST}{/if}">\
					{var rows = Math.ceil(items.length / config.itemsX)}\
					{for item in items}\
						{if item_index > 0 && item_index % config.itemsX == 0}\
							{if rows == (Math.ceil(item_index / config.itemsX) + 1)}\
								</tr><tr class="${classes.LAST}">\
							{else}\
								</tr><tr>\
							{/if}\
						{/if}\
						<td>${item|facade}</td>\
					{/for}\
					</tr>\
				</table>\
			</div>\
			<div class="${classes.CONTROL_PANEL}">\
				<span class="${hooks.PAGING}"></span>\
			</div>\
		{elseif community.isBlog(contentType)}\
			<div class="${classes.CONTROL_PANEL}">\
				<span class="${classes.PAGING}"></span>\
			</div>\
			<div class="${classes.CONTENT_PANEL}">\
				{for blog in items}\
					${blog|facade}\
				{/for}\
			</div>\
			<div class="${classes.CONTROL_PANEL} ${classes.LAST}">\
				<span class="${classes.PAGING}"></span>\
			</div>\
		{/if}\
		</div>'
};

(function() {
	var classes = HD.CSS_CLASSES;
	
	/**
	 * The collection of hooks.
	 */
	HD.GalleryWidget.hooks = {
		/**
		 * Standalone: 0..n <br/>
		 * Use: Selecting the nodes that will contain pagers <br/>
		 * @memberOf HD.GalleryWidget
		 */
		PAGING : classes.PAGING,
		
		/**
		 * Standalone: 0..1 <br/>
		 * Type: SELECT
		 * Use: Selecting and managing the list of sorting modes <br/>
		 * @memberOf HD.GalleryWidget
		 */
		SORTING : classes.SORT+'-list'
	};
})();

HD.GalleryWidget.prototype = {
	/**
	 * Monitors events by HD.CommunityDAO.
	 * @param {string} eventName
	 *                 The name of the event
	 * @param {object} [eventData]
	 *                 Data for the event
	 */
    update : function(eventName, eventData) {
    	if(eventName == "getMedia_Start") {
    		this.loading(true);
    	} else if(eventName == "getMedia_Finish") {
    		this.loading(false);
			if (this.mediaCache) {
				for (var i = 0; i < this.mediaCache.length; i++) {
					this.mediaCache[i].facade.destroy();
				}
			}
			/** Cache of the last media set. */
			this.mediaCache = eventData.media;
    		this.render(eventData);
    		if(this.paging != null) {
    			this.paging.controller.updatePagingData(eventData);
    		}
    	}
    },
    
	/**
	 * Sets event listeners for the widget.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */
    setListeners : function(data) {
    	if(HD.community.isBoth(data.contentType) || HD.community.isPhoto(data.contentType) || HD.community.isVideo(data.contentType) || this.config.showMatrix) {
    		return this.setBothListeners(data);
    	} else if(HD.community.isBlog(data.contentType)) {
    		return this.setBlogListeners(data);
    	}
    },
    
	/**
	 * Sets event listeners for the widget when set to photo/video/both media.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */
    setBothListeners : function(data) {
    	var classes = HD.CSS_CLASSES;
    	var viewAllMax = this.config.viewAllMax;
    	var defaultPageSize = this.config.itemsX*this.config.itemsY;
    	var showPageSizeSwitch = this.config.showPageSizeSwitch;
    	var parentEl = this.getParent();

		if (data.media.length > 0) {
			var itemEls = HD.getByClass(data.media[0].facade.config.hooks.MEDIA_ITEM, "*", parentEl);
			var photos = data.media;
		
			for(var i = 0, len = photos.length; i < len; i++) {
				if(photos[i] && itemEls[i]) {
					photos[i].facade.setListener(itemEls[i], this, this.config);
				}
			}
		}
		
		//////////////////
		// initialize paging
		var pagingEls = HD.getByClass(this.config.hooks.PAGING, "*", parentEl);
		if (pagingEls.length > 0) {
			var paging = new HD.util.Paging({
				startingPage : 1,	// starting page index
				containers : pagingEls,	// element(s) to hold paging controls 
				viewAllMax : viewAllMax,
				defaultPageSize : defaultPageSize,
				showPageSizeSwitch : showPageSizeSwitch,
				templates : this.config.pagingTemplates || {},
				hooks     : this.config.pagingHooks || {}
			});
		
			var cb = this;
			var modelCb = this.model;
			var pagingObserver = {
				update : function(eventName, eventData) {
			
					if(eventName == "paging_Next") {
						modelCb.getNextPage.call(modelCb);
					} else if(eventName == "paging_Previous") {
						modelCb.getPreviousPage.call(modelCb);
					} else if(eventName == "paging_Page") {
						modelCb.getMedia.call(modelCb, eventData);
					} else if(eventName == "show_All" || eventName == "show_Max") {
						modelCb.config.pageSize = viewAllMax;
						modelCb.getSamePage.call(modelCb);
					} else if(eventName == "show_Default") {
						modelCb.config.pageSize = defaultPageSize;
						modelCb.getSamePage.call(modelCb);
					} 
				}
			};

			paging.view.addObserver(pagingObserver);
			
			/** 
			 * Paging for the gallery.
			 * @type HD.util.Paging
			 */
			this.paging = paging;
		}
		//////////////////
		
		HD.getByClass(this.config.hooks.SORTING, "*", parentEl, function(selectEl) {
			selectEl.onchange = function(){
				var sortValue = selectEl.options[selectEl.selectedIndex].value;
				modelCb.setSort.call(modelCb, sortValue);
			};
		});
    },
    
	/**
	 * Sets event listeners for the widget when set to blog media.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */
    setBlogListeners : function(data) {
    	var classes = HD.CSS_CLASSES;
    	var parentEl = this.getParent();
    	var media = data.media;
    	var config = this.config;
    	var model = this.model;
    	
    	var blogItemEls = HD.getByClass(classes.ITEM, "div", parentEl);
    	
    	for(var i = 0, len = blogItemEls.length; i < len; i++) {
    		var medium = media[i];
    		if(medium != null) {
    			medium.facade.setListener(blogItemEls[i], this, config);
    		}
    	}
    	
		//////////////////
		// initialize paging
		var pagingEls = HD.getByClass(this.config.hooks.PAGING, "*", parentEl);
		if (pagingEls.length > 0) {
			var paging = new HD.util.Paging({
				startingPage : 1,	// starting page index
				containers : pagingEls,	// element(s) to hold paging controls
				templates : this.config.pagingTemplates || {},
				hooks     : this.config.pagingHooks || {}
			});

			var cb = this;
			var modelCb = this.model;
			var pagingObserver = {
				update : function(eventName, eventData) {
					if(eventName == "paging_Next") {
						modelCb.getNextPage.call(modelCb);
					} else if(eventName == "paging_Previous") {
						modelCb.getPreviousPage.call(modelCb);
					} else if(eventName == "paging_Page") {
						modelCb.getMedia.call(modelCb, eventData);
					} 
				}
			};
		
			paging.view.addObserver(pagingObserver);
		
			/** 
			 * Paging for the gallery.
			 * @type HD.util.Paging
			 */
			this.paging = paging;
		}
		/////////////////////
    },
    
	/**
	 * Renders the HTML for the widget based on dynamic data.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 * @returns HTML for the widget
	 * @type string
	 */
    getHtml : function(data) {
		return this.processTemplate(this.config.templates.getHtml(), {
			items        : (data && data.media) || [],
			contentType  : data.contentType || '',
			selectedSort : this.model.getSort() || '',
			sorts        : HD.SORTS,
			community    : HD.community
		});
    }
};

HD.extend(HD.GalleryWidget, [HD.Widget]);

HD.register('hd_gallery_widget', 'HD.GalleryWidget', {version: "1.0", build: "1"});