/*jslint node: true, nomen: true, unparam: true */
/*global jquery, $, _, define, Marionette, jqm, window */

'use strict';
define([ 'backbone', 'marionette', 'jquery', 'underscore' ],
	function (Backbone, Marionette, $, _) {
		var _utils = {},
		/* http://open.bekk.no/mixins-in-backbone
		 * Kim Joar Bekkelund */
			extendMethod = function (to, from, methodName) {
				if (!_.isUndefined(from[methodName])) {
					var old = to[methodName];

					// create a new function on to
					// wherein we first call the method which exists on `to`
					// then call the method on `from`,
					// returning what the method on 'to' returns
					to[methodName] = function () {
						var oldReturn = old.apply(this, arguments);

						from[methodName].apply(this, arguments);

						return oldReturn;
					};
				}
			};

		/* http://lostechies.com/derickbailey/2012/10/07/javascript-mixins-beyond-simple-object-extension/
		 * Derick Bailey */

		// build a mixin function to take a target that receives the mixin,
		// a source that is the mixin, and a list of methods / attributes to
		// copy over to the target

		_utils.mixinToView = function (target, source, methodNames) {

			// ignore the actual args list and build from arguments so we can
			// be sure to get all of the method names
			var deepDefault = [],
				args = Array.prototype.slice.apply(arguments);

			target = args.shift();
			source = args.shift();
			methodNames = args;

			// add methods and events which exist on 'source' but not 'target' over to 'target'

			//special cases to deepDefault
			deepDefault = ['attributes', 'regions', 'events', 'modelEvents', 'collectionEvents' ];
			_.each(deepDefault, function (property) {
				if (typeof target[property] !== 'undefined' || typeof source[property] !== 'undefined') {
					_.defaults(target[property], source[property]);
				}
			});
			if (typeof target.className !== 'undefined' || typeof source.className !== 'undefined') {
				target.className = source.className + target.className;
			}

			_.defaults(target, source);

			_.each(methodNames, function (methodName) {
				extendMethod(target, source, methodName);
			});

			return target;
		};

		return _utils;
	});