'use strict'
_ = require 'underscore'
Backbone = require 'backbone'
mediator = require 'chaplin/mediator'
utils = require 'chaplin/lib/utils'
EventBroker = require 'chaplin/lib/event_broker'
module.exports = class Dispatcher'use strict'
_ = require 'underscore'
Backbone = require 'backbone'
mediator = require 'chaplin/mediator'
utils = require 'chaplin/lib/utils'
EventBroker = require 'chaplin/lib/event_broker'
module.exports = class DispatcherBorrow the static extend method from Backbone.
  @extend = Backbone.Model.extendMixin an EventBroker.
  _.extend @prototype, EventBrokerThe previous route information. This object contains the controller name, action, path, and name (if any).
  previousRoute: nullThe current controller, route information, and parameters. The current route object contains the same information as previous.
  currentController: null
  currentRoute: null
  currentParams: null
  currentQuery: null
  constructor: ->
    @initialize arguments...
  initialize: (options = {}) ->Merge the options.
    @settings = _.defaults options,
      controllerPath: 'controllers/'
      controllerSuffix: '_controller'Listen to global events.
    @subscribeEvent 'router:match', @dispatchThe standard flow is:
  dispatch: (route, params, options) ->Clone params and options so the original objects remain untouched.
    params = if params then _.extend {}, params else {}
    options = if options then _.extend {}, options else {}null or undefined query parameters are equivalent to an empty hash
    options.query = {} if not options.query?Whether to force the controller startup even if current and new controllers and params match Default to false unless explicitly set to true.
    options.forceStartup = false unless options.forceStartup is trueStop if the desired controller/action is already active with the same params.
    return if not options.forceStartup and
      @currentRoute?.controller is route.controller and
      @currentRoute?.action is route.action and
      _.isEqual(@currentParams, params) and
      _.isEqual(@currentQuery, options.query)Fetch the new controller, then go on.
    @loadController route.controller, (Controller) =>
      @controllerLoaded route, params, options, ControllerLoad the constructor for a given controller name. The default implementation uses require() from a AMD module loader like RequireJS to fetch the constructor.
  loadController: (name, handler) ->
    fileName = name + @settings.controllerSuffix
    moduleName = @settings.controllerPath + fileName
    if define?.amd
      require [moduleName], handler
    else
      setTimeout =>
        handler require moduleName
      , 0Handler for the controller lazy-loading.
  controllerLoaded: (route, params, options, Controller) ->
    if @nextPreviousRoute = @currentRoute
      previous = _.extend {}, @nextPreviousRoute
      previous.params = @currentParams if @currentParams?
      delete previous.previous if previous.previous
      prev = {previous}
    @nextCurrentRoute = _.extend {}, route, prev
    controller = new Controller params, @nextCurrentRoute, options
    @executeBeforeAction controller, @nextCurrentRoute, params, optionsExecutes controller action.
  executeAction: (controller, route, params, options) ->Dispose the previous controller.
    if @currentControllerNotify the rest of the world beforehand.
      @publishEvent 'beforeControllerDispose', @currentControllerPassing new parameters that the action method will receive.
      @currentController.dispose params, route, optionsSave the new controller and its parameters.
    @currentController = controller
    @currentParams = params
    @currentQuery = options.queryCall the controller action with params and options.
    controller[route.action] params, route, optionsStop if the action triggered a redirect.
    return if controller.redirectedWe're done! Spread the word!
    @publishEvent 'dispatcher:dispatch', @currentController,
      params, route, optionsExecutes before action filterer.
  executeBeforeAction: (controller, route, params, options) ->
    before = controller.beforeAction
    executeAction = =>
      if controller.redirected or @currentRoute and route is @currentRoute
        @nextPreviousRoute = @nextCurrentRoute = null
        controller.dispose()
        return
      @previousRoute = @nextPreviousRoute
      @currentRoute = @nextCurrentRoute
      @nextPreviousRoute = @nextCurrentRoute = null
      @executeAction controller, route, params, options
    unless before
      executeAction()
      returnThrow deprecation warning.
    if typeof before isnt 'function'
      throw new TypeError 'Controller#beforeAction: function expected. ' +
        'Old object-like form is not supported.'Execute action in controller context.
    promise = controller.beforeAction params, route, options
    if promise and promise.then
      promise.then executeAction
    else
      executeAction()  disposed: false
  dispose: ->
    return if @disposed
    @unsubscribeAllEvents()
    @disposed = trueYou’re frozen when your heart’s not open.
    Object.freeze? this