text: import {
    Vector3,
    Vector4,
    Clock
  } from 'three'
  
  import Ui from './Ui'
  
  import Player from './Player'
  import KeyboardControls from './controls/KeyboardControls'
  import MobileDeviceControls from './controls/MobileDeviceControls'
  import ControlsManager from './controls/ControlsManager'
  
  import SimulationRenderer from './SimulationRenderer'
  import Teleporter from './Teleporter'
  
  class Simulation {
  
    init () {
      this.config = {
        wormhole: {
          position: new Vector3(10, 0.0, -32),
          radius: 0.8,
          gravityRatio: 0.25
        },
  
        blackhole: {
          position: new Vector3(0.0, -250.0, 250.0),
          radius: 12.5,
  
          // Ring definition - xyz is normal going through ring. Its magnitude determines inner radius.
          // w component determines outer radius
          disk: new Vector4(-12, 12, 6, 150.0),
          diskTexture: 'assets/accretion_disk.png'
        },
  
        saturn: {
          position: new Vector3(-14, 5, -40),
          radius: 8.0,
  
          // Ring definition - xyz is normal going through ring. Its magnitude determines inner radius.
          // w component determines outer radius
          rings: new Vector4(0, 9.22, 0, 17.1),
          texture: 'assets/saturn.jpg',
          ringsTexture: 'assets/saturnrings.png',
          lightDirection: (new Vector3(-4, 2, 3)).normalize()
        },
  
        planet: {
          position: new Vector3(7.6, -188.0, 200),
          radius: 0.08,
          diffuse: new Vector3(0.58, 0.85, 0.96),
          specular: new Vector3(0.1, 0.1, 0.1)
        },
  
        galaxy1: { texture: 'assets/galaxy1.png' },
        galaxy2: { texture: 'assets/galaxy2.png' }
      }
  
      this.teleportTargets = [
        { position: new Vector3(10, -307, 454), lookAt: this.config.blackhole.position, galaxy: 1 },
        { position: new Vector3(7.2, -188, 199.6), lookAt: this.config.planet.position, galaxy: 1 },
        { position: new Vector3(12.4, 3.3, -35.1), lookAt: this.config.wormhole.position, galaxy: 1 },
        { position: new Vector3(9.8, -4.6, -3.1), lookAt: this.config.wormhole.position, galaxy: 0 }
      ]
  
      this.initPlayer()
      this.initTeleporter()
      this.initRenderer()
      this.initControls()
    }
  
    initRenderer () {
      this.renderer = new SimulationRenderer(this.config, this.player)
      this.renderer.onTexturesLoaded = () => {
        Ui.removeLoadingScreen()
        this.inited = true
      }
  
      this.container = document.getElementById('container')
      this.container.appendChild(this.renderer.domElement)
  
      Ui.onPixelSizeChange = pixelSize => {
        this.renderer.setPixelSize(pixelSize)
      }
  
      window.addEventListener(
        'resize', e => {
          this.renderer.setSize(window.innerWidth, window.innerHeight)
        },
        false
      )
  
      let pixelSize = Ui.getSelectedPixelSize()
      if (!pixelSize) {
        pixelSize = this.getSuggestedPixelSize()
        Ui.setPixelSize(pixelSize)
      }
  
      this.renderer.setSize(window.innerWidth, window.innerHeight, pixelSize)
  
      window.addEventListener('wheel', e => {
        e.preventDefault()
  
        const delta = e.delta || (e.deltaX + e.deltaY + e.deltaZ)
        if (delta < 0) {
          this.renderer.setZoom(this.renderer.zoom * 1.06)
        }
        else {
          this.renderer.setZoom(this.renderer.zoom / 1.06)
        }
      }, false)
    }
  
    initPlayer () {
      this.player = new Player()
      this.player.lookAt(this.config.wormhole.position)
    }
  
    initControls () {
      // Add keyboard controls to the player
      this.keyboardControls = new KeyboardControls(this.player, this.container)
      this.keyboardControls.movementSpeed = 1
      this.keyboardControls.rollSpeed = Math.PI / 3
      this.keyboardControls.autoForward = false
      this.keyboardControls.dragToLook = false
  
      // Add mobile device controls (touch + accelerometer) to the player
      this.mobileDeviceControls = new MobileDeviceControls(this.player, this.container)
  
      this.controlsManager = new ControlsManager(this.keyboardControls, this.mobileDeviceControls)
      this.controlsManager.onChange = device => {
        if (device !== 'mobile') {
          return
        }
  
        // The player will probably not be looking with their device in the right direction, so fix that
        requestAnimationFrame(() => {
          this.player.object.quaternion.multiply(this.player.eyes.quaternion.clone().inverse())
        })
      }
  
      this.controlsManager.start()
  
      this.player.addController(this.keyboardControls)
      this.player.addController(this.mobileDeviceControls)
    }
  
    initTeleporter () {
      this.teleporter = new Teleporter(this.player)
      this.teleportTargets.forEach(target => {
        this.teleporter.addTarget(target)
      })
  
      Ui.onTeleportClick = () => {
        this.teleporter.teleportNext()
      }
  
      document.addEventListener('keydown', e => {
        if (e.keyCode === 84) {
          e.preventDefault()
  
          this.teleporter.teleportNext()
        }
      })
    }
  
    step () {
      if (this.inited) {
        this.update()
      }
  
      this.render()
    }
  
    start () {
      this.clock = new Clock()
  
      const animate = () => {
        requestAnimationFrame(animate)
  
        this.step()
      }
  
      animate()
    }
  
    update () {
      const delta = Math.max(0.001, this.clock.getDelta())
  
      this.player.update(delta)
    }
  
    render () {
      this.renderer.render()
    }
  
    getSuggestedPixelSize () {
      const pixelCount = window.innerWidth * window.innerHeight
      let pixelSize = 4
      while (pixelSize > 1) {
        if (pixelCount / (pixelSize * pixelSize) < 512 * 512) {
          pixelSize /= 2
        }
        else {
          break
        }
      }
      return pixelSize
    }
  
  }
  
  export default new Simulation()
  