/*
TODO: Implement RK4 by doing two updates (for x+h/2 and x+h) before drawing
*/

// canvas variables
var canvas_width = 400;
var canvas_height = 400;
var ctx;

// pendulum variables
var x1, y1, ang1, v_ang1;
var x2, y2, ang2, v_ang2;
var m1, length1;
var m2, length2;
var dampness;
var g = 1;

function initCanvas()
{
    var c = document.getElementById("pendulum-canvas");
    ctx =  c.getContext("2d");
}

var old_a_ang1, old_a_ang2;
var old_v_ang1, old_v_ang2;
var firstTime = true;
function update()
{
    // update angle1 acceleration
    var num1 = -g*(2*m1+m2)*Math.sin(ang1);
    var num2 = -m2*g*Math.sin(ang1-2*ang2);
    var num3 = -2*Math.sin(ang1-ang2)*m2;
    var num4 = v_ang2*v_ang2*length2+v_ang1*v_ang1*length1*Math.cos(ang1-ang2);
    var den  = length1*(2*m1+m2-m2*Math.cos(2*ang1-2*ang2));
    var a_ang1 = (num1 + num2 + num3*num4) / den;

    // update angle2 acceleration
    num1 = 2*Math.sin(ang1-ang2);
    num2 = v_ang1*v_ang1*length1*(m1+m2);
    num3 = g*(m1+m2)*Math.cos(ang1);
    num4 = v_ang2*v_ang2*length2*m2*Math.cos(ang1-ang2);
    den  = length2*(2*m1+m2-m2*Math.cos(2*ang1-2*ang2));
    var a_ang2 = num1*(num2+num3+num4)/den;
    
    // update anglular velocity and angle
    if( firstTime )
    {
        // Euler's first order
        v_ang1 += a_ang1;
        v_ang2 += a_ang2;

        ang1 += v_ang1;
        ang2 += v_ang2;
        firstTime = false;
    }
    else
    {
        // Huen's second order
        v_ang1 += (a_ang1 + old_a_ang1) / 2;
        v_ang2 += (a_ang2 + old_a_ang2) / 2;
    
        ang1 += (v_ang1 + old_v_ang1) / 2;
        ang2 += (v_ang2 + old_v_ang2) / 2;
    }

    // update mass positions
    x1 = length1*Math.sin(ang1);
    y1 = length1*Math.cos(ang1);

    x2 = x1 + length2*Math.sin(ang2);
    y2 = y1 + length2*Math.cos(ang2);

    // update angular velocity based off of dampness
    v_ang1 *= dampness;
    v_ang2 *= dampness;

    // save angular acceleration and velocity
    // for next time steps Heun's method
    old_a_ang1 = a_ang1;
    old_a_ang2 = a_ang2;
    old_v_ang1 = v_ang1;
    old_v_ang2 = v_ang2;
}

function draw()
{
    // clear canvas
    ctx.fillStyle="#FFFFFF";
    ctx.fillRect(0,0,canvas_width,canvas_height);

    ctx.translate(canvas_width/2, canvas_height/2);

    // draw origin
    ctx.fillStyle="#000000";
    ctx.beginPath();
    ctx.arc(0,0,2, 0,2*Math.PI);
    ctx.fill();

    // draw rods
    ctx.fillStyle="#000000";
    ctx.beginPath();
    ctx.moveTo(0,0);
    ctx.lineTo(x1,y1);
    ctx.stroke();

    ctx.beginPath();
    ctx.moveTo(x1,y1);
    ctx.lineTo(x2,y2);
    ctx.stroke();

    // draw weights
    ctx.fillStyle="#00FF00";
    ctx.beginPath();
    ctx.arc(x1,y1,m1, 0,2*Math.PI);
    ctx.fill();

    ctx.fillStyle="#FF0000";
    ctx.beginPath();
    ctx.arc(x2,y2,m2, 0,2*Math.PI);
    ctx.fill();

    ctx.translate(-canvas_width/2, -canvas_height/2);
}

function loop()
{
    update();
    draw();
    requestAnimationFrame(loop);
}

function main()
{
    // setup up sliders
    var dampnessSlider = document.getElementById("dampnessSlider");
    dampnessSlider.min = 0.001;
    dampnessSlider.max = 0.1;
    dampnessSlider.step = 0.001;
    dampnessSlider.value = 0.005;
    dampnessSlider.oninput = function(){dampness =  1 - this.value;};
    dampness = 1 - dampnessSlider.value;

    var length1Slider = document.getElementById("length1Slider");
    length1Slider.min = 20;
    length1Slider.max = canvas_width / 4;
    length1Slider.step = 1;
    length1Slider.value = 100;
    length1Slider.oninput = function(){length1 = this.value;};
    length1 = length1Slider.value;

    var length2Slider = document.getElementById("length2Slider");
    length2Slider.min = 20;
    length2Slider.max = canvas_width / 4;
    length2Slider.step = 1;
    length2Slider.value = 100;
    length2Slider.oninput = function(){length2 = this.value;};
    length2 = length2Slider.value;

    var mass1Slider = document.getElementById("mass1Slider");
    mass1Slider.min = 2;
    mass1Slider.max = 20;
    mass1Slider.step = 0.1;
    mass1Slider.value = 5;
    mass1Slider.oninput = function(){m1 = this.value;};
    m1 = mass1Slider.value;

    var mass2Slider = document.getElementById("mass2Slider");
    mass2Slider.min = 2;
    mass2Slider.max = 20;
    mass2Slider.step = 0.1;
    mass2Slider.value = 5;
    mass2Slider.oninput = function(){m2 = this.value;};
    m2 = mass2Slider.value;

    // setup canvas
    initCanvas();

    // setup initial values
    ang1 = Math.random() * 2*Math.PI - Math.PI;
    ang2 = Math.random() * 2*Math.PI - Math.PI;
    v_ang1 = v_ang2 = 0;  

    // start main loop
    requestAnimationFrame(loop);
}