/**
 * @class HD.MiniGalleryWidget
 * @description The purpose of MiniGalleryWidget is to provide a mechanism to display a small subset of media 
 *              (blog/photo/video/etc) through a miniature list.
 * @constructor
 * @extends HD.Widget
 * @see HD.MiniGalleryWidget.hooks
 * @see HD.MiniGalleryWidget.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.MiniGalleryWidget.hooks]
 *                 Customized subset of hooks (merged with the defaults).
 * @property {number}  config.numOfItems
 *                 The number of media items to display.
 * @property {object}  [config.templates=HD.MiniGalleryWidget.templates]
 *                 Customized subset of templates (merged with the defaults).
 * @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.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.MiniGalleryWidget = function(config) {
    this.config = config;
    
	/** Observer collection */
    this.observers = [];
	this.loadTemplates(arguments.callee);
    
	/** Starting page */
    this.initialPageIndex = 0;
};

/**
 * The collection of default templates.
 */
HD.MiniGalleryWidget.templates = {
	/**
	 * @constant
	 * @return {string} Main template for the widget
	 * @memberOf HD.MiniGalleryWidget
	 */
	getHtml : function() {
		return this.html;
	},
	
	/** 
	 * Main template for the widget
	 * @memberOf HD.MiniGalleryWidget
	 * @type jst_template
	 */
	html :  '\
		<div class="${classes.MINI_GALLERY} ${classes.WIDGET}">\
	   		<div class="${classes.WRAPPER}">\
			{if hasPrevious}\
				<div class="${hooks.PAGING_ARROW} ${hooks.PREVIOUS}">&nbsp;</div>\
    		{/if}\
			</div>\
			{for item in items}\
				${item|facade}\
			{/for}\
	   		<div class="${classes.WRAPPER}">\
			{if hasNext}\
				<div class="${hooks.PAGING_ARROW} ${hooks.NEXT}">&nbsp;</div>\
    		{/if}\
			</div>\
    	</div>'
};

(function() {
	var classes = HD.CSS_CLASSES;
	
	/**
	 * The collection of hooks.
	 */
	HD.MiniGalleryWidget.hooks = {
		/**
		 * Dependencies: 0..1: PAGING_ARROW (should be same element)<br/>
		 * Use: A node that switches to the next page
		 * @memberOf HD.MiniGalleryWidget
		 */
		NEXT : classes.NEXT,
		
		/**
		 * Dependencies: 0..1: PAGING_ARROW (should be same element)<br/>
		 * Use: A node that switches to the previous page
		 * @memberOf HD.MiniGalleryWidget
		 */
		PREVIOUS : classes.PREVIOUS,
		
		/**
		 * Standalone: 0..n <br/>
		 * Use: Nodes that switch pages
		 * @memberOf HD.MiniGalleryWidget
		 */
		PAGING_ARROW : classes.PAGING_ARROW
	};
})();

