/*  Map 3D
*   3D Model : Matthias Onestras
*   Code : Ronan Bonnet
*
*/
var rep = "assets/map/";

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.119.1/build/three.module.js';

import {
  OrbitControls
} from 'https://cdn.jsdelivr.net/npm/three@0.119.1/examples/jsm/controls/OrbitControls.js';
import {
  GLTFLoader
} from 'https://cdn.jsdelivr.net/npm/three@0.119.1/examples/jsm/loaders/GLTFLoader.js';

var container, stats, controls;
var camera, scene, renderer;

var raycaster, mouse;

init();
render();

var height, width;

/**
 * Initializes the 3D plan
 * Creates and loads every needed things
 */
function init() {


  // 
  // Creates HTML 
  //
  container = document.createElement('div');
  container.id = 'map3d';

  height = document.querySelector('#maps').clientHeight;
  width = document.querySelector('#maps').clientWidth;
  var svg = document.querySelector('#maps #map');
  document.querySelector('#maps').insertBefore(container, svg);


  //
  //  Creates cameras and scene
  //
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.75, 20000);
  camera.position.set(500,1500,500); 
  scene = new THREE.Scene();

  //
  // LIGHTS
  //
  let sol = new THREE.AmbientLight(0x404040, 1.0);
  scene.add(sol);

  var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
  hemiLight.position.set( 0, 20, 0 );
  scene.add( hemiLight );

  var dirLight = new THREE.DirectionalLight( 0xffffff );
  dirLight.position.set( - 3, 10, - 10 );
  scene.add( dirLight );

  //scene.background = new THREE.Color( 0xff0000 );


  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2()

  //
  // Loading screen
  //
  const loadingManager = new THREE.LoadingManager( () => {
    const loadingScreen = document.getElementById('loading-screen');
    loadingScreen.classList.add('fade-out');
    loadingScreen.addEventListener('transitionend', onTransitionEnd);
  });


  //
  // Load the 3D model
  //
  var loader = new GLTFLoader(loadingManager);

  loader.load(rep+'map3D.glb', function(gltf) {
    var object = gltf.scene;				
    gltf.scene.scale.set( 2, 2, 2 );			   
    gltf.scene.position.x = 0;				    //Position (x = right+ left-) 
    gltf.scene.position.y = 0;				    //Position (y = up+, down-)
    gltf.scene.position.z = 0;	

    scene.add(gltf.scene);
    
    render();

  });



  //
  // RENDERER
  //
  renderer = new THREE.WebGLRenderer({
    antialias: true,
  });
  renderer.setClearColor( 0x000000 );

  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(width, window.innerHeight * 0.75);
  renderer.toneMapping = THREE.ACESFilmicToneMapping;
  renderer.toneMappingExposure = 1;
  renderer.outputEncoding = THREE.sRGBEncoding;
  container.appendChild(renderer.domElement);

  var pmremGenerator = new THREE.PMREMGenerator(renderer);
  pmremGenerator.compileEquirectangularShader();

  //
  // CONTROLS
  //
  controls = new OrbitControls(camera, renderer.domElement);
  controls.addEventListener('change', render); // use if there is no animation loop
  controls.minDistance = 0;
  controls.maxDistance = 3500;
  controls.enablePan = true; 
  controls.target.set(-110, 300, 0);
  controls.maxPolarAngle = Math.PI/2.05;
  controls.update();

  //
  // Load Light
  //
  var ambientLight = new THREE.AmbientLight( 0xcccccc );
  scene.add( ambientLight );
        
  var directionalLight = new THREE.DirectionalLight( 0xffffff );
  directionalLight.position.set( 0, 1, 1 ).normalize();
  scene.add( directionalLight );	


  //
  // EVENTS
  //
  window.addEventListener('resize', onWindowResize, false);  

  renderer.domElement.addEventListener('click', onClick, false);        // Mouse
  //renderer.domElement.addEventListener('mousemove', onMouseOver,false);
  renderer.domElement.addEventListener('touchend', onTouchEnd, false);  // Smartphone

}

/**
 * Get all the selectors (buildings identifiers)
 * @returns Array with all the selectors
 */
function getSelectors() {
  let info = {};
  let object = {
    "function": 'get_map_selectors',
    'info': info,
  }
  return $.ajax({
      url: rep+'ajax.php',
      data: object,
      method: 'get',
      success: function(data){
        
      }
  });
}

/*
 * Show a screen page if the building on which was clicked is in the database
 * Display the name of the building and the description of the building
 */
