'use strict';
var stg = {
    primaryHandColor: 0x9b59b6,
    secondaryHandColor: 0x3498db,
    dotcolor: 0x185b79,
    linecolor: 0x1ba2ba,
    clickcolor: 0xAAAAAA,
    goodcolor: 0x90cc66,
    errorcolor: 0xc02f27,
    positiveObjectColor: 0x27ae60,
    negativeObjectColor: 0xc0392b,
    feedbackDuration: 1,
    scale: 300,

    // nuove visualizzazioni
    showVirtualScreen: false, // visualizza i bordi di uno schermo virtuale davanti al paziente
    showTrackedObjects: false  // visualizza gli oggetti che appaiono davanti al paziente (devono essere inclusi nel tracking)
};
stg.cameraY = 800 / stg.scale;
stg.cameraZ = 2300 / stg.scale;
stg.angle = Math.atan(stg.cameraY / stg.cameraZ);

var camera = {};
var scene = {};
var start = {};
var f = {};
var renderer = {};
var pointsGeometry = {};
var mainHandGeometry = {};
var secondaryHandGeometry = {};
var clickPointsGeometry = {};
var goodPointsGeometry = {};
var errorPointsGeometry = {};

var positiveTargetsPointsGeometry = {}; // @@
var positiveTargetsPointsVector = {};

var lineGeometry = {};
var mainHand = {};
var secondaryHand = {};
var points = {};
var body = {};
var elementContainer = {};
var clickPoints = {};
var goodPoints = {};
var errorPoints = {};
var animate = {};
var datas = {};
var currIndex = {};
var line = {};
var goodPointsVector = {};
var errorPointsVector = {};
var scoreTime = {};
var posTime = {};
var negTime = {};

var slider = {};
var playbutton = {};
var timeline = {};
var score = {};
var HR = {};
var pos = {};
var neg = {};
var checks = {};
var pause = {};
var clickedSlider = {};
var movedSlider = {};

var handMaterial = new THREE.PointsMaterial({ color: stg.primaryHandColor, size: 100 / stg.scale });
var secondaryHandMaterial = new THREE.PointsMaterial({ color: stg.secondaryHandColor, size: 100 / stg.scale });
var pointMaterial = new THREE.PointsMaterial({ color: stg.dotcolor, size: 100 / stg.scale });
var clickPointMaterial = new THREE.PointsMaterial({ color: stg.clickcolor, size: 200 / stg.scale });
var goodPointMaterial = new THREE.PointsMaterial({ color: stg.goodcolor, size: 200 / stg.scale });
var errorPointMaterial = new THREE.PointsMaterial({ color: stg.errorcolor, size: 200 / stg.scale });
var lineMaterial = new THREE.LineBasicMaterial({ color: stg.linecolor });


var lastPositionMouse = {};
var deltaX = {};
var deltaY = {};
var onMouseMoveCallbacks = {};

// buffer degli ultimi valori letti
var last_head = [0, 0 , 0];
var last_right_hand = [0, 0 , 0];
var last_left_hand = [0, 0 , 0];

// tracked objects
var trackedObjectsPositiveMaterialKinect = new THREE.PointsMaterial({ color: stg.positiveObjectColor, size: 0.25 });
var trackedObjectsPositiveGeometryKinect = {};
var trackedObjectsPositivePointsKinect = {};

var trackedObjectsNegativeMaterialKinect = new THREE.PointsMaterial({ color: stg.negativeObjectColor, size: 0.25 });
var trackedObjectsNegativeGeometryKinect = {};
var trackedObjectsNegativePointsKinect = {};

