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');

var divAngle = document.getElementById('angle');
var divDist = document.getElementById('distance');

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

var ANGLE = 20;//divAngle.value;
var DISTANCE = 60;//divDist.value;

var width = 900;
var height = 800;

var fichier;
var fileName = "";

var camera, scene, renderer, controls;

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

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

    while (scene.children.length > 0) {
        scene.remove(scene.children[0]);
    }
    debugaxis(10000);
}

init();
animate();

//création du canvas
function init() {

    scene = new THREE.Scene();

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

    camera = new THREE.PerspectiveCamera(70, width / height, 0.001, 10000); //TODO à ajuster
    controls = new OrbitControls(camera, document.getElementById("canvas"));

    controls.enableKeys = true;

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

    controls.update();
    camera.position.set(1924.0807427353375, 38.371457214044085, -144.6795262926123);
}

//sur chargement du fichier
fileHTML.onchange = function (event) {
    event.preventDefault();
    event.stopPropagation();

    fichier = fileHTML.files[0];

    fileName = fileHTML.value.split("\\")[2];

    var reader = new FileReader();

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

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

        purge();
        creerBulle(text);
    };

    reader.readAsText(fichier);
};


//Bubulle ----------------------------------------------------------------

//création d'une bulle par ligne
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++;
        }
    });

    //pour chaque bulle, on calcule les trajectoires correctes
    listBulle.forEach(function (bulle) {
        let traj = new Trajectoire();
        traj.add(bulle);
        backtracking(traj);
    });

    //recuperation des meilleures trajectoires
    trie();
    elagage();

    //coloration des trajectoires
    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);
    });

    //affichage des bulles
    listBulle.forEach(function (bulle) {
        scene.add(bulle.affichage(10));
    });

    //affichage des trajectoires
    listeTajectoireFinale.forEach(function (bulle) {
        bulle.affichage(scene);
    });

    //TODO mettre listeTajectoireFinale dans un fichier
    TrajectoireTofichier();
}

//trie les trajectoires par score, les meilleures trajectoires seront au debut
function TrajectoireTofichier() {

    var txt = ""

    listeTajectoireFinale.forEach(function (bulle) {
        txt += bulle.toString() + "\n";
    });

    //console.log(txt);//DEBUG

    var name = "Resultat_"+fileName;

    var uri = 'data:text;charset=utf-8,' + escape(txt);

    var link = document.createElement("a");
    link.text = name;
    link.href = uri;
    link.download = name + ".txt";
    document.getElementById("link").appendChild(link);
}

//trie les trajectoires par score, les meilleures trajectoires seront au debut
function trie() {
    listeTajectoire.sort(function (t1, t2) {
        return t2.score - t1.score;
    });
}

//on ne garde que les meilleures trajectoires
//chaque bulle ne peut etre présent que dans une trajectoire
function elagage() {
    var listB = listBulle.slice();

    listeTajectoire.forEach(function (t) {
        var valid = true;
        var tmp = [];

        t.list.forEach(function (b) {
            tmp.push(b);

            if (valid && inArray(listB, b)) {
                let index = listB.indexOf(b);
                listB.splice(index, 1);
            }
            else {
                valid = false;
            }

        });

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

    });
}

//permet de voir si une bulle est dans une trajectoire
function inArray(list, b2) {
    let ret = false;
    list.forEach(function (b1) {
        if (b1.id === b2.id) {
            ret = true;
        }
    });
    return ret;
}

//calcule le score d'une trajectoire
//plus la distance entre les bulles est identiques, plus le score sera bas
//plus la valeur des angles est identiques, plus le score est bas
//plus  le score est bas, mieux est la trajectoire
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;
}


function isCorrectDistance(b1, b2, dist) {
    if (b1.id !== b2.id) {
        let tmp = b1.distanceXYZ(b2);
        if (tmp >= 0 && tmp <= dist)
            return true;
    }
    return false;
}

//crée les trajectoires
function backtracking(trajectoire) {
    var b1 = trajectoire.last;

    listBulle.forEach(function (b2) {
        let isCorrect = false;

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

            if (trajectoire.size !== 3) {
                tmpDist = DISTANCE;
                tmpAng = ANGLE;
            } else {
                tmpDist = DISTANCE * 2;
                tmpAng = ANGLE * 2;
            }

            if (isCorrectDistance(b1, b2, tmpDist)) {
                if (trajectoire.size > 1) {
                    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;
                }
            }
        }

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

            if (trajectoire.size > 4) {
                let s = score(trajectoire);
                trajectoire.score = s;

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

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

    });

}

//Fin bubulles -------------------------------------------------------

function animate() {
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
}

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

    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);
};

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));

    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;
}
