/*

	Ractive-decorators-helpers
	==========================

	Version 0.1.1.

	Currently two helper methods:
		- .create() for simple decorators that need no teardown and
						use the same function for initial load and update.
		- .combine() for combining decorators. Ractive currently only allows
						one dectorator per element. This function creates a
						decorator that allows the use of multiple decorators

	==========================

	Troubleshooting: If you're using a module system in your app (AMD or
	something more nodey) then you may need to change the paths below,
	where it says `require( 'ractive' )` or `define([ 'ractive' ]...)`.

	==========================

	Usage: Include this file on your page below Ractive, e.g:

		<script src='lib/ractive.js'></script>
		<script src='lib/ractive-decorators-helpers.js'></script>

	Or, if you're using a module loader, require this module:

		// requiring the plugin will 'activate' it - no need to use
		// the return value
		require( 'ractive-decorators-helpers' );

	see http://martypdx.github.io/Ractive-decorator-helpers/ for demo and examples

*/

(function ( global, factory ) {

	'use strict';

	// Common JS (i.e. browserify) environment
	if ( typeof module !== 'undefined' && module.exports && typeof require === 'function' ) {
		factory( require( 'Ractive' ) );
	}

	// AMD?
	else if ( typeof define === 'function' && define.amd ) {
		define([ 'Ractive' ], factory );
	}

	// browser global
	else if ( global.Ractive ) {
		factory( global.Ractive );
	}

	else {
		throw new Error( 'Could not find Ractive! It must be loaded before the Ractive-decorators-helpers plugin' );
	}

}( typeof window !== 'undefined' ? window : this, function ( Ractive ) {

	'use strict';

	Ractive.decorators.create = function(fn){
	   return function(node){
			var args = Array.prototype.slice.call(arguments, 1, arguments.length)

			//note: fn.bind(node) fails in grunt:qunit :(

			fn.apply(node, args)

			function _fn(){
				fn.apply(node, arguments)
			}

			return {
				teardown: function(){},
				update: _fn
			}
		}
	}

	if(!Array.isArray) {
	  Array.isArray = function (vArg) {
		var isArray;

		isArray = vArg instanceof Array;

		return isArray;
	  };
	}

	Ractive.decorators.combine = function(wrapped){

		return function(node, toCall){
			var decorators = [],
				ractive = this

			wrapped.forEach( function(d){
				var callArgs, name = Object.keys(d)[0];

				if( !(callArgs = toCall[name]) ) { return; }

				var	fn = d[name],
					args = callArgs ? [node].concat(callArgs) : [node],
					result = fn.apply(ractive, args)


				if ( !result || !result.teardown ) {
					throw new Error( 'Decorator definition "' + name + '" must return an object with a teardown method' );
				}


				result._name = name
				decorators.push(result)

			})

			return {
				teardown: function(){
					decorators.forEach(function(d){
						d.teardown()
					})
				},
				update: function(toUpdate){
					decorators.forEach(function(d){
						var values = toUpdate[d._name]
						if(!Array.isArray(values)) { values = [values]}
						d.update.apply(node, values)
					})
				}
			};
		};
	};

}));