
import co           from 'co'
import { resolve }  from 'url'
import screenfull   from 'screenfull'
import React        from 'react'

// TODO: remove this dependency and use Options
import query                  from 'bemuse/utils/query'
import { getGrade }           from 'bemuse/rules/grade'

import SCENE_MANAGER          from 'bemuse/scene-manager'
import URLResource            from 'bemuse/resources/url'
import BemusePackageResources from 'bemuse/resources/bemuse-package'
import * as GameLoader        from 'bemuse/game/loaders/game-loader'
import GameScene              from 'bemuse/game/game-scene'
import LoadingScene           from 'bemuse/game/ui/LoadingScene.jsx'
import ResultScene            from './ui/ResultScene'
import * as Analytics         from './analytics'
import * as OptionsActions    from './actions/options-actions'
import OptionsStore           from './stores/options-store'
import OptionsInputStore      from './stores/options-input-store'
import { MISSED }             from 'bemuse/game/judgments'
import { unmuteAudio }        from 'bemuse/sampling-master'

import { shouldDisableFullScreen, isTitleDisplayMode } from 'bemuse/devtools/query-flags'

export function launch ({ server, song, chart }) {

  // Unmute audio immediately so that it sounds on iOS.
  unmuteAudio()

  return co(function*() {

    // go fullscreen
    if (screenfull.enabled && !shouldDisableFullScreen()) {
      let safari = /Safari/.test(navigator.userAgent) &&
                  !/Chrom/.test(navigator.userAgent)
      if (!safari) screenfull.request()
    }

    // get the options from the store
    let optionsStoreState = OptionsStore.get()
    let options = optionsStoreState.options

    // initialize the loading specification
    let loadSpec  = { }
    if (song.resources) {
      loadSpec.assets = song.resources
      loadSpec.bms    = yield song.resources.file(chart.file)
    } else {
      let url         = server.url + '/' + song.path + '/' + encodeURIComponent(chart.file)
      let assetsUrl   = resolve(url, 'assets/')
      loadSpec.bms    = new URLResource(url)
      loadSpec.assets = new BemusePackageResources(assetsUrl, {
        fallback: url,
        fallbackPattern: /\.(?:png|jpg)/,
      })
    }

    let latency = +query.latency || (+options['system.offset.audio-input'] / 1000) || 0
    let volume = getVolume(song)

    loadSpec.options = {
      audioInputLatency: latency,
      soundVolume: volume,
      tutorial: song.tutorial,
      players: [
        {
          speed:      +options['player.P1.speed'] || 1,
          autoplay:   false,
          placement:  options['player.P1.panel'],
          scratch:    optionsStoreState.scratch,
          input: {
            keyboard: OptionsInputStore.get().keyCodes,
          },
        },
      ],
    }

    // start loading the game
    let loader = GameLoader.load(loadSpec)
    let { tasks, promise } = loader

    // display loading scene
    let loadingScene = React.createElement(LoadingScene, {
      tasks: tasks,
      song: chart.info,
      eyecatchImagePromise: loader.get('EyecatchImage')
    })
    yield SCENE_MANAGER.push(loadingScene)

    // if in title display mode, stop
    if (isTitleDisplayMode()) return

    // send data to analytics
    Analytics.gameStart(song, chart, optionsStoreState.scratch ? 'BM' : 'KB')

    // wait for game to load and display the game
    let controller = yield promise
    yield SCENE_MANAGER.display(new GameScene(controller.display))
    controller.start()

    // wait for final game state
    let state = yield controller.promise

    // send data to analytics
    Analytics.gameFinish(song, chart, state)

    // get player's state and save options
    let playerState = state.player(state.game.players[0])
    OptionsActions.setOptions({
      'player.P1.speed': playerState.speed,
    })

    // display evaluation
    if (state.finished) {
      Analytics.action('Game:finish')
      yield showResult(playerState, chart)
    } else {
      Analytics.action('Game:escape')
    }
    controller.destroy()

    // go back to previous scene
    yield SCENE_MANAGER.pop()

  })
}

function showResult (playerState, chart) {
  return new Promise(_resolve => {
    let stats     = playerState.stats
    let playMode  = playerState.player.options.scratch === 'off' ? 'KB' : 'BM'
    let props = {
      result: {
        '1':          stats.counts['1'],
        '2':          stats.counts['2'],
        '3':          stats.counts['3'],
        '4':          stats.counts['4'],
        'missed':     stats.counts[MISSED],
        'score':      stats.score,
        'maxCombo':   stats.maxCombo,
        'accuracy':   stats.accuracy,
        'totalCombo': stats.totalCombo,
        'log':        stats.log,
        'deltas':     stats.deltas,
        'grade':      getGrade(stats),
      },
      chart:    chart,
      playMode: playMode,
      onExit:   _resolve,
    }
    SCENE_MANAGER.display(React.createElement(ResultScene, props)).done()
  })
}

function getVolume (song) {
  if (typeof song.replaygain !== 'string') return null
  if (!/^\S+\s+dB$/.test(song.replaygain)) return null
  const gain = parseFloat(song.replaygain)
  if (isNaN(gain)) return null
  return Math.pow(10, (gain + 8) / 20)
}

@@ -5003,26 +5003,267 @@
 %0A%7D%0A%0A
-function getVolume
+// http://qiita.com/dtinth/items/1200681c517a3fb26357%0Aconst DEFAULT_REPLAYGAIN = -12.2 // dB%0A%0Afunction getVolume (song) %7B%0A  const gain = replayGainFor(song)%0A  return Math.pow(10, ((gain == null ? DEFAULT_REPLAYGAIN : gain) + 8) / 20)%0A%7D%0A%0Afunction replayGainFor
  (so
@@ -5465,36 +5465,11 @@
 urn 
-Math.pow(10, (gain + 8) / 20)
+gain
 %0A%7D%0A

use default replaygain = -12.2 dB