HD.MiniGalleryWidget.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.separateItems(eventData);
			if (!!this.queueSetActive) {
				this.setActive(this.queueSetActive);
			}
    		this.render(eventData);
    		
    	} else if(eventName == "activeItem_Change") {
    		this.setActive(eventData);
    	}
    },
    
	/**
	 * Renders the HTML for the widget based on dynamic data.
	 * @returns HTML for the widget
	 * @type string
	 */
    getHtml : function() {
    	if (this.model.isLastIndexActive){
    		this.activePage = Math.floor(this.model.config.pageSize/this.config.numOfItems)-1;
    		this.model.isLastIndexActive = false;
    	}
    	
		/** Whether there is a previous mini page for the media set. */
    	this.hasPreviousMiniPage = this.activePage > this.initialPageIndex;
		/** Whether there is a previous media page for the media set. */
    	this.hasPreviousPage = this.model.hasPreviousPage();
		/** Whether there is a next mini page for the media set. */
    	this.hasNextMiniPage = this.activePage < this.pages.length - 1;
		/** Whether there is a next media page for the media set. */
    	this.hasNextPage = this.model.hasNextPage();

		return this.processTemplate(this.config.templates.getHtml(), {
			hasPrevious: this.hasPreviousMiniPage || this.hasPreviousPage,
			hasNext: this.hasNextMiniPage || this.hasNextPage,
			items: this.pages[this.activePage]
		});
    },
    
	/**
	 * Sets the active mini page according to the active selected media.
	 * @param {object} [item]
	 *                 Media item currently selected.
	 */
    setActive : function(item) {
		// Ensure that the page data is present before continuing.
		if (!this.pages) {
			/** Whether to set as active when data is present. */
			this.queueSetActive = item;
			return;
		}
	
    	var classes = HD.CSS_CLASSES;
    	var parentEl = this.getParent();
    	
    	// determine what page the item is in
    	var oldActivePage = this.activePage;
    	var pages = this.pages;
    	for(var i = 0, len = pages.length; i < len; i++) {
    		var pageItems = pages[i];
    		for(var j = 0, len1 = pageItems.length; j < len1; j++) {
    			var pageItem = pageItems[j];
    			if(pageItem != null && pageItem.mediaId == item.mediaId) {
    				this.activePage = i;
    				break;
    			}
    		}
    	}
    	
    	// render the page if not current
    	if(oldActivePage != this.activePage) {
    		this.render();
    	}
    	
    	// add 'selected' class to selected item
    	var pageItems = this.pages[this.activePage];
    	var itemEls = HD.getByClass(classes.ITEM, "div", parentEl);
    	for(var i = 0, len = pageItems.length; i < len; i++) {
    		var pageItem = pageItems[i];
    		var itemEl = itemEls[i];
    		
    		if(pageItem != null && pageItem.mediaId == item.mediaId) {
    			HD.addClass(itemEl, classes.ACTIVE);
    		} else {
    			HD.removeClass(itemEl, classes.ACTIVE);
    		}
    	}
    },
    
	/**
	 * Constructs an internal mini paging structure based on the active page of media.
	 * @param {object} [response]
	 *                 Event data from the update phase
	 */
    separateItems : function(response) {
		/** The current collection of pages. */
    	this.pages = [];
		/** The current mini page. */
    	this.activePage = this.initialPageIndex;
    	
    	var numOfItems = this.config.numOfItems;
    	var rowIndex = 0;
    	this.pages[rowIndex] = [];
    	var items = response.media;
    	for(var i = 0, len = items.length; i < len; i++) {
    		if(i > 0 && i % numOfItems == 0) {
    			rowIndex++;
    			this.pages[rowIndex] = [];
    		}
    		this.pages[rowIndex].push(items[i]);
    	}
    },
    
	/**
	 * Sets event listeners for the widget.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */
    setListeners : function(data) {
     	var hooks = this.config.hooks;
    	var parentEl = this.getParent();
    	
    	var arrowEls = HD.getByClass(hooks.PAGING_ARROW, "*", parentEl);
    	var previousEl = null;
    	var nextEl = null;
    	
    	for(var i = 0, len = arrowEls.length; i < len; i++) {
    		var arrowEl = arrowEls[i];
    		if(HD.hasClass(arrowEl, hooks.NEXT)) {
    			nextEl = arrowEl;
    		} else if(HD.hasClass(arrowEl, hooks.PREVIOUS)) {
    			previousEl = arrowEl;
    		}
    	}

    	var cb = this;
    	var modelCb = this.model;
    	if(previousEl != null) {
	    	previousEl.onclick = function() {
	    		if(cb.hasPreviousMiniPage) {
		    		cb.activePage--;
		    		cb.render.call(cb);
	    		} else if(cb.hasPreviousPage) {
		    		modelCb.getPreviousPage(true, true);
		    		modelCb.isLastIndexActive = true;
		    		
	    		}
	    	};
    	}
    	if(nextEl != null) {
	    	nextEl.onclick = function() {
	    		if(cb.hasNextMiniPage) {
	    			cb.activePage++;
		    		cb.render.call(cb);
	    		} else if(cb.hasNextPage) {
		    		modelCb.getNextPage(true);
	    		}
	    	};
    	}
    	
    	var pageItems = this.pages[this.activePage];
		if (pageItems.length > 0) {
	    	var itemEls = HD.getByClass(pageItems[0].facade.config.hooks.MEDIA_ITEM, "*", parentEl);
	    	for(var i = 0, len = pageItems.length; i < len; i++) {
				if (itemEls[i] && pageItems[i]) {
		    		this.setItemListener(itemEls[i], pageItems[i]);
				}
	    	}
		}
    },
    
	/**
	 * Sets event listeners for the child media items.
	 * @param {object} itemEl
	 *                 The element to apply a listener to
	 * @param {object} item
	 *                 The internal media item to bind to the element
	 */
    setItemListener : function(itemEl, item) {
    	var cb = this;
    	var i = item;
    	itemEl.onclick = function() {
    		cb.view.notifyObservers.call(cb.view, "itemChange_Start", i);
    		cb.model.setActiveItem.call(cb.model, i);
    		cb.model.activeItemPage = cb.model.pageNumber;
    	}
    }
};

HD.extend(HD.MiniGalleryWidget, [HD.Widget]);

HD.register('hd_mini_gallery_widget', 'HD.MiniGalleryWidget', {version: "1.0", build: "1"});