function handleClickOnBuilding(x,y) {

  mouse.x = x;
  mouse.y = y;

  raycaster.setFromCamera(mouse, camera);

  var intersects = raycaster.intersectObjects(scene.children, true);


  // If we clicked on a building
  if (intersects.length > 0) {

    var selector = intersects[0].object.name.toString().toLowerCase(); // Name of the building we clicked on

    // Wait for getSelectors() to be done
    // If we do not wait, everything will be executed before checking what is inside the database
    $.when(getSelectors().done(function(data) {
      if (data.map(x => x.selector).includes(selector)){
        // Use the same thing as the one for the 2D map
        $.alert({
          title: 'Chargement...',
          content: function () {
              let self = this;
              let object = {
                  "function": 'get_map_info',
                  'selector': selector,
              };
              return $.ajax({
                  url: rep+'ajax.php',
                  data: object,
                  method: 'get'
              }).done(function (data) {
                  if (data.length > 0) {
                      self.setTitle(data[0]['title']);
                      self.setContent(data[0]['description']);
                  } else {
                      self.setTitle('Erreur');
                      self.setContent('Une erreur est survenue')
                      return;
                  }
              }).fail(function(){
                  self.setContent('Something went wrong.');
              });
          },
        }); 
      } else {

      }
    }));

  }
}

/**
 * Get the position where the user clicked (mouse) on a building and process it
 */
function onClick() {

  event.preventDefault();

  height = document.querySelector('#maps').clientHeight;
  width = document.querySelector('#maps').clientWidth;


  const rect = renderer.domElement.getBoundingClientRect();
  mouse.x = ( ( event.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
  mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;
  handleClickOnBuilding(mouse.x, mouse.y);
 
}

/**
 * Get the position where the user clicked (smartphone) on a building and process it
 */
function onTouchEnd() {
  var clientX, clientY;

  clientX = event.changedTouches[0].clientX;
  clientY = event.changedTouches[0].clientY;

  const rect = renderer.domElement.getBoundingClientRect();
  mouse.x = ( ( clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
  mouse.y = - ( ( clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;

  handleClickOnBuilding(mouse.x, mouse.y);
}


/**
 * Process something when the user moved the mouse over a building
 * @todo add text over the building
 */
function onMouseOver() {

  event.preventDefault();

  height = document.querySelector('#maps').clientHeight;
  width = document.querySelector('#maps').clientWidth;


  const rect = renderer.domElement.getBoundingClientRect();
  mouse.x = ( ( event.clientX - rect.left ) / ( rect.right - rect.left ) ) * 2 - 1;
  mouse.y = - ( ( event.clientY - rect.top ) / ( rect.bottom - rect.top) ) * 2 + 1;

  createTextOverBuilding(mouse.x,mouse.y)

}

function createTextOverBuilding(x,y) {
  mouse.x = x;
  mouse.y = y;

  raycaster.setFromCamera(mouse, camera);

  var intersects = raycaster.intersectObjects(scene.children, true);


  // If we clicked on a building
  if (intersects.length > 0) {
    console.log(intersects);



  }

  
}

function makeLabelCanvas(baseWidth, size, name) {
  const borderSize = 2;
  const ctx = document.createElement('canvas').getContext('2d');
  const font =  `${size}px bold sans-serif`;
  ctx.font = font;
  // measure how long the name will be
  const textWidth = ctx.measureText(name).width;

  const doubleBorderSize = borderSize * 2;
  const width = baseWidth + doubleBorderSize;
  const height = size + doubleBorderSize;
  ctx.canvas.width = width;
  ctx.canvas.height = height;

  // need to set font again after resizing canvas
  ctx.font = font;
  ctx.textBaseline = 'middle';
  ctx.textAlign = 'center';

  ctx.fillStyle = 'blue';
  ctx.fillRect(0, 0, width, height);

  // scale to fit but don't stretch
  const scaleFactor = Math.min(1, baseWidth / textWidth);
  ctx.translate(width / 2, height / 2);
  ctx.scale(scaleFactor, 1);
  ctx.fillStyle = 'white';
  ctx.fillText(name, 0, 0);


  const labelBaseScale = 0.01;
  const label = new THREE.Sprite(labelMaterial);
  scene.add(label);
  label.position.y = head.position.y + headRadius + size * labelBaseScale;

  label.scale.x = canvas.width  * labelBaseScale;
  label.scale.y = canvas.height * labelBaseScale;
  return ctx.canvas;
}


/**
 * Auto-resizes the canvas when window size is updated
 */
function onWindowResize() {

  height = document.querySelector('#main-content .inner').clientHeight;
  width = document.querySelector('#main-content .inner').clientWidth;
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(width * 0.9, window.innerHeight * 0.75); // 0.9 and 0.75 so it looks comfortable on the screen
  
  render();

}

/**
 * Render the scene
 */
function render() {

  renderer.render(scene, camera);
}

/*
 * Remove the loader when the model loaded
 */
function onTransitionEnd( event) {
  event.target.remove();
}