     # 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'


    describe 'Before actions', ->

      describe "General behavior", ->

        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 modules
        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'
          executeBeforeActionChain = sinon.mock(dispatcher).expects 'executeBeforeActionChain'

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

          loadBeforeActionsAndExecute ->
            expect(executeAction.called).to.not.be.ok()
            expect(executeBeforeActionChain.getCall(0).args[0]).to.be.a TestBeforeActionsController

            executeAction.restore()
            executeBeforeActionChain.verify()

            done()

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

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

          loadBeforeActionsAndExecute ->
            args = executeAction.getCall(0).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.verify()

            done()

      describe '#executeBeforeActionChain', ->

        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", ->
          BaseController = Controller.extend
            historyURL: -> 'foo'

            beforeAction:
              '.*': 'loadSession'

            loadSession: ->
              userModel = isAdmin: -> true

          AdminController = BaseController.extend
            beforeAction:
              '.*': 'checkAdminPrivileges'

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

          UserBanningController = AdminController.extend
            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.calledBefore(checkAdminPrivileges)).to.be.ok
          expect(checkAdminPrivileges.calledBefore(loadUsers)).to.be.ok

        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', ->
          previousBeforeActionReturnValueToCheck = null

          class BeforeActionChainController extends Controller

            historyURL: -> 'foo'

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

            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(previousBeforeActionReturnValueToCheck).to.equal 'foo'


        it 'should handle async. before actions, then pass the returned value', ->
          promise =
            done: (callback) ->
              @callback = -> callback 'response'
            then: ->
            resolve: -> @callback()

          class AsyncBeforeActionChainController extends Controller
            historyURL: -> 'foo'
            beforeAction:
              '.*': (params) ->
                # Returning a promise here triggers asynchronous behavior.
                promise
              'show': (params, previousBeforeActionReturnValue) ->
                previousBeforeActionReturnValueToCheck = previousBeforeActionReturnValue

            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.callCount).to.be 0
          expect(action.callCount).to.be 0

          # Force promise to be resolved...

          promise.resolve()

          expect(beforeAction.calledWith(sinon.match.object, "response")).to.be.ok()

          expect(beforeAction.calledOnce).to.be.ok()
          expect(action.calledOnce).to.be.ok()


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

    # Define test controllers

    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

    # Create a fresh Dispatcher instance for each test

    beforeEach ->
      dispatcher = new Dispatcher()

    afterEach ->
      dispatcher.dispose()
      dispatcher = null

    # Reset helpers

    # Unique ID counter for creating params objects
    paramsId = 0

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