function animateStickman(elem, data, flip) {
    var canvasNS = "http://www.w3.org/1999/xhtml";
    var container = document.getElementById(elem);
    while (container.firstChild) {
        container.removeChild(container.firstChild);
    }
    container.setAttribute("width", "100%");
    container.setAttribute("height", "100%");
    // here are defined standard settings for the chart (or the parameter in input is filled with missing elements) 

    datas[elem] = data;

    f[elem] = datas[elem].f;
    slider[elem] = document.createElement("input");
    slider[elem].setAttribute("type", "range");
    slider[elem].setAttribute("min", "0");
    slider[elem].setAttribute("step", "0.01");
    slider[elem].setAttribute("max", datas[elem]["head"].length / f[elem]);


    timeline[elem] = document.createElement("span");
    timeline[elem].classList.add("timelabel");
    score[elem] = document.createElement("span");
    score[elem].classList.add("scorelabel");

    var pt = document.createElement("b");
    pt.textContent = "Pt ";
    score[elem].appendChild(pt);
    score[elem].appendChild(document.createElement("span"));
    var hrenabled = false;
    for (var key in datas[elem]) {
        if (key == "events") {
            for (var iter in datas[elem][key]) {
                if (datas[elem][key][iter].type == "HR") {
                    hrenabled = true;
                    break;
                }
            }
            break;
        }
    }
    if (hrenabled) {
        HR[elem] = document.createElement("span");
        HR[elem].classList.add("HRlabel");
        var hrtext = document.createElement("b");
        hrtext.textContent = "HR ";
        HR[elem].appendChild(hrtext);
        HR[elem].appendChild(document.createElement("span"));
    }
    camera[elem] = new THREE.PerspectiveCamera(70, container.clientWidth / container.clientHeight, 0.01, 100);
    camera[elem].position.z = stg.cameraZ;
    camera[elem].position.y = stg.cameraY;
    scene[elem] = new THREE.Scene();
    scene[elem].background = new THREE.Color(0xFFFFFF);
    currIndex[elem] = -1;

    mainHandGeometry[elem] = new THREE.BufferGeometry();
    secondaryHandGeometry[elem] = new THREE.BufferGeometry();
    pointsGeometry[elem] = new THREE.BufferGeometry();
    clickPointsGeometry[elem] = new THREE.BufferGeometry();
    deltaX[elem] = 0;
    deltaY[elem] = 0;
    goodPointsGeometry[elem] = new THREE.BufferGeometry();
    errorPointsGeometry[elem] = new THREE.BufferGeometry();

    positiveTargetsPointsGeometry[elem] = new THREE.BufferGeometry(); // @@

    lineGeometry[elem] = new THREE.Geometry();

    goodPointsVector[elem] = [];
    errorPointsVector[elem] = [];
    scoreTime[elem] = [];
    posTime[elem] = [];
    negTime[elem] = [];


    // tracked objects
    trackedObjectsPositiveGeometryKinect[elem] = new THREE.BufferGeometry();
    trackedObjectsNegativeGeometryKinect[elem] = new THREE.BufferGeometry();
    

    for (var tindex in datas[elem]["head"]) {
        scoreTime[elem][tindex] = tindex > 0 ? scoreTime[elem][tindex - 1] : 0;
        posTime[elem][tindex] = tindex > 0 ? posTime[elem][tindex - 1] : 0;
        negTime[elem][tindex] = tindex > 0 ? negTime[elem][tindex - 1] : 0;

        for (var key in datas[elem]) {
            if (Array.isArray(datas[elem][key]) && typeof datas[elem][key][tindex] == 'object' && datas[elem][key][tindex].s) {
                if (key != "cursor") {
                    scoreTime[elem][tindex] += datas[elem][key][tindex].s;
                    if (datas[elem][key][tindex].s > 0) {
                        posTime[elem][tindex]++;
                    } else {
                        negTime[elem][tindex]++;
                    }
                }
            }
        }
    }
    pos[elem] = document.createElement("span");
    pos[elem].classList.add("poslabel");
    var check = document.createElement("span");
    check.classList.add("glyphicon");
    check.classList.add("glyphicon-ok");
    pos[elem].appendChild(document.createElement("span"));
    var totalPos = document.createElement("span");
    totalPos.textContent = "/" + posTime[elem][datas[elem]["head"].length - 1];
    pos[elem].appendChild(totalPos);
    pos[elem].appendChild(check);
    checks[elem] = document.createElement("span");
    checks[elem].classList.add("checklabel");
    if (negTime[elem][datas[elem]["head"].length - 1] && negTime[elem][datas[elem]["head"].length - 1] > 0) {
        neg[elem] = document.createElement("span");
        neg[elem].classList.add("neglabel");
        var cross = document.createElement("span");
        cross.classList.add("glyphicon");
        cross.classList.add("glyphicon-remove");

        neg[elem].appendChild(document.createElement("span"));
        var totalNeg = document.createElement("span");
        totalNeg.textContent = "/" + negTime[elem][datas[elem]["head"].length - 1];
        neg[elem].appendChild(totalNeg);
        neg[elem].appendChild(cross);
    }

    var virtualScreen = null;
    if (stg.showVirtualScreen) {
        virtualScreen = setupVirtualScreen(data, elem);
    }
    var handPosition = calculateBody(elem, 0);

    
    mainHand[elem] = new THREE.Points(mainHandGeometry[elem], handMaterial);
    secondaryHand[elem] = new THREE.Points(secondaryHandGeometry[elem], secondaryHandMaterial);
    points[elem] = new THREE.Points(pointsGeometry[elem], pointMaterial);
    line[elem] = new THREE.Line(lineGeometry[elem], lineMaterial);
    clickPoints[elem] = new THREE.Points(clickPointsGeometry[elem], clickPointMaterial);
    goodPoints[elem] = new THREE.Points(goodPointsGeometry[elem], goodPointMaterial);
    errorPoints[elem] = new THREE.Points(errorPointsGeometry[elem], errorPointMaterial);




    // tracked objects
    trackedObjectsPositivePointsKinect[elem] = new THREE.Points(trackedObjectsPositiveGeometryKinect[elem], trackedObjectsPositiveMaterialKinect);
    trackedObjectsNegativePointsKinect[elem] = new THREE.Points(trackedObjectsNegativeGeometryKinect[elem], trackedObjectsNegativeMaterialKinect);


    body[elem] = new THREE.Group();
    elementContainer[elem] = new THREE.Group();

    elementContainer[elem].add(mainHand[elem]);
    elementContainer[elem].add(secondaryHand[elem]);
    elementContainer[elem].add(clickPoints[elem]);
    elementContainer[elem].add(line[elem]);
    elementContainer[elem].add(points[elem]);
    elementContainer[elem].add(goodPoints[elem]);
    elementContainer[elem].add(errorPoints[elem]);

    if (stg.showTrackedObjects) {
        elementContainer[elem].add(trackedObjectsPositivePointsKinect[elem]);
        elementContainer[elem].add(trackedObjectsNegativePointsKinect[elem]);
    }


    if ( virtualScreen ) {
        elementContainer[elem].add(screenBorders[elem]);
    }

    body[elem].add(elementContainer[elem]);
    body[elem].rotation.y = Math.PI;

    // aggiungo i targets

    /*
    if (targetsGroup!=null) {
        body[elem].remove(targetsGroup);
    }
    targetsGroup = calculateTargets(elem, handPosition)
    body[elem].add(targetsGroup);
    */


    if (flip)
        body[elem].scale.x = -1;
    scene[elem].add(body[elem]);
    renderer[elem] = new THREE.WebGLRenderer({ antialias: true });
    renderer[elem].setSize(container.clientWidth, container.clientHeight);
    container.appendChild(renderer[elem].domElement);
    animate[elem] = animateFactory(elem);
    animate[elem](window.performance.now());

    onMouseMoveCallbacks[elem] = function (event) {
        if (!lastPositionMouse[elem]) {
            lastPositionMouse[elem] = new THREE.Vector2();
        } else {
            if (event.clientX) {
                deltaX[elem] = (lastPositionMouse[elem].x - event.clientX) / 100;
                deltaY[elem] = (lastPositionMouse[elem].y - event.clientY) / 100;
            } else if (event.touches && event.touches.length > 0) {
                deltaX[elem] = (lastPositionMouse[elem].x - event.touches[0].clientX) / 100;
                deltaY[elem] = (lastPositionMouse[elem].y - event.touches[0].clientY) / 100;
            }
        }
        if (event.clientX) {
            lastPositionMouse[elem].x = event.clientX;
            lastPositionMouse[elem].y = event.clientY;
        } else if (event.touches && event.touches.length > 0) {
            lastPositionMouse[elem].x = event.touches[0].clientX;
            lastPositionMouse[elem].y = event.touches[0].clientY;
        }
    };
    renderer[elem].domElement.addEventListener("touchstart", function (event) {
        event.stopPropagation();
        container.addEventListener("touchmove", onMouseMoveCallbacks[elem], false);
    }, false);
    renderer[elem].domElement.addEventListener("mousedown", function (event) {
        container.addEventListener("mousemove", onMouseMoveCallbacks[elem], false);
    }, false);
    renderer[elem].domElement.addEventListener("touchend", function (event) {
        event.stopPropagation();
        container.removeEventListener("touchmove", onMouseMoveCallbacks[elem]);

        lastPositionMouse[elem] = undefined;
    }, false);
    renderer[elem].domElement.addEventListener("mouseup", function (event) {
        container.removeEventListener("mousemove", onMouseMoveCallbacks[elem]);
        lastPositionMouse[elem] = undefined;
    }, false);
    renderer[elem].domElement.addEventListener("mouseout", function (event) {
        container.removeEventListener("mousemove", onMouseMoveCallbacks[elem]);
        container.removeEventListener("touchmove", onMouseMoveCallbacks[elem]);

        lastPositionMouse[elem] = undefined;
    }, false);
    container.appendChild(slider[elem]);
    slider[elem].addEventListener("touchstart", function (event) {
        event.stopPropagation();
        clickedSlider[elem] = true;
    }, false);
    slider[elem].addEventListener("touchend", function (event) {
        event.stopPropagation();
        if (clickedSlider[elem]) {
            goodPointsVector[elem] = [];
            errorPointsVector[elem] = [];
            start[elem] = window.performance.now() - slider[elem].value * 1000;
        }
        clickedSlider[elem] = false;
    }, false);
    slider[elem].addEventListener("mousedown", function (event) {
        clickedSlider[elem] = true;
    }, false);
    slider[elem].addEventListener("mouseup", function (event) {
        if (clickedSlider[elem]) {
            goodPointsVector[elem] = [];
            errorPointsVector[elem] = [];
            start[elem] = window.performance.now() - slider[elem].value * 1000;
        }
        clickedSlider[elem] = false;
    }, false);
    slider[elem].addEventListener("mouseout", function (event) {
        clickedSlider[elem] = false;
    }, false);
    slider[elem].addEventListener("mousemove", function (event) {
        if (clickedSlider[elem]) {
            goodPointsVector[elem] = [];
            errorPointsVector[elem] = [];
            start[elem] = window.performance.now() - slider[elem].value * 1000;
            movedSlider[elem] = true;
        }
    }, false);
    slider[elem].addEventListener("touchmove", function (event) {
        if (clickedSlider[elem]) {
            goodPointsVector[elem] = [];
            errorPointsVector[elem] = [];
            start[elem] = window.performance.now() - slider[elem].value * 1000;
            movedSlider[elem] = true;
        }
    }, false);
    playbutton[elem] = document.createElement("button");
    playbutton[elem].classList.add("onlyicon");
    playbutton[elem].classList.add("play");
    var pauseButton = document.createElement("i");
    pauseButton.classList.add("fas");
    pauseButton.classList.add("fa-pause");
    pauseButton.setAttribute("aria-hidden", true);
    playbutton[elem].appendChild(pauseButton);
    playbutton[elem].addEventListener("mouseup", function (event) {
        pause[elem] = !pause[elem];
        if (pause[elem]) {
            pauseButton.classList.remove("fa-pause");
            pauseButton.classList.add("fa-play");
        } else {
            pauseButton.classList.add("fa-pause");
            pauseButton.classList.remove("fa-play");
            start[elem] = window.performance.now() - slider[elem].value * 1000;
        }
    });
    container.appendChild(playbutton[elem]);
    container.appendChild(timeline[elem]);
    container.appendChild(score[elem]);
    if (hrenabled) {
        container.appendChild(HR[elem]);
    }
    container.appendChild(pos[elem]);
    container.appendChild(checks[elem]);
    if (neg[elem])
        container.appendChild(neg[elem]);

    var size = 200;
    var divisions = 200;
    var gridHelper = new THREE.GridHelper(size, divisions, 0xdddddd, 0xf2f2f2);
    elementContainer[elem].add(gridHelper);
}

