     # Initialize shared variables
     dispatcher = params = routeOptions = null
 
-    # Unique ID counter for creating params objects
-    paramsId = 0
-
     # Fake route objects, walk like a route and swim like a route
 
     route1 = controller: 'test1', action: 'show'

    redirectToURLRoute = controller: 'test1', action: 'redirectToURL'
    redirectToControllerRoute = controller: 'test1', action: 'redirectToController'

    Test1Controller = null
    Test2Controller = null

    loadTest1ControllerAndExecute = null
    loadTest2ControllerAndExecute = null

    beforeEach ->
      dispatcher = new Dispatcher()

      # Define test controllers. The classes are redefined before each spec to
      # ensure a spec fiddling around with their prototype can't break other specs.

      Test1Controller = class Test1Controller extends Controller

        historyURL: (params) ->
          #console.debug 'Test1Controller#historyURL'
          'test1/' + if params.id? then params.id else ''

        initialize: (params, oldControllerName) ->
          #console.debug 'Test1Controller#initialize', params.id, oldControllerName
          super

        show: (params, oldControllerName) ->
          #console.debug 'Test1Controller#show', params, oldControllerName

        redirectToURL: (params, oldControllerName) ->
          @redirectTo '/test2/123'

        redirectToController: (params, oldControllerName) ->
          @redirectTo 'test2', 'show', params

        dispose: (params, newControllerName) ->
          #console.debug 'Test1Controller#dispose'
          super

      Test2Controller = class Test2Controller extends Controller

        historyURL: (params) ->
          #console.debug 'Test2Controller#historyURL'
          'test2/' + if params.id? then params.id else ''

        initialize: (params, oldControllerName) ->
          #console.debug 'Test2Controller#initialize', params, oldControllerName
          super

        show: (params, oldControllerName) ->
          #console.debug 'Test2Controller#show', params, oldControllerName

        dispose: (params, newControllerName) ->
          #console.debug 'Test2Controller#dispose'
          super

      # Define a test controller AMD modules
      test1Module = 'controllers/test1_controller'
      test2Module = 'controllers/test2_controller'
      define test1Module, -> Test1Controller
      define test2Module, -> Test2Controller

      # Helpers for asynchronous tests
      loadTest1ControllerAndExecute = (callback) -> require [test1Module], callback
      loadTest2ControllerAndExecute = (callback) -> require [test2Module], callback

    afterEach ->
      dispatcher.dispose()
      dispatcher = null


    # Reset helpers

    refreshParams = ->
      # Create a fresh params object which does not equal the previous one


    describe 'Before actions', ->

      route = controller: 'test_before_actions', action: 'show'

      class TestBeforeActionsController extends Controller

        historyURL: (params) ->
          'test_before_actions/' + (params.id or '')

        beforeAction:
          show: ->
          index: ->

        show: (params, oldControllerName) ->

        index: (params, oldControllerName) ->

      # Define a test controller AMD module
      testBeforeActionsModule = 'controllers/test_before_actions_controller'
      define testBeforeActionsModule, -> TestBeforeActionsController

      # Helpers for asynchronous tests
      loadBeforeActionsAndExecute = (callback) ->
        require [testBeforeActionsModule], callback

      it 'should not run executeAction directly if before actions are present', (done) ->
        executeAction = sinon.spy dispatcher, 'executeAction'
        # Replace executeBeforeActionChain with a no-op stub
        executeBeforeActionChain = sinon.stub dispatcher, 'executeBeforeActionChain'

        mediator.publish 'matchRoute', route, params, routeOptions

        loadBeforeActionsAndExecute ->
          expect(executeAction).was.notCalled()
          expect(executeBeforeActionChain).was.called()
          expect(executeBeforeActionChain.firstCall.args[0]).to.be.a(
            TestBeforeActionsController
          )

          executeAction.restore()
          executeBeforeActionChain.restore()

          done()

      it 'should call executeAction after with exactly the same arguments', (done) ->
        executeAction = sinon.spy dispatcher, 'executeAction'

        mediator.publish 'matchRoute', route, params, routeOptions

        loadBeforeActionsAndExecute ->
          args = executeAction.firstCall.args

          expect(args).to.have.length 5
          expect(args[0]).to.be.a TestBeforeActionsController
          expect(args[1]).to.be 'test_before_actions'
          expect(args[2]).to.be 'show'
          expect(args[3]).to.be.an 'object'
          expect(args[4]).to.be.an 'object'

          executeAction.restore()

          done()

      it 'should run all defined before actions when running an action', ->
        called = []

        class TestController extends Controller

          historyURL: (params) ->
            'test_before_actions/' + (params.id or '')

          beforeAction:
            show: -> called.push 'showBeforeAction'
            'show*': 'beforeShow'
            create: -> called.push 'createBeforeAction'

          show: ->

          create: ->

          beforeShow: ->
            called.push 'showWildcardBeforeAction'

        controller = new TestController()

        dispatcher.executeBeforeActionChain controller, 'test', 'show',
          params, routeOptions

        expect(called).to.have.length 2
        expect(called).to.contain 'showBeforeAction'
        expect(called).to.contain 'showWildcardBeforeAction'

        called = []

        dispatcher.executeBeforeActionChain controller, 'test', 'create',
          params, routeOptions

        expect(called).to.have.length 1
        expect(called).to.contain 'createBeforeAction'

      it 'should run all before actions of the whole prototype chain in correct order', ->

        class BaseController extends Controller

          historyURL: -> 'foo'

          beforeAction:
            '.*': 'loadSession'

          loadSession: ->
            userModel = isAdmin: -> true

        class AdminController extends BaseController

          beforeAction:
            '.*': 'checkAdminPrivileges'

          checkAdminPrivileges: (params, userModel) ->
            unless userModel.isAdmin()
              @redirectTo '500'

        class UserBanningController extends AdminController

          beforeAction:
            index: 'loadUsers'

          index: ->

          loadUsers: ->

        loadSession = sinon.spy BaseController.prototype, 'loadSession'
        checkAdminPrivileges = sinon.spy AdminController.prototype,
          'checkAdminPrivileges'
        loadUsers = sinon.spy UserBanningController.prototype, 'loadUsers'

        controller = new UserBanningController()
        dispatcher.executeBeforeActionChain controller, 'user_banning',
          'index', params, routeOptions

        expect(loadSession).was.called()
        expect(checkAdminPrivileges).was.called()
        expect(loadUsers).was.called()

        expect(loadSession).was.calledOn controller
        expect(checkAdminPrivileges).was.calledOn controller
        expect(loadUsers).was.calledOn controller

        expect(loadSession.calledBefore(checkAdminPrivileges)).to.be true
        expect(checkAdminPrivileges.calledBefore(loadUsers)).to.be true

      it 'should throw an error if a before action method isn’t a function or a string', ->

        class BrokenBeforeActionController extends Controller

          historyURL: -> 'foo'

          beforeAction:
            index: new Date()

          index: ->

        controller = new BrokenBeforeActionController()

        failFn = ->
          dispatcher.executeBeforeActionChain controller, 'broken_before_action',
            'index', params, routeOptions

        expect(failFn).to.throwError()

      it 'should handle sync. before actions then pass the params and the returned value', ->
        previousReturnValueToCheck = null

        class BeforeActionChainController extends Controller

          historyURL: -> 'foo'

          beforeAction:
            '.*': (params) ->
              params.bar = 'qux'
              # This return value should be passed to next before action in the chain
              'foo'
            show: (params, previousReturnValue) ->
              previousReturnValueToCheck = previousReturnValue

          show: ->

        controller = new BeforeActionChainController()
        dispatcher.executeBeforeActionChain controller,
          'before_action_chain', 'show', params, routeOptions
        expect(params.bar).to.be 'qux'

        # This is done here to ensure the method before actions are actually
        # run synchronous and not asynchronous.
        expect(previousReturnValueToCheck).to.be 'foo'

      it 'should handle async. before actions, then pass the returned value', ->
        deferred = $.Deferred()
        promise = deferred.promise()
        resolveArgument = foo: 'bar'

        class AsyncBeforeActionChainController extends Controller

          historyURL: -> 'foo'

          beforeAction:
            '.*': ->
              # Returning a promise here triggers asynchronous behavior.
              promise
            show: ->

          show: ->

        controller = new AsyncBeforeActionChainController()

        action = sinon.spy controller, 'show'
        beforeAction = sinon.spy controller.beforeAction, 'show'

        dispatcher.executeBeforeActionChain controller,
          'async_before_action_chain', 'show', params, routeOptions

        expect(beforeAction).was.notCalled()
        expect(action).was.notCalled()

        # Resolve the Deferred
        deferred.resolve resolveArgument

        expect(beforeAction).was.calledOnce()
        expect(beforeAction).was.calledWith params, resolveArgument

        expect(action).was.calledOnce()
