/**
* Gumby Toggles/Switches
*/
!function($) {

	'use strict';

	// Toggle constructor
	function Toggle($el) {
		this.$el = $($el);
		this.targets = [];
		this.on = '';
		this.className = '';
		this.self = false;

		if(this.$el.length) {
			Gumby.debug('Initializing Toggle', $el);
			this.init();
		}
	}

	// Switch constructor
	function Switch($el) {
		this.$el = $($el);
		this.targets = [];
		this.on = '';
		this.className = '';
		this.self = false;

		if(this.$el.length) {
			Gumby.debug('Initializing Switch', $el);
			this.init();
		}
	}

	// intialise toggles, switches will inherit method
	Toggle.prototype.init = function() {
		var scope = this;

		// set up module based on attributes
		this.setup();

		// bind to specified event and trigger
		this.$el.on(this.on, function(e) {
			e.preventDefault();
			scope.trigger(scope.triggered);

		// listen for gumby.trigger to dynamically trigger toggle/switch
		}).on('gumby.trigger', function() {
			Gumby.debug('Trigger event triggered', scope.$el);
			scope.trigger(scope.triggered);
		// re-initialize module
		}).on('gumby.initialize', function() {
			Gumby.debug('Re-initializing '+scope.constructor, $el);
			scope.setup();
		});
	};

	// set up module based on attributes
	Toggle.prototype.setup = function() {
		this.targets = this.parseTargets();
		this.on = Gumby.selectAttr.apply(this.$el, ['on']) || Gumby.click;
		this.className = Gumby.selectAttr.apply(this.$el, ['classname']) || 'active';
		this.self = Gumby.selectAttr.apply(this.$el, ['self']) === 'false';
	};

	// parse data-for attribute, switches will inherit method
	Toggle.prototype.parseTargets = function() {
		var targetStr = Gumby.selectAttr.apply(this.$el, ['trigger']),
			secondaryTargets = 0,
			targets = [];

		// no targets so return false
		if(!targetStr) {
			return false;
		}

		secondaryTargets = targetStr.indexOf('|');

		// no secondary targets specified so return single target
		if(secondaryTargets === -1) {
			if(!this.checkTargets([targetStr])) {
				return false;
			}
			return [$(targetStr)];
		}

		// return array of both targets, split and return 0, 1
		targets = targetStr.split('|');
		if(!this.checkTargets(targets)) {
			return false;
		}
		return targets.length > 1 ? [$(targets[0]), $(targets[1])] : [$(targets[0])];
	};

	Toggle.prototype.checkTargets = function(targets) {
		var i = 0;

		for(i; i < targets.length; i++) {
			if(targets[i] && !$(targets[i]).length) {
				Gumby.error('Cannot find '+this.constructor.name+' target: '+targets[i]);
				return false;
			}
		}

		return true;
	};

	// call triggered event and pass target data
	Toggle.prototype.triggered = function() {
		// trigger gumby.onTrigger event and pass array of target status data
		Gumby.debug('Triggering onTrigger event', this.$el);
		this.$el.trigger('gumby.onTrigger', [this.$el.hasClass(this.className)]);
	};

	// Switch object inherits from Toggle
	Switch.prototype = new Toggle();
	Switch.prototype.constructor = Switch;

	// Toggle specific trigger method
	Toggle.prototype.trigger = function(cb) {

		Gumby.debug('Triggering Toggle', this.$el);

		var $target;

		// no targets just toggle active class on toggle
		if(!this.targets) {
			this.$el.toggleClass(this.className);

		// combine single target with toggle and toggle active class
		} else if(this.targets.length == 1) {
			this.$el.add(this.targets[0]).toggleClass(this.className);

		// if two targets check active state of first
		// always combine toggle and first target
		} else if(this.targets.length > 1) {
			if(this.targets[0].hasClass(this.className)) {
				$target = this.targets[0];
				
				// add this element to it unless gumby-self set
				if(!this.self) {
					$target = $target.add(this.$el);
				}

				$target.removeClass(this.className);
				this.targets[1].addClass(this.className);
			} else {
				$target = this.targets[0];
				
				// add this element to it unless gumby-self set
				if(!this.self) {
					$target = $target.add(this.$el);
				}

				$target.addClass(this.className);
				this.targets[1].removeClass(this.className);
			}
		}

		// call event handler here, applying scope of object Switch/Toggle
		if(cb && typeof cb === 'function') {
			cb.apply(this);
		}
	};

	// Switch specific trigger method
	Switch.prototype.trigger = function(cb) {

		Gumby.debug('Triggering Switch', this.$el);

		var $target;

		// no targets just add active class to switch
		if(!this.targets) {
			this.$el.addClass(this.className);

		// combine single target with switch and add active class
		} else if(this.targets.length == 1) {
			$target = this.targets[0];
				
			// add this element to it unless gumby-self set
			if(!this.self) {
				$target = $target.add(this.$el);
			}

			$target.addClass(this.className);

		// if two targets check active state of first
		// always combine switch and first target
		} else if(this.targets.length > 1) {
			$target = this.targets[0];
				
			// add this element to it unless gumby-self set
			if(!this.self) {
				$target = $target.add(this.$el);
			}

			$target.addClass(this.className);
			this.targets[1].removeClass(this.className);
		}

		// call event handler here, applying scope of object Switch/Toggle
		if(cb && typeof cb === 'function') {
			cb.apply(this);
		}
	};

	// add toggle initialisation
	Gumby.addInitalisation('toggles', function(all) {
		$('.toggle').each(function() {
			var $this = $(this);

			// this element has already been initialized
			// and we're only initializing new modules
			if($this.data('isToggle') && !all) {
				return true;

			// this element has already been initialized
			// and we need to reinitialize it
			} else if($this.data('isToggle') && all) {
				$this.trigger('gumby.initialize');
			}

			// mark element as initialized
			$this.data('isToggle', true);
			new Toggle($this);
		});
	});

	// add switches initialisation
	Gumby.addInitalisation('switches', function(all) {
		$('.switch').each(function() {
			var $this = $(this);

			// this element has already been initialized
			// and we're only initializing new modules
			if($this.data('isSwitch') && !all) {
				return true;

			// this element has already been initialized
			// and we need to reinitialize it
			} else if($this.data('isSwitch') && all) {
				$this.trigger('gumby.initialize');
				return true;
			}

			// mark element as initialized
			$this.data('isSwitch', true);
			new Switch($this);
		});
	});

	// register UI module
	Gumby.UIModule({
		module: 'toggleswitch',
		events: ['initialize', 'trigger', 'onTrigger'],
		init: function() {
			// Run initialize methods
			Gumby.initialize('switches');
			Gumby.initialize('toggles');
		}
	});
}(jQuery);
