'use strict';

var _three = require('three');

var t = _interopRequireWildcard(_three);

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

var Vector2 = t.Vector2,
    PerspectiveCamera = t.PerspectiveCamera,
    Vector3 = t.Vector3,
    OrthographicCamera = t.OrthographicCamera,
    Scene = t.Scene,
    SphereGeometry = t.SphereGeometry,
    Mesh = t.Mesh,
    MeshBasicMaterial = t.MeshBasicMaterial,
    Raycaster = t.Raycaster,
    ImageUtils = t.ImageUtils,
    WebGLRenderer = t.WebGLRenderer,
    Texture = t.Texture,
    SpriteMaterial = t.SpriteMaterial,
    Sprite = t.Sprite,
    TextureLoader = t.TextureLoader,
    tMath = t.Math;


var _camera, _scene, _renderer;
var _cameraOrtho, _sceneOrtho;
var _fov = 75;
var _pRadius = 1000;
var _raycaster;
var _container;
var _isUserInteracting = false;
var _lon = 0,
    _lat = 0;
var _onPointerDownLon = 0,
    _onPointerDownLat = 0;
var _onPointerDownPointerX = 0,
    _onPointerDownPointerY = 0;
var _mouse = new Vector2();
var _clickableObjects = [];
var _sprites = [];
var _lables = [];

var options = {
  container: 'panoramaConianer', //容器
  url: 'resources/img/panorama/pano-7.jpg', //全景图路径
  lables: [], //标记   {position:{lon:114,lat:38},logoUrl:'lableLogo.png',text:'我是一个标记'}
  widthSegments: 60, //水平切段数
  heightSegments: 40, //垂直切段数(值小粗糙速度快,值大精细速度慢)
  pRadius: 1000, //全景球的半径,推荐使用默认值
  minFocalLength: 1, //镜头最小拉近距离
  maxFocalLength: 100, //镜头最大拉近距离
  sprite: 'label', // label,icon
  onClick: function onClick() {}
};

function tpanorama(opt) {
  this.render(opt);
}

tpanorama.prototype = {
  constructor: undefined,
  def: {},
  render: function render(opt) {
    var _this = this;

    this.def = extend(options, opt, true);
    document.getElementById(this.def.container).innerHTML = '';
    _lables = [];
    initContainer(this.def.container);
    initCamera();
    initRaycaster();
    makePanorama(this.def.pRadius, this.def.widthSegments, this.def.heightSegments, this.def.url);
    initRenderer();
    initLable(this.def.lables, this.def.sprite);
    _container.addEventListener('mousedown', onDocumentMouseDown, false);
    _container.addEventListener('mousemove', onDocumentMouseMove, false);
    _container.addEventListener('mouseup', onDocumentMouseUp, false);
    _container.addEventListener('mousewheel', function (e) {
      onDocumentMouseWheel(e, _this.def.minFocalLength, _this.def.maxFocalLength);
    }, false);
    _container.addEventListener('DOMMouseScroll', function (e) {
      onDocumentMouseWheel(e, _this.def.minFocalLength, _this.def.maxFocalLength);
    }, false);
    _container.addEventListener('click', onDocumentMouseClick.bind(this), false);
    global.addEventListener('resize', onWindowResize, false);
    animate();
  }
};

function extend(o, n, override) {
  for (var key in n) {
    if (n.hasOwnProperty(key) && (!o.hasOwnProperty(key) || override)) {
      o[key] = n[key];
    }
  }
  return o;
}

function initContainer(c) {
  _container = document.getElementById(c);
}

function initCamera() {
  _camera = new PerspectiveCamera(_fov, window.innerWidth / window.innerHeight, 1, 1100);
  _camera.target = new Vector3(0, 0, 0);
  _cameraOrtho = new OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 1, 10);
  _cameraOrtho.position.z = 10;
  _scene = new Scene();
  _sceneOrtho = new Scene();
}

function initRaycaster() {
  _raycaster = new Raycaster();
}

