<commit_before>View = require 'views/kinds/RootView'
template = require 'templates/play/level'
{me} = require('lib/auth')
ThangType = require 'models/ThangType'
utils = require 'lib/utils'

# temp hard coded data
World = require 'lib/world/world'

# tools
Surface = require 'lib/surface/Surface'
God = require 'lib/God'
GoalManager = require 'lib/world/GoalManager'
ScriptManager = require 'lib/scripts/ScriptManager'
LevelBus = require('lib/LevelBus')
LevelLoader = require 'lib/LevelLoader'
LevelSession = require 'models/LevelSession'
Level = require 'models/Level'
LevelComponent = require 'models/LevelComponent'
Article = require 'models/Article'
Camera = require 'lib/surface/Camera'
AudioPlayer = require 'lib/AudioPlayer'

# subviews
LoadingView = require './level/level_loading_view'
TomeView = require './level/tome/tome_view'
ChatView = require './level/level_chat_view'
HUDView = require './level/hud_view'
ControlBarView = require './level/control_bar_view'
PlaybackView = require './level/playback_view'
GoalsView = require './level/goals_view'
GoldView = require './level/gold_view'
VictoryModal = require './level/modal/victory_modal'
InfiniteLoopModal = require './level/modal/infinite_loop_modal'

PROFILE_ME = false

module.exports = class PlayLevelView extends View
  id: 'level-view'
  template: template
  cache: false
  shortcutsEnabled: true
  startsLoading: true
  isEditorPreview: false

  subscriptions:
    'level-set-volume': (e) -> createjs.Sound.setVolume(e.volume)
    'level-show-victory': 'onShowVictory'
    'restart-level': 'onRestartLevel'
    'level-highlight-dom': 'onHighlightDom'
    'end-level-highlight-dom': 'onEndHighlight'
    'level-focus-dom': 'onFocusDom'
    'level-disable-controls': 'onDisableControls'
    'level-enable-controls': 'onEnableControls'
    'god:new-world-created': 'onNewWorld'
    'god:infinite-loop': 'onInfiniteLoop'
    'level-reload-from-data': 'onLevelReloadFromData'
    'play-next-level': 'onPlayNextLevel'
    'edit-wizard-settings': 'showWizardSettingsModal'
    'surface:world-set-up': 'onSurfaceSetUpNewWorld'
    'level:session-will-save': 'onSessionWillSave'
    'level:set-team': 'setTeam'
    'god:new-world-created': 'loadSoundsForWorld'
    'level:started': 'onLevelStarted'
    'level:loading-view-unveiled': 'onLoadingViewUnveiled'

  events:
    'click #level-done-button': 'onDonePressed'

  shortcuts:
    'ctrl+s': 'onCtrlS'

  constructor: (options, @levelID) ->
    console.profile?() if PROFILE_ME
    super options
    if not me.get('hourOfCode') and @getQueryVariable "hour_of_code"
      me.set 'hourOfCode', true
      me.save()
      $('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
      window.tracker?.trackEvent 'Hour of Code Begin', {}

    @isEditorPreview = @getQueryVariable 'dev'
    @sessionID = @getQueryVariable 'session'

    $(window).on('resize', @onWindowResize)
    @supermodel.once 'error', @onLevelLoadError
    @saveScreenshot = _.throttle @saveScreenshot, 30000

    if @isEditorPreview
      f = =>
        @supermodel.shouldSaveBackups = (model) ->
          model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem']
        @load() unless @levelLoader
      setTimeout f, 100
    else
      @load()

  onLevelLoadError: (e) =>
    application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}

  setLevel: (@level, @supermodel) ->
    @god?.level = @level.serialize @supermodel
    if @world
      serializedLevel = @level.serialize(@supermodel)
      @world.loadFromLevel serializedLevel, false
    else
      @load()

  load: ->
    @levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
    @levelLoader.once 'loaded-all', @onLevelLoaderLoaded, @
    @levelLoader.on 'progress', @onLevelLoaderProgressChanged, @
    @god = new God()

  getRenderData: ->
    c = super()
    c.world = @world
    if me.get('hourOfCode') and me.lang() is 'en-US'
      # Show the Hour of Code footer explanation until it's been more than a day
      elapsed = (new Date() - new Date(me.get('dateCreated')))
      c.explainHourOfCode = elapsed < 86400 * 1000
    c

  afterRender: ->
    window.onPlayLevelViewLoaded? @  # still a hack
    @insertSubView @loadingView = new LoadingView {}
    @$el.find('#level-done-button').hide()
    super()

  onLevelLoaderProgressChanged: ->
    return if @seenDocs
    return unless @levelLoader.session.loaded and @levelLoader.level.loaded
    return unless showFrequency = @levelLoader.level.get('showsGuide')
    session = @levelLoader.session
    diff = new Date().getTime() - new Date(session.get('created')).getTime()
    return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
    articles = @levelLoader.supermodel.getModels Article
    for article in articles
      return unless article.loaded
    @showGuide()

  showGuide: ->
    @seenDocs = true
    DocsModal = require './level/modal/docs_modal'
    options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
    @openModalView(new DocsModal(options), true)
    Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
    return true

  onLevelLoaderLoaded: ->
    return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
    if window.currentModal and not window.currentModal.destroyed
      @loadingView.showReady()
      return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @

    # Save latest level played in local storage
    localStorage["lastLevel"] = @levelID if localStorage?
    @grabLevelLoaderData()
    team = @getQueryVariable("team") ? @world.teamForPlayer(0)
    @loadOpponentTeam(team)
    @god.level = @level.serialize @supermodel
    @god.worldClassMap = @world.classMap
    @setTeam team
    @initSurface()
    @initGoalManager()
    @initScriptManager()
    @insertSubviews ladderGame: @otherSession?
    @initVolume()
    @session.on 'change:multiplayer', @onMultiplayerChanged, @
    @originalSessionState = _.cloneDeep(@session.get('state'))
    @register()
    @controlBar.setBus(@bus)
    @surface.showLevel()
    if @otherSession<commit_msg>Fixed control bar leaderboard button for #429<commit_after>View = require 'views/kinds/RootView'
