import './index.css';
import { Bulle } from './Bulle.js';
import { Trajectoire } from './Trajectoire.js';
import { Angle } from './Angle.js';

const THREE = require("three");
const OrbitControls = require('three-orbit-controls')(THREE)
const divCanvas = document.getElementById('container');

const divAngle = document.getElementById('angle');
const divDist = document.getElementById('disctance');

const fileHTML = document.getElementById('inputRessources');

var ANGLE = 20;
var DISTANCE = 60;


var width = 900;
var height = 800;

var ficher;

var camera, scene, renderer, controls;
var geometry, material, mesh;

var listBulle = [];
var listeTajectoire = [];
var listeTajectoireFinale = [];

function purge(){
  listeTajectoireFinale = [];
  listeTajectoire = [];
  listBulle = [];
}

init();
animate();

function init() {

    scene = new THREE.Scene();

    //angle, aspectRatio, near, far
    camera = new THREE.PerspectiveCamera(70, width / height, 0.001, 10000); //TODO à ajuster
    controls = new OrbitControls( camera );

    controls.enableKeys = true;

    controls.keys = {
      LEFT: 37, //left arrow
      UP: 38, // up arrow
      RIGHT: 39, // right arrow
      BOTTOM: 40 // down arrow
    }

    controls.update();
    //x, y, z //TODO à changer
    camera.position.set(0, 0, 100);


    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( width, height );
    renderer.domElement.id = "canvas";
    divCanvas.appendChild( renderer.domElement );

}

fileHTML.onchange = function(event){
  event.preventDefault();
  event.stopPropagation();

  ficher = fileHTML.files[0];

  var reader = new FileReader();

  reader.onload = function(e) {
    let text = reader.result.toString();

    ANGLE = divAngle.value;
    DISTANCE = divDist.value;

    purge();
    creerBulle(text);
  }

  reader.readAsText(ficher);
}


//Bubule

function creerBulle(texte){
  let lignes = texte.split("\n");

  let id=1;

  //Lecture et création des bulles
  lignes.forEach(function(ligne){
    let number = ligne.split(" ");
    if(number.length > 2){
      listBulle.push(new Bulle(id,number[0],number[1],number[2]));
      id++;
    }
  });

  //TODO récupéré seulemnt les bulles autour?
  listBulle.forEach(function(bulle){
    let traj = new Trajectoire();
    traj.add(bulle);
    backtracking(traj);
  });

  trie();
  elagage();
  //listeTajectoireFinale=listeTajectoire;

  //TODO tmp colorisation
  listeTajectoireFinale.forEach(function(t){

    let o = Math.round, ra = Math.random, s = 255;
    let r = o(ra()*s);
    let g = o(ra()*s);
    let b = o(ra()*s);

    t.setRGB(r,g,b);
  });

  console.log("Fini");

  //TODO Affichage
  listBulle.forEach(function(bulle){
    scene.add( bulle.affichage(10) );
  });

  listeTajectoireFinale.forEach(function(bulle){
    bulle.affichage(scene);
  });
  
  //TODO mettre listeTajectoireFinale dans un fichier
}


function trie(){
  listeTajectoire.sort(function(t1,t2){
    return t2.score - t1.score;
  });
}



function elagage(){
  console.log("Elagage");
  var listB = listBulle.slice();


  listeTajectoire.forEach(function(t){

    var valid = true;
    var tmp = [];

    console.log(t);

    t.list.forEach(function(b){

      tmp.push(b);

      //Si encore valide et la bulle n'est pas utilisé
			if(valid && inArray(listB,b)){ //TODO bug dans l'original les supprime mais les rajoute pas si la tajectoire n'est pas bonne ?
        let index = listB.indexOf(b);
				listB.splice(index,1);
			}
			else {


        /*if(valid){
          tmp.forEach(function(b){
            listB.push(b);
          });
        }*/

        		valid = false;
			}

    });

    console.log(valid);

    if(valid){
      listeTajectoireFinale.push(t);
    }

  });
}

function inArray(list,b2){
  let ret = false;
  list.forEach(function(b1){
    if(b1.id === b2.id) {
      ret = true;
    }
  });
  return ret;
}