function makePanorama(pRadius, widthSegments, heightSegments, u) {
  var mesh = new Mesh(new SphereGeometry(pRadius, widthSegments, heightSegments), new MeshBasicMaterial({ map: ImageUtils.loadTexture(u) }));
  mesh.scale.x = -1;
  _scene.add(mesh);
}

function initRenderer() {
  _renderer = new WebGLRenderer();
  _renderer.setSize(window.innerWidth, window.innerHeight);
  _renderer.autoClear = false;
  _container.appendChild(_renderer.domElement);
}

function onDocumentMouseDown(event) {
  event.preventDefault();
  _isUserInteracting = true;
  _onPointerDownPointerX = event.clientX;
  _onPointerDownPointerY = event.clientY;
  _onPointerDownLon = _lon;
  _onPointerDownLat = _lat;
}

function onDocumentMouseMove(event) {
  if (_isUserInteracting) {
    _lon = (_onPointerDownPointerX - event.clientX) * 0.1 + _onPointerDownLon;
    _lat = (event.clientY - _onPointerDownPointerY) * 0.1 + _onPointerDownLat;
  }
}

function onDocumentMouseUp() {
  _isUserInteracting = false;
}

function onDocumentMouseClick(event) {
  _mouse.x = event.clientX / window.innerWidth * 2 - 1;
  _mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
  _raycaster.setFromCamera(_mouse, _cameraOrtho);
  var intersects = _raycaster.intersectObjects(_clickableObjects);
  intersects.forEach(this.def.onClick);
}

function onDocumentMouseWheel(ev, minFocalLength, maxFocalLength) {
  var ev = ev || window.event;
  var down = true;
  var m = _camera.getFocalLength();
  down = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0;
  if (down) {
    if (m > minFocalLength) {
      m -= m * 0.05;
      _camera.setFocalLength(m);
    }
  } else {
    if (m < maxFocalLength) {
      m += m * 0.05;
      _camera.setFocalLength(m);
    }
  }
  if (ev.preventDefault) {
    ev.preventDefault();
  }
  return false;
}

function onWindowResize() {
  _camera.aspect = window.innerWidth / window.innerHeight;
  _camera.projectionMatrix.makePerspective(_fov, _camera.aspect, 1, 1100);
  _camera.updateProjectionMatrix();
  _cameraOrtho.left = -window.innerWidth / 2;
  _cameraOrtho.right = window.innerWidth / 2;
  _cameraOrtho.top = window.innerHeight / 2;
  _cameraOrtho.bottom = -window.innerHeight / 2;
  _cameraOrtho.updateProjectionMatrix();
  _renderer.setSize(window.innerWidth, window.innerHeight);
}

function initLable(lables, sprite) {
  if (sprite == 'label') {
    for (var i = 0; i < lables.length; i++) {
      _lables.push(createLableSprite(_sceneOrtho, lables[i].text, lables[i].position));
    }
  } else if (sprite == 'icon') {
    for (var i = 0; i < lables.length; i++) {
      _sprites.push(createSprite(lables[i].position, lables[i].logoUrl, lables[i].text));
    }
  }
}

function createLableSprite(scene, name, position) {
  var canvas1 = document.createElement('canvas');
  var context1 = canvas1.getContext('2d');
  var metrics = context1.measureText(name);
  var width = metrics.width * 1.5;
  context1.font = "10px 宋体";
  context1.fillStyle = "rgba(0,0,0,0.95)";
  context1.fillRect(0, 0, width + 8, 20 + 8);
  context1.fillStyle = "rgba(0,0,0,0.2)";
  context1.fillRect(2, 2, width + 4, 20 + 4);
  context1.fillStyle = "rgba(255,255,255,0.95)";
  context1.fillText(name, 4, 20);
  var texture1 = new Texture(canvas1);
  texture1.needsUpdate = true;
  var spriteMaterial = new SpriteMaterial({ map: texture1 });
  var sprite1 = new Sprite(spriteMaterial);
  sprite1.scale.set(1.0, 1.0, 1.0);
  sprite1.position.set(0, 0, 0);
  sprite1.name = name;
  var lable = {
    name: name,
    pos: position,
    canvas: canvas1,
    context: context1,
    texture: texture1,
    sprite: sprite1
  };
  _sceneOrtho.add(lable.sprite);
  _clickableObjects.push(lable.sprite);
  return lable;
}