var targetsGroup = null;
function animateFactory(elem) {
    return function (timestamp) {
        if (!start[elem]) {
            start[elem] = timestamp;
        }
        requestAnimationFrame(animate[elem]);

        var handPosition = new THREE.Vector3(0, 0, 0);

        if (!clickedSlider[elem] && !pause[elem]) {
            handPosition = calculateBody(elem, (timestamp - start[elem]) / 1000);
        } else if (movedSlider[elem]) {
            handPosition = calculateBody(elem, (timestamp - start[elem]) / 1000);
            movedSlider[elem] = false;
        }
        /*
        if (targetsGroup!=null) {
            body[elem].remove(targetsGroup);
        }
        
        targetsGroup = calculateTargets(elem, handPosition)
        body[elem].add(targetsGroup);
        */

        body[elem].rotation.y -= deltaX[elem];
        body[elem].rotation.x -= deltaY[elem];
        if (body[elem].rotation.x < -stg.angle) {
            body[elem].rotation.x = -stg.angle;
        }
        if (body[elem].rotation.x > Math.PI / 2) {
            body[elem].rotation.x = Math.PI / 2;
        }

        deltaX[elem] = 0;
        deltaY[elem] = 0;
        renderer[elem].render(scene[elem], camera[elem]);
    }
}

