/**
 * @class HD.ShareWidget
 * @description The purpose of ShareWidget is to provide a mechanism to share site pages. 
 * 				Registered as hd_share_widget.
 * @constructor
 * @extends HD.Widget
 * @see HD.ShareWidget.hooks
 * @see HD.ShareWidget.templates
 * @property {object} 	config
 *                    	The configuration for the widget.
 * @property {object} 	[config.hooks=HD.ShareWidget.hooks]
 *                 		Customized subset of hooks (merged with the defaults).
 * @property {boolean} 	config.embedMode
 *                    	TBD
 *                    	Default is false.
 * @property {boolean} 	config.standaloneMode
 *                    	Whether the share widget should not be dependent on retrieving content
 *                    	Default is false.
 * @property {number} 	config.previewlength
 *                    	Character length to show in the share preview.
 *                    	Default is 0.
 * @property {array}	config.services
 * 						Array of services to be shown .     
 * 						Default is [services.DIGG, services.FACEBOOK, services.TWITTER].
 * @property {method}	config.getPermalink
 * 						Method to generare URL to be used in share.
 * 						Default is window.location.href
 * @property {boolean}	config.useShareAPI
 * 						Whether or not to use child hd_social_share widget
 * @property {method)	config.callback
 * 						Method fired on user click			             
 * @property {object} 	[config.templates=HD.ShareWidget.templates]
 *                 		Customized subset of templates (merged with the defaults).
 */
HD.ShareWidget = function(config) {
	var services = HD.ShareWidget.SERVICES;
    this.config = config || {};
	this.config.embedMode = this.config.embedMode || false;
	this.config.standaloneMode = this.config.standaloneMode || false;
	this.config.previewLength = this.config.previewLength || 0;
	this.config.services = this.config.services || [services.DIGG, services.FACEBOOK, services.TWITTER];
	this.config.getPermalink = this.config.getPermalink || function(media, service, config) { 
		return media.facade.generatePermalink();
	};
	this.config.useShareAPI = this.config.useShareAPI == null ? true : this.config.useShareAPI;
	this.config.callback = this.config.callback || function(service, shareUrl, title, description, thumbUrl, media) {};
	
	// Update/validate services to point to actual service configs.
	for (var i = this.config.services.length - 1; i >= 0; i--) {
		if (typeof this.config.services[i] == 'string') {
			this.config.services[i] = this.getService(this.config.services[i]);
			if (!this.config.services[i]) {
				this.config.services[i].splice(i, 1);
			}
		}
	}
    
	/** Observer collection */
    this.observers = [];
	this.loadTemplates(arguments.callee);
};

/**
 * The collection of share services.
 * @fieldOf HD.ShareWidget
 */
HD.ShareWidget.SERVICES = {
	BLOGGER:     { name: 'Blogger', url: null, callback: null },
	DELICIOUS:   { name: 'Delicious', url: null, callback: null },
	DIGG:        { name: 'Digg', url: null, callback: null },
	FACEBOOK:    { name: 'Facebook', url: null, callback: null },
	FRIENDFEED:  { name: 'Friendfeed', url: null, callback: null },
	GOOGLE:      { name: 'Google', url: null, callback: null },
	LINKEDIN:    { name: 'Linked In', url: null, callback: null },
	MAGNOLIA:    { name: 'Magnolia', url: null, callback: null },
	MIXX:        { name: 'Mixx', url: null, callback: null },
	MYSPACE:     { name: 'MySpace', url: null, callback: null },
	NEWSVINE:    { name: 'NewsVine', url: null, callback: null },
	REDDIT:      { name: 'Reddit', url: null, callback: null },
	SLASHDOT:    { name: 'Slashdot', url: null, callback: null },
	STUMBLEUPON: { name: 'Stumble Upon', url: null, callback: null },
	TECHNORATI:  { name: 'Technorati', url: null, callback: null },
	TWITTER:     { name: 'Twitter', url: null, callback: null },
	WORDPRESS:   { name: 'Wordpress', url: null, callback: null }
};

/**
 * The collection of default templates.
 */
HD.ShareWidget.templates = {
	/**
	 * Label for the widget
	 * @memberOf HD.ShareWidget
	 */	
	shareLabel : "Share: ",
	
	/**
	 * @constant
	 * @return {string} Label for the widget: shareLabel
	 * @memberOf HD.ShareWidget
	 */
	getShareLabel : function(){
		return this.shareLabel;
	},
	
	/**
	 * @constant
	 * @return {string} JST template for the widget
	 * @memberOf HD.ShareWidget
	 */
	getHtml : function() {
		return this.html;
	},
	
	/** 
	 * JST template for the widget
	 * @memberOf HD.ShareWidget
	 * @type jst_template
	 */
	html :  '\
		<div class="${classes.SHARE} ${classes.WIDGET}">\
			<span>${templates.getShareLabel()}</span>\
			<ul>\
			{for service in config.services}\
				<li class="${service|getClass} ${hooks.ITEMSHARE}">\
					<a class="${hooks.ITEMLINK}" \
						{if _MODIFIERS.getUrl(service,media)}\
							href="${service|getUrl:media}" target="_blank"\
						{else}\
							href="javascript:void(0)"\
						{/if}\
					></a>\
					<div><span>${service.name}</span></div></li>\
			{/for}\
			</ul>\
		</div>\
		<div class="${classes.SHARE}Clear"></div>'
};

