/**
 * @class HD.CategoriesWidget
 * @description The purpose of CategoriesWidget is to provide a mechanism to dynamically change 
 *              the categories data filter on HD.CommunityDAO. Default render options include 
 *              an unordered list (UL) and selectable list (SELECT). Registered as hd_categories_widget.
 * @constructor
 * @extends HD.Widget
 * @see HD.CategoriesWidget.hooks
 * @see HD.CategoriesWidget.templates
 * @property {object} config
 *                 The configuration for the widget
 * @property {object} [config.hooks=HD.CategoriesWidget.hooks]
 *                 Customized subset of hooks (merged with the defaults).
 * @property {array}  [config.items=[]]
 *                 An ordered array of name/value object pairs of categories arrays.
 *                 Example: [{ name: 'All Stories', categories: ['HD/105th','Dark Custom'] }, 
 *                 { name: '105th', categories: ['HD/105th'] }]
 * @property {string} [config.renderMode="list"] 
 *                 How to render the categories. Can be set to 'list' or 'select'.
 * @property {object} [config.templates=HD.CategoriesWidget.templates]
 *                 Customized subset of templates (merged with the defaults).
 */
HD.CategoriesWidget = function(config) {
    this.config = config || {};
	this.config.items = this.config.items || [];
	this.config.renderMode = this.config.renderMode || 'list' || 'select';

	/** Observer collection */
    this.observers = [];
	
	/**
	 * The current active categories object casted as a string for easy state comparisons.
	 * @type string
	 */
	this.categories = this.config.items.length > 0 ? this.config.items[0].categories.join(';') : '';
	
	this.loadTemplates(arguments.callee);
	this.render();
};

/**
 * The collection of default templates.
 */
HD.CategoriesWidget.templates = {
	/**
	 * Label for the widget
	 * @memberOf HD.CategoriesWidget
	 */
	categoryLabel : 'Category',
	
	/**
	 * @constant
	 * @return {string} Label for the widget
	 * @memberOf HD.CategoriesWidget
	 */
	getCategoryLabel : function() {
		return this.categoryLabel;
	},
	
	/**
	 * @constant
	 * @return {string} Main template for the widget
	 * @memberOf HD.CategoriesWidget
	 */
	getHtml : function() {
		return this.html;
	},
	
	/** 
	 * Main template for the widget
	 * @memberOf HD.CategoriesWidget
	 * @type jst_template
	 */
	html :  '\
		<div class="${classes.CATEGORIES} ${classes.WIDGET}"><span>${templates.getCategoryLabel()}</span>\
		{if config.renderMode == "list"}\
			<ul class="${hooks.LIST}">\
			{for item in items}\
				<li class="${hooks.ITEM}{if item_index == 0} ${classes.ACTIVE}{/if}"><a href="javascript:void(0)">${item.name}</a></li>\
			{/for}\
			</ul>\
		{elseif config.renderMode == "select"}\
			<select class="${hooks.LIST}">\
			{for item in items}\
				<option class="${hooks.ITEM}" value="${item_index}"{if item_index == 0} selected="selected"{/if}>${item.name}</option>\
			{/for}\
			</select>\
		{/if}\
		</div>'
};

(function() {
	var classes = HD.CSS_CLASSES;
	
	/**
	 * The collection of hooks.
	 */
	HD.CategoriesWidget.hooks = {
		/**
		 * Standalone: 0..n <br/>
		 * Type: OPTION for config.renderMode="select" <br/>
		 * Use: Selecting category nodes <br/>
		 * @memberOf HD.CategoriesWidget
		 */
		ITEM : classes.ITEM,
		
		/**
		 * Standalone: 0..1 <br/>
		 * Type: SELECT for config.renderMode="select" <br/>
		 * Use: Selecting the parent node of the list <br/>
		 * @memberOf HD.CategoriesWidget
		 */
		LIST : classes.LIST
	};
})();

HD.CategoriesWidget.prototype = { 
	/**
	 * Sets event listeners for the widget.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */
    setListeners : function(data) {
		var classes = HD.CSS_CLASSES;
		var self = this;
		
		// Set categories value in DAO on change
		if (this.config.renderMode == 'list') {
			var nodes = HD.getByClass(this.config.hooks.ITEM, '*', this.getParent());
			for (var i = 0, l = nodes.length; i < l; i++) {
				(function() {
					var offset = i;
					nodes[offset].onclick = function() {
						for (var j = 0; j < l; j++) {
							HD.removeClass(nodes[j], classes.ACTIVE);
						}
						HD.addClass(this, classes.ACTIVE);
						var categories = self.config.items[offset].categories;
						self.model.setCategories(categories);
						self.categories = categories.join(';');
					};
				})();
			}
		}
		else if (this.config.renderMode == 'select') {
			HD.getByClass(this.config.hooks.LIST, '*', this.getParent(), function(list) {
				list.onchange = function() {
					var categories = self.config.items[parseInt(this.options[this.selectedIndex].value, 10)].categories;
					self.model.setCategories(categories);
					self.categories = categories.join(';');
				};
			});
		}
    },
    
	/**
	 * Monitors events by HD.CommunityDAO.
	 * @param {string} eventName
	 *                 The name of the event
	 * @param {object} [eventData]
	 *                 Data for the event
	 */
    update : function(eventName, eventData) {
		// Update the selector if necessary.
		if (eventName == 'categories_Set') {
			// Check if the active category is in sync.
			if (eventData.join(';') != this.categories) {
				// Grab relevant data.
				var eventDataString = eventData.join(';');
				var nodes = [];
				var classes = HD.CSS_CLASSES;
				if (this.config.renderMode == 'list') {
					nodes = HD.getByClass(this.config.hooks.ITEM, '*', this.getParent());
				}
				else if (this.config.renderMode == 'select') {
					nodes = HD.getByClass(this.config.hooks.LIST, '*', this.getParent());
				}
				
				// Update the selector.
				for (var i = 0; i < this.config.items.length; i++) {
					if (this.config.renderMode == 'list' && nodes[i]) {
						HD.removeClass(nodes[i], classes.ACTIVE);
					}
					// Found matching categories, updating as active.
					if (this.config.items[i].categories.join(';') == eventDataString) {
						if (this.config.renderMode == 'list' && nodes[i]) {
							HD.addClass(nodes[i], classes.ACTIVE);
						}
						else if (this.config.renderMode == 'select' && nodes[0]) {
							nodes[0].selectedIndex = i;
							break;
						}
					}
				}
			}
		}
    },
    
	/**
	 * 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 : this.config.items
		});
	}
};

HD.extend(HD.CategoriesWidget, [HD.Widget]);

HD.register('hd_categories_widget', 'HD.CategoriesWidget', {version: "1.0", build: "1"});