(function() { 'use strict'; angular.module('shared') .factory('advise', ['$injector', '_', '$advice', function($injector, _, $advice) { return function applyAdvice(originalFn, middlewares, locals) { if( !_.isFunction(originalFn) ) { throw new Error('Can only apply advice to a function') } locals = locals || {}; middlewares = _.isArray(middlewares) ? middlewares : [middlewares]; middlewares = _.map(middlewares, function(middleware) { return $advice(middleware, locals); }); return function advisedFn() { var initialArgs = Array.prototype.slice.call(arguments); var self = this; var initialContext = { invocationTarget: self, invokedFunction: originalFn, arguments: initialArgs }; var index = 0; function next(context) { if(index >= middlewares.length) { var finalArgs = context.arguments || initialArgs; return originalFn.apply(self, finalArgs); } else { return middlewares[index++].call(self, context, next); } } return next(initialContext); } }; }]) })();