function score(t) {

  let list = t.list;
  let s = 0.0;

  //Angle
  for(let i = 0; i < 2; i++) {
  	s += Math.abs( Angle.degre3B(list[i], list[i+1], list[i+2]) - Angle.degre3B(list[i+1], list[i+2], list[i+3]) );
  }

  //Distance
  for(let i = 0; i < 3; i++) {
  	s += Math.abs( list[i].distanceXYZ(list[i+1]) - list[i+1].distanceXYZ(list[i+2]) );
  }

  return s;
}

//Si la distanc est correct
function isCorrectDistance(b1,b2,dist){
  if(b1.id !== b2.id){
    let tmp = b1.distanceXYZ(b2);

    if(tmp >= 0 && tmp <= dist) return true;
  }

  return false;
}


function backtracking(trajectoire){

  var b1 = trajectoire.last;

  listBulle.forEach(function(b2){

    let isCorrect = false;

    //Debut Test
    if(!trajectoire.contains(b2)){
      let tmpDist;
      let tmpAng;

      //Cas du décalage entre la bulle 3 et la bulle 4
      if(trajectoire.size !== 3){
            tmpDist = DISTANCE;
            tmpAng = ANGLE;
        }else{
            tmpDist = DISTANCE*2;
            tmpAng = ANGLE * 2;
        }

        //Si la distance est correct
        if(isCorrectDistance(b1,b2,tmpDist)){

          if(trajectoire.size > 1) { //TODO c'est pas 3 points pour avoir un angle?

            let listA = trajectoire.list;
            let listB = trajectoire.list;

            let bulleA = listA[trajectoire.size-2];
            let bulleB = listB[trajectoire.size-1];

            if(Angle.angleB(bulleA, bulleB, b2, tmpAng)) {
                isCorrect = true;
            }

          }else{
            isCorrect = true;
          }
        }
    }
    //Fin Test

    if(isCorrect){
      trajectoire.add(b2);

      //Fin de la Trajectoire
      if(trajectoire.size > 4){
      
        //TODO Calcul du score?
        let s = score(trajectoire);
        trajectoire.score = s;

        //let copy = clone(trajectoire); //Marche pas car copy les bulle aussi

        let copy = new Trajectoire();
        copy.score = s;
        copy.list = trajectoire.list;

        /*console.log(copy.size); //DEBUG
        console.log(copy);*/

        listeTajectoire.push(copy);

        trajectoire.removeLast();
      }else{
        backtracking(trajectoire);
      }
    }

  });

}

//Fin Bubule
function animate() {

    requestAnimationFrame( animate );

    controls.update();
    renderer.render( scene, camera );

}

//Axe de DEBUG

var debugaxis = function(axisLength){
    //Shorten the vertex function
    function v(x,y,z){
            return new THREE.Vector3(x,y,z);
    }

    //Create axis (point1, point2, colour)
    function createAxis(p1, p2, color){
        var line, lineGeometry = new THREE.Geometry(),
        lineMat = new THREE.LineBasicMaterial({color: color});
        lineGeometry.vertices.push(p1, p2);
        line = new THREE.Line(lineGeometry, lineMat);
        scene.add(line);
    }

    createAxis(v(-axisLength, 0, 0), v(axisLength, 0, 0), 0xFF0000);
    createAxis(v(0, -axisLength, 0), v(0, axisLength, 0), 0x00FF00);
    createAxis(v(0, 0, -axisLength), v(0, 0, axisLength), 0x0000FF);
};

debugaxis(10000); //TODO à déplacer

function clone(originalObject){
    if((typeof originalObject !== 'object') || originalObject === null){
        throw new TypeError("originalObject parameter must be an object which is not null");
    }

    var deepCopy = JSON.parse(JSON.stringify(originalObject));

    // Une petite récursivité
    function deepProto(originalObject, deepCopy){
        deepCopy.__proto__ = Object.create(originalObject.constructor.prototype);
        for(var attribute in originalObject){
            if(typeof originalObject[attribute] === 'object' && originalObject[attribute] !== null){
                deepProto(originalObject[attribute], deepCopy[attribute]);
            }
        }
    }
    deepProto(originalObject, deepCopy);

    return deepCopy;
}