template = require 'templates/play/level'
{me} = require('lib/auth')
ThangType = require 'models/ThangType'
utils = require 'lib/utils'

# temp hard coded data
World = require 'lib/world/world'

# tools
Surface = require 'lib/surface/Surface'
God = require 'lib/God'
GoalManager = require 'lib/world/GoalManager'
ScriptManager = require 'lib/scripts/ScriptManager'
LevelBus = require('lib/LevelBus')
LevelLoader = require 'lib/LevelLoader'
LevelSession = require 'models/LevelSession'
Level = require 'models/Level'
LevelComponent = require 'models/LevelComponent'
Article = require 'models/Article'
Camera = require 'lib/surface/Camera'
AudioPlayer = require 'lib/AudioPlayer'

# subviews
LoadingView = require './level/level_loading_view'
TomeView = require './level/tome/tome_view'
ChatView = require './level/level_chat_view'
HUDView = require './level/hud_view'
ControlBarView = require './level/control_bar_view'
PlaybackView = require './level/playback_view'
GoalsView = require './level/goals_view'
GoldView = require './level/gold_view'
VictoryModal = require './level/modal/victory_modal'
InfiniteLoopModal = require './level/modal/infinite_loop_modal'

PROFILE_ME = false

module.exports = class PlayLevelView extends View
  id: 'level-view'
  template: template
  cache: false
  shortcutsEnabled: true
  startsLoading: true
  isEditorPreview: false

  subscriptions:
    'level-set-volume': (e) -> createjs.Sound.setVolume(e.volume)
    'level-show-victory': 'onShowVictory'
    'restart-level': 'onRestartLevel'
    'level-highlight-dom': 'onHighlightDom'
    'end-level-highlight-dom': 'onEndHighlight'
    'level-focus-dom': 'onFocusDom'
    'level-disable-controls': 'onDisableControls'
    'level-enable-controls': 'onEnableControls'
    'god:new-world-created': 'onNewWorld'
    'god:infinite-loop': 'onInfiniteLoop'
    'level-reload-from-data': 'onLevelReloadFromData'
    'play-next-level': 'onPlayNextLevel'
    'edit-wizard-settings': 'showWizardSettingsModal'
    'surface:world-set-up': 'onSurfaceSetUpNewWorld'
    'level:session-will-save': 'onSessionWillSave'
    'level:set-team': 'setTeam'
    'god:new-world-created': 'loadSoundsForWorld'
    'level:started': 'onLevelStarted'
    'level:loading-view-unveiled': 'onLoadingViewUnveiled'

  events:
    'click #level-done-button': 'onDonePressed'

  shortcuts:
    'ctrl+s': 'onCtrlS'

  constructor: (options, @levelID) ->
    console.profile?() if PROFILE_ME
    super options
    if not me.get('hourOfCode') and @getQueryVariable "hour_of_code"
      me.set 'hourOfCode', true
      me.save()
      $('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
      window.tracker?.trackEvent 'Hour of Code Begin', {}

    @isEditorPreview = @getQueryVariable 'dev'
    @sessionID = @getQueryVariable 'session'

    $(window).on('resize', @onWindowResize)
    @supermodel.once 'error', @onLevelLoadError
    @saveScreenshot = _.throttle @saveScreenshot, 30000

    if @isEditorPreview
      f = =>
        @supermodel.shouldSaveBackups = (model) ->
          model.constructor.className in ['Level', 'LevelComponent', 'LevelSystem']
        @load() unless @levelLoader
      setTimeout f, 100
    else
      @load()

  onLevelLoadError: (e) =>
    application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}

  setLevel: (@level, @supermodel) ->
    @god?.level = @level.serialize @supermodel
    if @world
      serializedLevel = @level.serialize(@supermodel)
      @world.loadFromLevel serializedLevel, false
    else
      @load()

  load: ->
    @levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
    @levelLoader.once 'loaded-all', @onLevelLoaderLoaded, @
    @levelLoader.on 'progress', @onLevelLoaderProgressChanged, @
    @god = new God()

  getRenderData: ->
    c = super()
    c.world = @world
    if me.get('hourOfCode') and me.lang() is 'en-US'
      # Show the Hour of Code footer explanation until it's been more than a day
      elapsed = (new Date() - new Date(me.get('dateCreated')))
      c.explainHourOfCode = elapsed < 86400 * 1000
    c

  afterRender: ->
    window.onPlayLevelViewLoaded? @  # still a hack
    @insertSubView @loadingView = new LoadingView {}
    @$el.find('#level-done-button').hide()
    super()

  onLevelLoaderProgressChanged: ->
    return if @seenDocs
    return unless @levelLoader.session.loaded and @levelLoader.level.loaded
    return unless showFrequency = @levelLoader.level.get('showsGuide')
    session = @levelLoader.session
    diff = new Date().getTime() - new Date(session.get('created')).getTime()
    return if showFrequency is 'first-time' and diff > (5 * 60 * 1000)
    articles = @levelLoader.supermodel.getModels Article
    for article in articles
      return unless article.loaded
    @showGuide()

  showGuide: ->
    @seenDocs = true
    DocsModal = require './level/modal/docs_modal'
    options = {docs: @levelLoader.level.get('documentation'), supermodel: @supermodel}
    @openModalView(new DocsModal(options), true)
    Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @
    return true

  onLevelLoaderLoaded: ->
    return unless @levelLoader.progress() is 1 # double check, since closing the guide may trigger this early
    if window.currentModal and not window.currentModal.destroyed
      @loadingView.showReady()
      return Backbone.Mediator.subscribeOnce 'modal-closed', @onLevelLoaderLoaded, @

    # Save latest level played in local storage
    localStorage["lastLevel"] = @levelID if localStorage?
    @grabLevelLoaderData()
    team = @getQueryVariable("team") ? @world.teamForPlayer(0)
    @loadOpponentTeam(team)
    @god.level = @level.serialize @supermodel
    @god.worldClassMap = @world.classMap
    @setTeam team
    @initSurface()
    @initGoalManager()
    @initScriptManager()
    @insertSubviews ladderGame: (@level.get('type') is "ladder")
    @initVolume()
    @session.on 'change:multiplayer', @onMultiplayerChanged, @
    @originalSessionState = _.cloneDeep(@session.get('state'))
    @register()
    @controlBar.setBus(@bus)
    @surface.showLevel()
    if @otherSession
{'fraction_non_alphanumeric': 0.130479344055503, 'fraction_numerical': 0.004336171554714601, 'mean_word_length': 4.152315190901706, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4100337', 'n_tokens_mistral': 4035, 'n_tokens_neox': 3904, 'n_words': 867}