//-------------------------------------------------------------------------------------------------------
// virtual screen drawing
//-------------------------------------------------------------------------------------------------------
/*
    "boundary-screen": {
        "top-right": {
            "x": 462.250274658203,
            "y": 1849.78930664063,
            "z": 2613.73510742188
        },
        "bottom-left": {
            "x": -263.311401367188,
            "y": 1381.55102539063,
            "z": 2613.73510742188
        }
    }
*/
// global variables for screen drawing
var screenBordersGeometry = {};
var screenLineMaterial = new THREE.LineBasicMaterial({ color: 0x8e44ad }); // 0xCCCCCC
var screenBorders = {};
function setupVirtualScreen(data, elem) {
    if (typeof data['boundary-screen'] !== 'undefined' && data['boundary-screen'].length>0) {

        screenBordersGeometry[elem] = new THREE.BufferGeometry();
        screenBorders[elem]         = new THREE.Line(screenBordersGeometry[elem], screenLineMaterial);
        return updateVirtualScreen(elem, data['boundary-screen'], 0)
    }
    return false;

}

function updateVirtualScreen(elem, samples, index) {

    if (!samples || samples.length == 0 || samples.length < index ) return;

    var screen = samples[index];
    var bottomLeft = screen["bottomLeft"];
    var bottomRight = screen["bottomRight"];
    var topLeft = screen["topLeft"];
    var topRight = screen["topRight"];

    var vertices = [];

    vertices.push(bottomLeft.x/stg.scale, bottomLeft.y/stg.scale, bottomLeft.z/stg.scale);
    vertices.push(topLeft.x/stg.scale, topLeft.y/stg.scale, topLeft.z/stg.scale);

    vertices.push(topLeft.x/stg.scale, topLeft.y/stg.scale, topLeft.z/stg.scale);
    vertices.push(topRight.x/stg.scale, topRight.y/stg.scale, topRight.z/stg.scale);

    vertices.push(topRight.x/stg.scale, topRight.y/stg.scale, topRight.z/stg.scale);
    vertices.push(bottomRight.x/stg.scale, bottomRight.y/stg.scale, bottomRight.z/stg.scale);

    vertices.push(bottomRight.x/stg.scale, bottomRight.y/stg.scale, bottomRight.z/stg.scale);
    vertices.push(bottomLeft.x/stg.scale, bottomLeft.y/stg.scale, bottomLeft.z/stg.scale);

    screenBordersGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
    
    return true;

}

