text: /*
   * Copyright 2017-2020 The ShadowEditor Authors. All rights reserved.
   *
   * Use of this source code is governed by a MIT-style
   * license that can be found in the LICENSE file.
   * 
   * For more information, please visit: https://github.com/tengge1/ShadowEditor
   * You can also visit: https://gitee.com/tengge1/ShadowEditor
   */
  import {dispatch} from '../third_party';
  
  import EventList from './EventList';
  import PackageManager from '../package/PackageManager';
  import PlayerLoader from './component/PlayerLoader';
  import PlayerEvent from './component/PlayerEvent';
  import PlayerControl from './component/PlayerControl';
  import PlayerAudio from './component/PlayerAudio';
  import PlayerRenderer from './component/PlayerRenderer';
  import PlayerAnimation from './component/PlayerAnimation';
  import PlayerPhysics from './component/PlayerPhysics';
  import PlayerLoadMask from './component/PlayerLoadMask';
  import WebVR from './component/WebVR';
  import CssUtils from '../utils/CssUtils';
  import global from '../global';
  
  /**
   * 播放器
   * @author mrdoob / http://mrdoob.com/
   * @author tengge / https://github.com/tengge1
   * @param {HTMLElement} container 容器
   * @param {Object} options 配置信息
   * @param {String} options.server 服务器信息，例如：http://localhost:2000
   * @param {Boolean} options.enableThrowBall 是否允许扔小球进行物理测试
   * @param {Boolean} options.showStats 是否显示性能控件
   */
  class Player {
      constructor(container = document.body, options = {}) {
          this.container = container;
          this.options = options;
  
          this.options.server = this.options.server || window.origin;
          this.options.enablePhysics = false; // 这个配置在场景里
          this.options.enableThrowBall = false;
          this.options.showStats = this.options.showStats || false;
  
          // 在播放器中
          if (!global.app) {
              global.app = this;
          }
  
          this.dispatch = dispatch.apply(dispatch, EventList);
          this.call = this.dispatch.call.bind(this.dispatch);
          this.on = this.dispatch.on.bind(this.dispatch);
  
          // 性能控件
          if (this.options.showStats) {
              this.stats = new Stats();
              Object.assign(this.stats.dom.style, {
                  position: 'absolute',
                  left: '8px',
                  top: '8px',
                  zIndex: 'initial'
              });
  
              container.appendChild(this.stats.dom);
          }
  
          window.addEventListener('resize', this.onResize.bind(this));
  
          var observer = new MutationObserver(this.onResize.bind(this));
  
          observer.observe(this.container, {
              attributes: true,
              characterData: false,
              childList: false
          });
  
          this.scene = null;
          this.camera = null;
          this.renderer = null;
  
          this.gis = null;
  
          this.package = new PackageManager();
          this.require = this.package.require.bind(this.package);
  
          this.loader = new PlayerLoader(this);
          this.event = new PlayerEvent(this);
          this.control = new PlayerControl(this);
          this.audio = new PlayerAudio(this);
          this.playerRenderer = new PlayerRenderer(this);
          this.animation = new PlayerAnimation(this);
          this.physics = new PlayerPhysics(this);
          this.webvr = new WebVR(this);
          this.mask = new PlayerLoadMask(this);
  
          this.isPlaying = false;
          this.clock = new THREE.Clock(false);
  
          // 保证播放器在不加载语言包的情况下正常运行
          if (!window._t) {
              window._t = function (data) {
                  return data;
              };
          }
      }
  
      /**
       * 启动播放器
       * @param {String} sceneData 场景数据
       */
      start(sceneData) {
          if (typeof sceneData !== 'string') {
              global.app.toast(_t('Scene data of string type is needed.'));
              return;
          }
  
          var jsons;
  
          try {
              jsons = JSON.parse(sceneData);
          } catch (e) {
              global.app.toast(_t('Cannot deserialize scene data.'), 'error');
              return;
          }
  
          if (this.isPlaying) {
              return;
          }
          this.isPlaying = true;
  
          this.container.style.display = 'block';
  
          this.mask.show();
  
          this.loader.create(jsons, {
              domWidth: this.container.clientWidth,
              domHeight: this.container.clientHeight
          }).then(obj => {
              this.initPlayer(obj);
  
              this.dispatch.call('init', this);
  
              var promise1 = this.event.create(this.scene, this.camera, this.renderer, obj.scripts);
              var promise2 = this.control.create(this.scene, this.camera, this.renderer);
              var promise3 = this.audio.create(this.scene, this.camera, this.renderer);
              var promise4 = this.playerRenderer.create(this.scene, this.camera, this.renderer);
              var promise5 = this.animation.create(this.scene, this.camera, this.renderer, obj.animations);
              var promise6 = this.physics.create(this.scene, this.camera, this.renderer);
              var promise7 = this.webvr.create(this.scene, this.camera, this.renderer);
  
              Promise.all([promise1, promise2, promise3, promise4, promise5, promise6, promise7]).then(() => {
                  this.mask.hide();
                  this.event.init();
                  this.clock.start();
                  this.event.start();
                  this.renderer.setAnimationLoop(this.animate.bind(this));
              });
          });
      }
  
      /**
       * 停止播放器
       */
      stop() {
          if (!this.isPlaying) {
              return;
          }
          this.isPlaying = false;
          this.renderer.setAnimationLoop(null);
  
          this.event.stop();
  
          this.loader.dispose();
          this.event.dispose();
          this.control.dispose();
          this.audio.dispose();
          this.animation.dispose();
          this.physics.dispose();
          this.webvr.dispose();
  
          // if (this.gis) {
          //     this.gis.dispose();
          //     this.gis = null;
          // }
  
          this.playerRenderer.dispose();
  
          this.container.removeChild(this.renderer.domElement);
          this.container.style.display = 'none';
  
          this.scene.children.length = 0;
  
          this.scene = null;
          this.camera = null;
          this.renderer = null;
  
          this.clock.stop();
      }
  
      /**
       * 初始化播放器
       * @param {*} obj 场景数据
       */
      initPlayer(obj) {
          var container = this.container;
  
          // options
          this.options.enablePhysics = obj.options.enablePhysics;
          this.options.enableVR = obj.options.enableVR;
          this.options.vrSetting = obj.options.vrSetting;
  
          // camera
          this.camera = obj.camera;
  
          if (!this.camera) {
              console.warn(`Player: Three is no camera in the scene.`);
              this.camera = new THREE.PerspectiveCamera(
                  50,
                  container.clientWidth / container.clientHeight,
                  0.1,
                  1000
              );
          }
  
          // renderer
          this.renderer = obj.renderer || new THREE.WebGLRenderer({
              antialias: true
          });
  
          this.renderer.setSize(container.clientWidth, container.clientHeight);
          container.appendChild(this.renderer.domElement);
  
          this.camera.aspect = this.renderer.domElement.width / this.renderer.domElement.height;
          this.camera.updateProjectionMatrix();
  
          var listener = obj.audioListener || new THREE.AudioListener();
          this.camera.add(listener);
  
          this.renderer.domElement.style.filter = CssUtils.serializeFilter(obj.options);
  
          // scene
          this.scene = obj.scene || new THREE.Scene();
      }
  
      animate() {
          if (!this.isPlaying) {
              return;
          }
  
          if (this.stats) {
              this.stats.begin();
          }
  
          this.clock._getDelta(); // see: ../polyfills.js
  
          var deltaTime = this.clock.getDelta();
  
          this.event.update(this.clock, deltaTime);
          this.control.update(this.clock, deltaTime);
          this.playerRenderer.update(this.clock, deltaTime);
          this.animation.update(this.clock, deltaTime);
          this.physics.update(this.clock, deltaTime);
          this.webvr.update(this.clock, deltaTime);
  
          // if (this.gis) {
          //     this.gis.update();
          // }
  
          if (this.stats) {
              this.stats.end();
          }
      }
  
      resize() {
          if (!this.camera || !this.renderer) {
              return;
          }
  
          var width = this.container.clientWidth;
          var height = this.container.clientHeight;
  
          var camera = this.camera;
          var renderer = this.renderer;
  
          camera.aspect = width / height;
          camera.updateProjectionMatrix();
  
          renderer.domElement;
          renderer.setSize(width, height);
      }
  
      onResize() {
          this.resize();
      }
  }
  
  export default Player;