"use strict";
/**
 * @fileOverview Provides easy access to the system bus and provides some helper methods for doing so
 * @module mixins/bussable
 * @requires postal
 * @requires lodash
 * @requires base
 */
var bus = require( "postal" );
var Base = require( "../base" );
var sys = require( "lodash" );

/**
 *  @classDesc Provides easy access to the system bus and provides some helper methods for doing so
 *  @exports mixins/bussable
 *  @mixin
 */
var Bussable = Base.compose( [Base], /** @lends mixins/bussable# */{
	declaredClass : "mixins/Bussable",
	constructor   : function () {
		/**
		 * The list of subscriptions maintained by the mixin
		 * @type {Array}
		 * @memberof mixins/bussable#
		 * @name _subscriptions
		 * @private
		 */
		this._subscriptions = {};

		this.log.trace( "Bussable constructor" );
	},

	/**
	 * Subscribe to an event
	 * @param {string} channel The channel to subscribe to
	 * @param {string} topic The topic to subscribe to
	 * @param {callback} callback What to do when you get the event
	 * @returns {object} The subscription definition
	 */
	subscribe : function ( channel, topic, callback ) {
		this.log.trace( "Bussable subscribe" );
		var sub = bus.subscribe( {channel : channel, topic : topic, callback : callback} );
		this.subscriptions[channel + "." + topic] = sub;
		return sub;
	},

	/**
	 * Subscribe to an event once
	 * @param {string} channel The channel to subscribe to
	 * @param {string} topic The topic to subscribe to
	 * @param {callback} callback What to do when you get the event
	 * @returns {object} The subscription definition
	 */
	once : function ( channel, topic, callback ) {
		this.log.trace( "Bussable once" );
		var sub = this.subscribe( channel, topic, callback );
		this.subscriptions[channel + "." + topic] = sub;
		sub.disposeAfter( 1 );
		return sub;
	},

	/**
	 * Publish an event on the system bus
	 * @param {string} channel The channel to publish to
	 * @param {string} topic The topic to publish to
	 * @param {object=} options What to pass to the event
	 */
	publish : function ( channel, topic, options ) {
		this.log.trace( "Bussable publish" );
		bus.publish( {channel : channel, topic : topic, data : options} );
	},

	/**
	 * Get a subscription definition
	 *
	 * @param {string} channel
	 * @param {string} topic
	 * @returns {object=} The subscription definition
	 */
	getSubscription : function ( channel, topic ) {
		this.log.trace( "Bussable getSubscription" );
		return this.subscriptions[channel + "." + topic];
	},

	/**
	 * Gets rid of all subscriptions for this object.
	 * @private
	 */
	destroy : function () {
		this.log.trace( "Bussable destroy" );

		sys.each( this.subscriptions, function ( sub ) {
			sub.unsubscribe();
		} );
	}
} );

module.exports = Bussable;