function isArrayZero(_array) {
    return (_array[0]==0 && _array[1]==0 && _array[2]==0)
}

// returns hand position Vector3()
function calculateBody(elem, time) {

    var handPosition = null;

    currIndex[elem] = Math.floor(time * f[elem]);
    if (!clickedSlider[elem]) {
        slider[elem].value = time;
    }
    var seconds = Math.floor(time % 60);

    timeline[elem].textContent = Math.floor(time / 60) + ":" + (seconds < 10 ? "0" + seconds : seconds);
    var mainHandVertices = [];
    var secondaryHandVertices = [];
    var vertices = [];
    var clickVertices = [];


    var trackedObjectsPositiveVertices = [];
    var trackedObjectsNegativeVertices = [];

    var deviceMainHand = 'right-hand';
    if (typeof datas[elem]['main-hand'] !== 'undefined') {
        deviceMainHand = datas[elem]['main-hand'];
    }

    var deviceSecondaryHand = 'left-hand';
    if (typeof datas[elem]['secondary-hand'] !== 'undefined') {
        deviceSecondaryHand = datas[elem]['secondary-hand'];
    }
    if (currIndex[elem] >= datas[elem]["head"].length) {
        currIndex[elem] = 0;
        start[elem] = 0;
        goodPointsVector[elem] = [];
        errorPointsVector[elem] = [];
    }
    for (var key in datas[elem]) {
        if (key =='cursor' || key =='cursor-secondary') {
            continue;
        }
        if (key == "events") {
            var activeChecks = [];
            for (var iev in datas[elem][key]) {
                if (datas[elem][key][iev].index <= currIndex[elem]) {
                    if (datas[elem][key][iev].type.indexOf("check.") == 0) {
                        if (parseInt(datas[elem][key][iev].value) > 0) {
                            activeChecks.push(datas[elem][key][iev].type);
                        } else if (activeChecks.indexOf(datas[elem][key][iev].type) >= 0) {
                            activeChecks.splice(activeChecks.indexOf(datas[elem][key][iev].type), 1);
                        }
                    }
                    if (datas[elem][key][iev].type == "HR") {
                        HR[elem].lastChild.textContent = "" + datas[elem][key][iev].value;
                    }
                }
            }
            if (activeChecks.length > 0) {
                checks[elem].textContent = "" + activeChecks[0].substring(activeChecks[0].indexOf(".") + 1).replace(".", " ").toUpperCase();
            } else {
                checks[elem].textContent = "";
            }
        } else if (key == 'tracked-objects' && stg.showTrackedObjects) {
            var idx = currIndex[elem];
            if (idx >= 0) {
                var tkObjects = datas[elem][key][idx];
                for (var cnn = 0; cnn < tkObjects.length; cnn++) {
                    var objPos = tkObjects[cnn]['device-position'];

                    if (!objPos) continue;

                    var t = { x: objPos.x / stg.scale, y: objPos.y / stg.scale, z: objPos.z / stg.scale };

                    if (tkObjects[cnn].points && tkObjects[cnn].points <= 0) {
                        trackedObjectsNegativeVertices.push(t.x, t.y, t.z);
                    } else {
                        trackedObjectsPositiveVertices.push(t.x, t.y, t.z);
                    }
                }
            }
        } else if (key == 'boundary-screen' && stg.showVirtualScreen) {
            var idx = currIndex[elem];
            if (idx >= 0) {
                updateVirtualScreen(elem, datas[elem]['boundary-screen'], idx)
                
            }
        } else {
            if (Array.isArray(datas[elem][key]) && Array.isArray(datas[elem][key][currIndex[elem]])) {

                //vertices.push(datas[elem][key][currIndex[elem]][0] / stg.scale, datas[elem][key][currIndex[elem]][1] / stg.scale, datas[elem][key][currIndex[elem]][2] / stg.scale);
                
                if (key==deviceMainHand) {
                    mainHandVertices.push(datas[elem][key][currIndex[elem]][0] / stg.scale, datas[elem][key][currIndex[elem]][1] / stg.scale, datas[elem][key][currIndex[elem]][2] / stg.scale);
                } else if (key==deviceSecondaryHand) {
                    secondaryHandVertices.push(datas[elem][key][currIndex[elem]][0] / stg.scale, datas[elem][key][currIndex[elem]][1] / stg.scale, datas[elem][key][currIndex[elem]][2] / stg.scale);
                } else {
                    vertices.push(datas[elem][key][currIndex[elem]][0] / stg.scale, datas[elem][key][currIndex[elem]][1] / stg.scale, datas[elem][key][currIndex[elem]][2] / stg.scale);
                }
                
            } else if (Array.isArray(datas[elem][key]) && typeof datas[elem][key][currIndex[elem]] == 'object' && datas[elem][key][currIndex[elem]].p) {
                if (datas[elem][key][currIndex[elem]].g) {
                    clickVertices.push(datas[elem][key][currIndex[elem]].p[0] / stg.scale, datas[elem][key][currIndex[elem]].p[1] / stg.scale, datas[elem][key][currIndex[elem]].p[2] / stg.scale);
                }
                if (datas[elem][key][currIndex[elem]].s != undefined) {
                    if (datas[elem][key][currIndex[elem]].s > 0) {
                        goodPointsVector[elem].push({ t: time, p: datas[elem][key][currIndex[elem]].p });
                    } else {
                        errorPointsVector[elem].push({ t: time, p: datas[elem][key][currIndex[elem]].p });
                    }
                }
                //vertices.push(datas[elem][key][currIndex[elem]].p[0] / stg.scale, datas[elem][key][currIndex[elem]].p[1] / stg.scale, datas[elem][key][currIndex[elem]].p[2] / stg.scale);
                if (key==deviceMainHand) {
                    mainHandVertices.push(datas[elem][key][currIndex[elem]].p[0] / stg.scale, datas[elem][key][currIndex[elem]].p[1] / stg.scale, datas[elem][key][currIndex[elem]].p[2] / stg.scale);
                } else if (key==deviceSecondaryHand) {
                    secondaryHandVertices.push(datas[elem][key][currIndex[elem]].p[0] / stg.scale, datas[elem][key][currIndex[elem]].p[1] / stg.scale, datas[elem][key][currIndex[elem]].p[2] / stg.scale);
                } else {
                    vertices.push(datas[elem][key][currIndex[elem]].p[0] / stg.scale, datas[elem][key][currIndex[elem]].p[1] / stg.scale, datas[elem][key][currIndex[elem]].p[2] / stg.scale);
                }
                

            }
        }
    }
    score[elem].lastChild.textContent = "" + scoreTime[elem][currIndex[elem]];
    pos[elem].firstChild.textContent = posTime[elem][currIndex[elem]];
    if (neg[elem])
        neg[elem].firstChild.textContent = negTime[elem][currIndex[elem]];

    var goodVertices = [];
    for (var index in goodPointsVector[elem]) {
        if (time - goodPointsVector[elem][index].t < stg.feedbackDuration) {
            goodVertices.push(goodPointsVector[elem][index].p[0] / stg.scale, goodPointsVector[elem][index].p[1] / stg.scale, goodPointsVector[elem][index].p[2] / stg.scale);
        }
    }
    var errorVertices = [];
    for (var index in errorPointsVector[elem]) {
        if (time - errorPointsVector[elem][index].t < stg.feedbackDuration) {
            errorVertices.push(errorPointsVector[elem][index].p[0] / stg.scale, errorPointsVector[elem][index].p[1] / stg.scale, errorPointsVector[elem][index].p[2] / stg.scale);
        }
    }


    mainHandGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(mainHandVertices), 3));
    secondaryHandGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(secondaryHandVertices), 3));
    
    pointsGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(vertices), 3));
    clickPointsGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(clickVertices), 3));
    goodPointsGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(goodVertices), 3));
    errorPointsGeometry[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(errorVertices), 3));

    lineGeometry[elem].vertices = [];

    if (currIndex[elem] < 0) {
        return new THREE.Vector3(0, 0, 0);
    }

    // head
    if (!isArrayZero(datas[elem]["head"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["head"][currIndex[elem]][0] / stg.scale, datas[elem]["head"][currIndex[elem]][1] / stg.scale, datas[elem]["head"][currIndex[elem]][2] / stg.scale));
    }
    
    if (!isArrayZero(datas[elem]["neck"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["neck"][currIndex[elem]][0] / stg.scale, datas[elem]["neck"][currIndex[elem]][1] / stg.scale, datas[elem]["neck"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["collar"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["collar"][currIndex[elem]][0] / stg.scale, datas[elem]["collar"][currIndex[elem]][1] / stg.scale, datas[elem]["collar"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["left-shoulder"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-shoulder"][currIndex[elem]][0] / stg.scale, datas[elem]["left-shoulder"][currIndex[elem]][1] / stg.scale, datas[elem]["left-shoulder"][currIndex[elem]][2] / stg.scale));
    }
    
    if (!isArrayZero(datas[elem]["left-elbow"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-elbow"][currIndex[elem]][0] / stg.scale, datas[elem]["left-elbow"][currIndex[elem]][1] / stg.scale, datas[elem]["left-elbow"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["left-wrist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-wrist"][currIndex[elem]][0] / stg.scale, datas[elem]["left-wrist"][currIndex[elem]][1] / stg.scale, datas[elem]["left-wrist"][currIndex[elem]][2] / stg.scale));
    }
    if (Array.isArray(datas[elem]["left-hand"][currIndex[elem]])) {

        if (!isArrayZero(datas[elem]["left-hand"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-hand"][currIndex[elem]][0] / stg.scale, datas[elem]["left-hand"][currIndex[elem]][1] / stg.scale, datas[elem]["left-hand"][currIndex[elem]][2] / stg.scale));
        }
        
    } else if (datas[elem]["left-hand"][currIndex[elem]].p) {
        if (!isArrayZero(datas[elem]["left-hand"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-hand"][currIndex[elem]].p[0] / stg.scale, datas[elem]["left-hand"][currIndex[elem]].p[1] / stg.scale, datas[elem]["left-hand"][currIndex[elem]].p[2] / stg.scale));
        }
    }
    //lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-wrist"][currIndex[elem]][0]/stg.scale,  datas[elem]["left-wrist"][currIndex[elem]][1]/stg.scale, datas[elem]["left-wrist"][currIndex[elem]][2]/stg.scale));

    if (!isArrayZero(datas[elem]["left-elbow"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-elbow"][currIndex[elem]][0] / stg.scale, datas[elem]["left-elbow"][currIndex[elem]][1] / stg.scale, datas[elem]["left-elbow"][currIndex[elem]][2] / stg.scale));
    }
    
    

    if (!isArrayZero(datas[elem]["left-shoulder"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-shoulder"][currIndex[elem]][0] / stg.scale, datas[elem]["left-shoulder"][currIndex[elem]][1] / stg.scale, datas[elem]["left-shoulder"][currIndex[elem]][2] / stg.scale));
    }

    if (Array.isArray(datas[elem]["torso"][currIndex[elem]])) {
        if (!isArrayZero(datas[elem]["torso"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["torso"][currIndex[elem]][0] / stg.scale, datas[elem]["torso"][currIndex[elem]][1] / stg.scale, datas[elem]["torso"][currIndex[elem]][2] / stg.scale));
        }
    } else {
        if (!isArrayZero(datas[elem]["torso"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["torso"][currIndex[elem]].p[0] / stg.scale, datas[elem]["torso"][currIndex[elem]].p[1] / stg.scale, datas[elem]["torso"][currIndex[elem]].p[2] / stg.scale));
        }
    }

    if (!isArrayZero(datas[elem]["waist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["waist"][currIndex[elem]][0] / stg.scale, datas[elem]["waist"][currIndex[elem]][1] / stg.scale, datas[elem]["waist"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["left-hip"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-hip"][currIndex[elem]][0] / stg.scale, datas[elem]["left-hip"][currIndex[elem]][1] / stg.scale, datas[elem]["left-hip"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["left-knee"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-knee"][currIndex[elem]][0] / stg.scale, datas[elem]["left-knee"][currIndex[elem]][1] / stg.scale, datas[elem]["left-knee"][currIndex[elem]][2] / stg.scale));
    }
    if (Array.isArray(datas[elem]["left-ankle"][currIndex[elem]])) {
        if (!isArrayZero(datas[elem]["left-ankle"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-ankle"][currIndex[elem]][0] / stg.scale, datas[elem]["left-ankle"][currIndex[elem]][1] / stg.scale, datas[elem]["left-ankle"][currIndex[elem]][2] / stg.scale));
        }
    } else {
        if (!isArrayZero(datas[elem]["left-ankle"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-ankle"][currIndex[elem]].p[0] / stg.scale, datas[elem]["left-ankle"][currIndex[elem]].p[1] / stg.scale, datas[elem]["left-ankle"][currIndex[elem]].p[2] / stg.scale));
        }
    }

    if (!isArrayZero(datas[elem]["left-knee"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-knee"][currIndex[elem]][0] / stg.scale, datas[elem]["left-knee"][currIndex[elem]][1] / stg.scale, datas[elem]["left-knee"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["left-hip"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["left-hip"][currIndex[elem]][0] / stg.scale, datas[elem]["left-hip"][currIndex[elem]][1] / stg.scale, datas[elem]["left-hip"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["waist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["waist"][currIndex[elem]][0] / stg.scale, datas[elem]["waist"][currIndex[elem]][1] / stg.scale, datas[elem]["waist"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["right-hip"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-hip"][currIndex[elem]][0] / stg.scale, datas[elem]["right-hip"][currIndex[elem]][1] / stg.scale, datas[elem]["right-hip"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["right-knee"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-knee"][currIndex[elem]][0] / stg.scale, datas[elem]["right-knee"][currIndex[elem]][1] / stg.scale, datas[elem]["right-knee"][currIndex[elem]][2] / stg.scale));
    }
    if (Array.isArray(datas[elem]["right-ankle"][currIndex[elem]])) {
        if (!isArrayZero(datas[elem]["right-ankle"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-ankle"][currIndex[elem]][0] / stg.scale, datas[elem]["right-ankle"][currIndex[elem]][1] / stg.scale, datas[elem]["right-ankle"][currIndex[elem]][2] / stg.scale));
        }
    } else {
        if (!isArrayZero(datas[elem]["right-ankle"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-ankle"][currIndex[elem]].p[0] / stg.scale, datas[elem]["right-ankle"][currIndex[elem]].p[1] / stg.scale, datas[elem]["right-ankle"][currIndex[elem]].p[2] / stg.scale));
        }
    }

    if (!isArrayZero(datas[elem]["right-knee"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-knee"][currIndex[elem]][0] / stg.scale, datas[elem]["right-knee"][currIndex[elem]][1] / stg.scale, datas[elem]["right-knee"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["right-hip"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-hip"][currIndex[elem]][0] / stg.scale, datas[elem]["right-hip"][currIndex[elem]][1] / stg.scale, datas[elem]["right-hip"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["waist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["waist"][currIndex[elem]][0] / stg.scale, datas[elem]["waist"][currIndex[elem]][1] / stg.scale, datas[elem]["waist"][currIndex[elem]][2] / stg.scale));
    }
    if (Array.isArray(datas[elem]["torso"][currIndex[elem]])) {

        if (!isArrayZero(datas[elem]["torso"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["torso"][currIndex[elem]][0] / stg.scale, datas[elem]["torso"][currIndex[elem]][1] / stg.scale, datas[elem]["torso"][currIndex[elem]][2] / stg.scale));
        }
    } else {
        if (!isArrayZero(datas[elem]["torso"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["torso"][currIndex[elem]].p[0] / stg.scale, datas[elem]["torso"][currIndex[elem]].p[1] / stg.scale, datas[elem]["torso"][currIndex[elem]].p[2] / stg.scale));
        }
    }
    if (!isArrayZero(datas[elem]["right-shoulder"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-shoulder"][currIndex[elem]][0] / stg.scale, datas[elem]["right-shoulder"][currIndex[elem]][1] / stg.scale, datas[elem]["right-shoulder"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["right-elbow"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-elbow"][currIndex[elem]][0] / stg.scale, datas[elem]["right-elbow"][currIndex[elem]][1] / stg.scale, datas[elem]["right-elbow"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["right-wrist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-wrist"][currIndex[elem]][0] / stg.scale, datas[elem]["right-wrist"][currIndex[elem]][1] / stg.scale, datas[elem]["right-wrist"][currIndex[elem]][2] / stg.scale));
    }
    if (Array.isArray(datas[elem]["right-hand"][currIndex[elem]])) {
    
        if (!isArrayZero(datas[elem]["right-hand"][currIndex[elem]])) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-hand"][currIndex[elem]][0] / stg.scale, datas[elem]["right-hand"][currIndex[elem]][1] / stg.scale, datas[elem]["right-hand"][currIndex[elem]][2] / stg.scale));
            handPosition = new THREE.Vector3(datas[elem]["right-hand"][currIndex[elem]][0] / stg.scale, datas[elem]["right-hand"][currIndex[elem]][1] / stg.scale, datas[elem]["right-hand"][currIndex[elem]][2] / stg.scale)
        }
    
    } else if (datas[elem]["right-hand"][currIndex[elem]].p) {

        if (!isArrayZero(datas[elem]["right-hand"][currIndex[elem]].p)) {
            lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-hand"][currIndex[elem]].p[0] / stg.scale, datas[elem]["right-hand"][currIndex[elem]].p[1] / stg.scale, datas[elem]["right-hand"][currIndex[elem]].p[2] / stg.scale));
            handPosition = new THREE.Vector3(datas[elem]["right-hand"][currIndex[elem]].p[0] / stg.scale, datas[elem]["right-hand"][currIndex[elem]].p[1] / stg.scale, datas[elem]["right-hand"][currIndex[elem]].p[2] / stg.scale);
            last_right_hand = [datas[elem]["right-hand"][currIndex[elem]].p[0], datas[elem]["right-hand"][currIndex[elem]].p[1], datas[elem]["right-hand"][currIndex[elem]].p[2]]
        }

        
    }

    if (!isArrayZero(datas[elem]["right-wrist"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-wrist"][currIndex[elem]][0] / stg.scale, datas[elem]["right-wrist"][currIndex[elem]][1] / stg.scale, datas[elem]["right-wrist"][currIndex[elem]][2] / stg.scale));
    }
    if (!isArrayZero(datas[elem]["right-elbow"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-elbow"][currIndex[elem]][0] / stg.scale, datas[elem]["right-elbow"][currIndex[elem]][1] / stg.scale, datas[elem]["right-elbow"][currIndex[elem]][2] / stg.scale));
    }
    
    
    if (!isArrayZero(datas[elem]["right-shoulder"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["right-shoulder"][currIndex[elem]][0] / stg.scale, datas[elem]["right-shoulder"][currIndex[elem]][1] / stg.scale, datas[elem]["right-shoulder"][currIndex[elem]][2] / stg.scale));
    }

    if (!isArrayZero(datas[elem]["collar"][currIndex[elem]])) {
        lineGeometry[elem].vertices.push(new THREE.Vector3(datas[elem]["collar"][currIndex[elem]][0] / stg.scale, datas[elem]["collar"][currIndex[elem]][1] / stg.scale, datas[elem]["collar"][currIndex[elem]][2] / stg.scale));
    }
    lineGeometry[elem].verticesNeedUpdate = true;


    trackedObjectsPositiveGeometryKinect[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(trackedObjectsPositiveVertices), 3))
    trackedObjectsNegativeGeometryKinect[elem].addAttribute('position', new THREE.BufferAttribute(new Float32Array(trackedObjectsNegativeVertices), 3))


    return handPosition;
}
