initVariables();
//////////////////////////////////////////////
xp = 0;
yp = 0;
rp = 50;
numSpheres = 12; // Número de esferas
radius; // Radio del reloj
nCoefi = 2.80;
/////////////////////////////////////////////

ballPos, ballVel, ballRadius = 80;
gravity = 1.0, initialV = 4;
pt1, pt2;
////////////////////////////////////////////////////////
function funcionGo(ctx, width, height) {
    if (lInit) {
        jsreinitProcedure();
        jsinitTimer(1);
        ballPos = createVector(width / 2, 0);
        ballVel = createVector(0, initialV);
        pt1 = createVector(width / 2, height);
        pt2 = createVector(width / 2, height);

        xp = width / 2;
        yp = hsIni - ballRadius;

        ellipse(xp, yp, rp * 2, rp * 2);
        txClocalUp = "DESPLAZAR";
        txClocalDown = "siga a la esfera";
        ballPos.set(parseInt(random(wsIni + ballRadius / 2, wsIni + wVideo - ballRadius / 2)), 0);
        ballVel.set(0, initialV);
    }
    //displaymodulo(0);

    fill(255, 255, 255, 128);
    ellipse(xp, yp, rp * 2, rp * 2)

    fill(255, 0, 0, 128);
    //ellipse(pCW1.x, pCW1.y, rp * 2, rp * 2);
    //ellipse(pCW2.x, pCW2.y, rp * 2, rp * 2);
    if (dist(xp, yp, pCW1.x, pCW1.y) < rp * 2 || dist(xp, yp, pCW2.x, pCW2.y) < rp * 2) {
        ellipse(pCW1.x, pCW1.y, rp * 2, rp * 2);
        ellipse(pCW2.x, pCW2.y, rp * 2, rp * 2);
        fill(255, 255, 255, 128);
        ellipse(xp, yp, rp * 1.5, rp * 1.5);
        if (dist(xp, yp, pCW1.x, pCW1.y) < rp * 1.5 || dist(xp, yp, pCW2.x, pCW2.y) < rp * 1.5) {
            fill(255, 255, 255, 128);
            ellipse(xp, yp, rp * 1, rp * 1);
            if (dist(xp, yp, pCW1.x, pCW1.y) < rp * 1 || dist(xp, yp, pCW2.x, pCW2.y) < rp * 1) {
                fill(255, 255, 255, 128);
                ellipse(xp, yp, rp * 0.5, rp * 0.5);
                if (dist(xp, yp, pCW1.x, pCW1.y) < rp / 1.5 || dist(xp, yp, pCW2.x, pCW2.y) < rp / 1.5) {
                    ellipse(xp, yp, rp * 0.25, rp * 0.25);
                    ballPos.set(parseInt(random(wsIni + ballRadius / 2, wsIni + wVideo - ballRadius / 2)), -80);
                    ballVel.set(0, initialV);
                }
            }
        }
    } else {
        fill(255, 0, 0, 128);
    }

    strokeWeight(2);
    stroke(200);

    pt1.x = -width;
    pt1.y = -width;
    pt2.x = -width;
    pt2.y = -width;


    pt1.x = pC1.x;
    pt1.y = pC1.y;
    pt2.x = pC5.x;
    pt2.y = pC5.y;
    //stroke(255);
    line(pt1.x, pt1.y, pt2.x, pt2.y);

    drawcolision();
    if (modoReflejo) {
        line(pt1.x, pt1.y, pt2.x, pt2.y);
        pt1.x = pC6.x;
        pt1.y = pC6.y;
        pt2.x = pC10.x;
        pt2.y = pC10.y;
        //stroke(255);
        line(pt1.x, pt1.y, pt2.x, pt2.y);
        drawcolision();
    }
    fill(255, 0, 0, 128);
    if (ballPos.x < wsIni + ballRadius / 2 || ballPos.x > wsIni + wVideo - ballRadius / 2 || ballPos.y < -ballRadius || ballPos.y > hsIni + hVideo + ballRadius / 2) {
    }
    else {
        circle(ballPos.x, ballPos.y, ballRadius);
    }

    pCW1.x = -width;
    pCW1.y = -width;
    pCW2.x = -width;
    pCW2.x = -width;
}

function drawcolision() {

    ballVel.y += gravity;
    ballPos.add(ballVel);

    if (circCollideLine(ballPos, ballRadius / 2, pt1, pt2)) {
        // calculate normals for line  -- normalise
        let l = p5.Vector.sub(pt2, pt1);
        let normal1 = l.rotate(HALF_PI);
        let normal2 = l.rotate(-HALF_PI);
        normal1.normalize();
        normal2.normalize();
        // find shortest normal+ballVel
        let normal;
        if (p5.Vector.add(ballVel, normal1).mag() < p5.Vector.add(ballVel, normal2).mag()) {
            normal = normal1;
        } else {
            normal = normal2;
        }
        // invert ballVel
        ballVel.mult(-1);
        // reflect angle
        ballVel.reflect(normal);
    }
    else {
        if (ballPos.x < wsIni + ballRadius / 2 || ballPos.x > wsIni + wVideo - ballRadius / 2 || ballPos.y < -ballRadius || ballPos.y > hsIni + hVideo - ballRadius / 2) {
            // invert ballVel
            ballVel.mult(-1);
        }
    }
}


function circCollideLine(circ, radius, pt1, pt2) {
    let pt1Collide = ptCollideCirc(pt1, circ, radius);
    let pt2Collide = ptCollideCirc(pt2, circ, radius);
    if (pt1Collide || pt2Collide) { return true; }  // does either end collide with circle

    let lineLen = dist(pt1.x, pt1.y, pt2.x, pt2.y);
    let dotProd = (((circ.x - pt1.x) * (pt2.x - pt1.x)) +
        ((circ.y - pt1.y) * (pt2.y - pt1.y))) / pow(lineLen, 2);
    let closestX = pt1.x + (dotProd * (pt2.x - pt1.x)); // closest point on line to circle
    let closestY = pt1.y + (dotProd * (pt2.y - pt1.y)); // closest point on line to circle

    let onSegment = ptCollideLine({ x: closestX, y: closestY }, pt1, pt2);  // not on infinite line beyond ends
    if (!onSegment) return false;

    if (dist(circ.x, circ.y, closestX, closestY) < radius) {
        return true;
    }

    return false;
}

function lineCollideLine(a1, a2, b1, b2) {
    // calculate dist to point of intersection
    let uA = ((b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)) /
        ((b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y));
    let uB = ((a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)) /
        ((b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y));

    if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
        return true;
    }
    return false;
}

function ptCollideCirc(point, circ, radius) {
    return dist(point.x, point.y, circ.x, circ.y) < radius;
}

function ptCollideLine(pt, end1, end2) {
    let lineLen = dist(end1.x, end1.y, end2.x, end2.y);  // could use vector.dist(v2)
    let ptTo1 = dist(pt.x, pt.y, end1.x, end1.y);
    let ptTo2 = dist(pt.x, pt.y, end2.x, end2.y);
    let buffer = 0.1; // accuracy value - higher num = less precise

    if (ptTo1 + ptTo2 >= lineLen - buffer && ptTo1 + ptTo2 <= lineLen + buffer) {
        // if (ptTo1 + ptTo2 <= lineLen + buffer) {  // isn't this functionally equiv. to above?
        return true;
    }
    return false;
}