(function() {
	var classes = HD.CSS_CLASSES;
	
	/**
	 * The collection of hooks
	 */
	HD.ShareWidget.hooks = {
		
		/**
		 * Standalone: 0..n<br />
		 * Use: share listing<br />
		 * @memberOf HD.ShareWidget
		 */
		ITEMSHARE : classes.SHARE + '-item',
		
		/**
		 * Dependencies: 0..1:ITEMSHARE <br/>
		 * Use: share listing link<br />
		 * @memberOf HD.ShareWidget
		 */
		ITEMLINK : classes.SHARE + '-link'
	};
})();

HD.ShareWidget.prototype = {
    
	/**
	 * Sets event listeners for the widget.
	 * @param {object} [data]
	 *                 Event data from the render phase
	 */		
    setListeners : function(media) {
		if (!media) {
			return;
		}
		
		var self = this;
		// Add click events.
		var linkEls = HD.getByClass(this.config.hooks.ITEMLINK, '*', this.getParent());
		var itemEls = HD.getByClass(this.config.hooks.ITEMSHARE, '*', this.getParent());
		for (var i = 0; i < this.config.services.length; i++) {
			// Handle rollovers
			if(itemEls[i]){
				itemEls[i].onmouseover = function() {
					HD.addClass(this, HD.CSS_CLASSES.SHARE+'Hover');
				};
				itemEls[i].onmouseout = function() {
					HD.removeClass(this, HD.CSS_CLASSES.SHARE+'Hover');
				};
			}
			
			(function() {
				// Add click events
				var service = self.config.services[i];
				if(linkEls[i]){
					linkEls[i].onclick = function() {
						if (service.callback) {
							media = service.callback(media) || media;
						}
						self.notifyObservers('share', { service: service, media: media });
						HD.util.Analytics.track(self.analyticsShareString(service, media));
						if (self.config.callback) {
							var description = HD.util.Common.stripHtmlTags(media.description);
							if (self.config.useShareAPI && window.HDSocial) {
								HDSocial.hdSocialShare(self.getServiceHash(service), self.config.getPermalink(media, service, self.config), media.title, HD.util.Common.ellipseText(description, self.config.previewLength || description.length), media.thumbUrl, null, null, media);
							}
							self.config.callback(service, self.config.getPermalink(media, service, self.config), media.title, HD.util.Common.ellipseText(description, self.config.previewLength || description.length), media.thumbUrl, media);
						}
					};
				}
			})();
		}
    },
    
    /**
	 * Monitors events by HD.ShareWidget.
	 * @param {string} eventName
	 *                 The name of the event
	 * @param {object} [eventData]
	 *                 Data for the event
	 */
    update : function(eventName, eventData) {
    	if (this.config.standaloneMode){
    		if(eventName == "loadShare_Start") {
    			this.render(eventData);
    		}
    	}
    	else if (!this.config.embedMode) {
	    	if(eventName == "getMedium_Start") {
	    		this.loading(true);
	    	} else if(eventName == "getMedium_Finish") {
	    		this.loading(false);
	    		this.render(eventData);
	    	} else if(eventName == "activeItem_Change") {
	    		this.render(eventData);
	    	}
		}
    },
    
    /**
	 * 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(media) {
		if (!media) {
			return;
		}
		
		var self = this;
		return this.processTemplate(this.config.templates.getHtml(), {
			media        : media,
			_MODIFIERS   : {
				getClass : function(service) { return self.getClass(service); },
				getUrl   : function(service, media) { return self.getUrl(service, media); }
			}
		});
    },
    
    /**
	 * Cleans the service name for use in hd_social_share widget
	 * @param {object} [service]
	 *                 Service for share
	 * @returns {string} service name trimmed and lower case or null
	 */
	getServiceHash : function(service) {
		return service.name.replace(/\s+/g,'').toLowerCase() || null;
	},
	
	/**
	 * Cleans the service name for use in validating config.services array
	 * @param {string} serviceName
	 *                 Service name for share
	 * @returns {string} service name trimmed and upper case or null
	 */
	getService : function(serviceName) {
		return HD.ShareWidget.SERVICES[serviceName.replace(/\s+/g,'').toUpperCase()] || null;
	},
	
	/**
	 * Generates a class name with a clean service name for use in markup output
	 * @param {object} [service]
	 *                 Service for share
	 * @returns {string} Class name for service
	 */
	getClass : function(service) {
		return HD.CSS_CLASSES.SHARE + service.name.replace(/\s+/g,'');
	},
	
	/**
	 * Generates a url for use in service links
	 * @param {object} [service]
	 *                 Service for share
	 * @param {object} [media]
	 *                 Event data from the render phase
	 * @returns {string} url for linking to service or null
	 */
	getUrl : function(service, media) {
		if (service.url) {
			var url = service.url;
			url = url.replace(/\{permalink\}/, encodeURIComponent(this.config.getPermalink(media)));
			url = url.replace(/\{title\}/, encodeURIComponent(media.title));
			url = url.replace(/\{thumbnail\}/, encodeURIComponent(media.thumbUrl));
			url = url.replace(/\{description\}/, encodeURIComponent(HD.util.Common.ellipseText(media.description, this.config.previewLength || media.description.length)));
			return url;
		}
		else {
			return null;
		}
	},
	
    /**
	 * Analytics event for when a share event is fired
	 * @param {string} service
	 *                 The service being shared to
	 * @param {object} media
	 *                 The media being shared
	 * @returns {string} Analytics string
	 */
	analyticsShareString : function(service, media) {
		return "default_analyticsShareString";
	}
};

HD.extend(HD.ShareWidget, [HD.Widget]);

HD.register('hd_share_widget', 'HD.ShareWidget', {version: "1.0", build: "1"});