function createSprite(position, url, name) {
  var textureLoader = new TextureLoader();
  var ballMaterial = new SpriteMaterial({
    map: textureLoader.load(url)
  });
  var sp1 = {
    pos: position,
    name: name,
    sprite: new Sprite(ballMaterial)
  };
  sp1.sprite.scale.set(32, 32, 1.0);
  sp1.sprite.position.set(0, 0, 0);
  sp1.sprite.name = name;
  _sceneOrtho.add(sp1.sprite);
  _clickableObjects.push(sp1.sprite);
  return sp1;
}

function animate() {
  requestAnimationFrame(animate);
  render();
}

function render() {
  calPosition();
  addSprites();
  runRender();
}

function calPosition() {
  _lat = Math.max(-85, Math.min(85, _lat));
  var phi = tMath.degToRad(90 - _lat);
  var theta = tMath.degToRad(_lon);
  _camera.target.x = _pRadius * Math.sin(phi) * Math.cos(theta);
  _camera.target.y = _pRadius * Math.cos(phi);
  _camera.target.z = _pRadius * Math.sin(phi) * Math.sin(theta);
  _camera.lookAt(_camera.target);
}

function addSprites() {
  if (typeof _sprites != "undefined") {
    for (var i = 0; i < _sprites.length; i++) {
      var wp = geoPosition2World(_sprites[i].pos.lon, _sprites[i].pos.lat);
      var sp = worldPostion2Screen(wp, _camera);
      var test = wp.clone();
      test.project(_camera);
      if (test.x > -1 && test.x < 1 && test.y > -1 && test.y < 1 && test.z > -1 && test.z < 1) {
        _sprites[i].sprite.scale.set(32, 32, 32);
        _sprites[i].sprite.position.set(sp.x, sp.y, 1);
      } else {
        _sprites[i].sprite.scale.set(1.0, 1.0, 1.0);
        _sprites[i].sprite.position.set(0, 0, 0);
      }
    }
  }
  if (typeof _lables != "undefined") {
    for (var i = 0; i < _lables.length; i++) {
      var wp = geoPosition2World(_lables[i].pos.lon, _lables[i].pos.lat);
      var sp = worldPostion2Screen(wp, _camera);
      var test = wp.clone();
      test.project(_camera);
      if (test.x > -1 && test.x < 1 && test.y > -1 && test.y < 1 && test.z > -1 && test.z < 1) {
        var metrics = _lables[i].context.measureText(_lables[i].name);
        var width = metrics.width * 3.5;
        _lables[i].sprite.scale.set(400, 150, 1.0);
        _lables[i].sprite.position.set(sp.x + width, sp.y - 40, 1);
      } else {
        _lables[i].sprite.scale.set(1.0, 1.0, 1.0);
        _lables[i].sprite.position.set(0, 0, 0);
      }
    }
  }
}

function geoPosition2World(lon, lat) {
  lat = Math.max(-85, Math.min(85, lat));
  var phi = tMath.degToRad(90 - lat);
  var theta = tMath.degToRad(lon);

  var result = {
    x: _pRadius * Math.sin(phi) * Math.cos(theta),
    y: _pRadius * Math.cos(phi),
    z: _pRadius * Math.sin(phi) * Math.sin(theta)
  };
  return new Vector3(result.x, result.y, result.z);
}

function worldPostion2Screen(world_vector, camera) {
  var vector = world_vector.clone();
  vector.project(camera);
  var result = {
    x: Math.round((vector.x + 1) * window.innerWidth / 2 - window.innerWidth / 2),
    y: Math.round(window.innerHeight / 2 - (-vector.y + 1) * window.innerHeight / 2),
    z: 0
  };
  return new Vector3(result.x, result.y, result.z);
}

function runRender() {
  _renderer.render(_scene, _camera);
  _renderer.render(_sceneOrtho, _cameraOrtho);
}

module.exports = tpanorama;