var background_color = "#fafafa";
var canvas = document.getElementById("canvas");
var renderer = new THREE.WebGLRenderer( { canvas: canvas } );
var scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
var win_width = 0, win_height = 0;
function update_size() {
    if (window.innerWidth != win_width || window.innerHeight != win_height) {
        win_width = window.innerWidth;
        win_height = window.innerHeight;
        renderer.setPixelRatio(window.devicePixelRatio || 1);
        renderer.setSize(win_width, win_height);
        camera.aspect = win_width / win_height;
        camera.updateProjectionMatrix();
    }
}
update_size();

var clock = new THREE.Clock();
var delta_time = 1/60.0;
var elapsed_time = 0;

var geometry = new THREE.Geometry();
var radius = 10;
var depth_step = 10;
var num_rings = 100;
var num_segments = 24;

var outer_h = Math.max($("#outer").height(), 10000) - 1200;
var content_h = Math.max($("#content").height(), 10000);
var content_h2 = $("#content").height() + 9200;

var base_colors = [];
var colors = [];
var num_colors = num_rings * num_segments * 2;
for (var c = 0; c < num_colors; c++) {
    base_colors[c] = new THREE.Color(Math.random(), Math.random(), Math.random());
    colors[c] = base_colors[c].clone();
}

function lerp(res, color1, color2, t) {
    res.r = (1-t)*color1.r + t*color2.r;
    res.g = (1-t)*color1.g + t*color2.g;
    res.b = (1-t)*color1.b + t*color2.b;
}

function update_colors(delta, progress) {
    var bias = 1;
    var bg = new THREE.Color(background_color);
    var h1 = content_h - 6000;
    var h2 = content_h + 400;
    if (progress < h1) {
        bias = 0;
    } else if (progress < h2) {
        bias = (progress - h1) / (h2 - h1);
    }
    //if (s > content_h) {
    //    if (s > content_h + 1000) {
    //        color = new THREE.Color(1, 1, 1);
    //    } else {
    //        var q = (s - content_h) / 1000;
    //        //color = new THREE.Color(r + (1-r) * q, g + (1-g) * q, b + (1-b) * q);
    //        color = new THREE.Color();
    //        color.setHSL(0, 0.5, q * 0.6 + 0.4);
    //    }
    //} else {
    //    var q = (content_h-s) / content_h;
    //    color = new THREE.Color();
    //    color.setHSL(q, 0.5, 0.4);
    //}
    for (var c = 0; c < num_colors; c++) {
        var hsl = base_colors[c].getHSL();
        var h = hsl.h;
        h = (h + delta * (1+c/100)) % 1;
        base_colors[c].setHSL(h, hsl.s, hsl.l);
        lerp(colors[c], bg, base_colors[c], bias);
    }
}
update_colors(0, 0);

var verts = [];
var speeds = [];
var phases = [];
function init_verts() {
    var x = 0, y = 0, z = 0;
    var dz = -depth_step / num_segments;
    for (var r = 0; r < num_rings; r++) {
        for (var s = 0; s < num_segments; s++) {
            var angle = Math.PI * 2 * (s / num_segments);
            var x = Math.cos(angle) * radius;
            var y = Math.sin(angle) * radius;
            verts.push(new THREE.Vector3(x, y, z));
            speeds.push(Math.random());
            phases.push(Math.random());
            z += dz;
        }
    }
}
init_verts();
function update_verts(t) {
    var d = num_rings * 0.4;
    var v = 0;
    for (var r = 0; r < num_rings; r++) {
        for (var s = 0; s < num_segments; s++) {
            if (r > d) {
                var p = 0.5 + 0.5 * Math.sin(t*speeds[v] + phases[v])
                var q = (r-d)/d * 1.1;
                var rad = (1-p * q) * radius;
                var angle = Math.PI * 2 * (s / num_segments);
                var x = Math.cos(angle) * rad;
                var y = Math.sin(angle) * rad;
                var vert = verts[v];
                vert.x = x;
                vert.y = y;
            }
            v++;
        }
    }
}
update_verts(0);

function mkgeometry(geometry) {
    var fi = 0;
    var f = 0;
    var vi = 0;
    var v = 0;
    var x = 0, y = 0, z = 0;
    var dz = -depth_step / num_segments;
    var c = 0;
    for (var r = 0; r < num_rings; r++) {
        for (var s = 0; s < num_segments; s++) {
            var vert1 = verts[vi];
            var vert2 = vi - 1 >= 0 ? verts[vi - 1] : verts[0];
            var vert3 = vi - num_segments >= 0 ? verts[vi - num_segments] : verts[0];
            var vert4 = vi - num_segments - 1 >= 0 ? verts[vi - num_segments - 1] : verts[0];
            vi++;
            
            geometry.vertices[v++] = vert1;
            geometry.vertices[v++] = vert2;
            geometry.vertices[v++] = vert4;
            geometry.faces[f++] = new THREE.Face3(fi, fi+1, fi+2, null, colors[c++]);
            fi += 3;
            geometry.vertices[v++] = vert1;
            geometry.vertices[v++] = vert4;
            geometry.vertices[v++] = vert3;
            geometry.faces[f++] = new THREE.Face3(fi, fi+1, fi+2, null, colors[c++]);
            fi += 3;
            old_x = x;
            old_y = y;
            old_z = z;
            z += dz;
        }
    }
    geometry.verticesNeedUpdate = true;
    geometry.colorsNeedUpdate = true;
    geometry.elementsNeedUpdate = true;
}
mkgeometry(geometry);
var material = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors, color: background_color });
material.depthFunc = THREE.AlwaysDepth;
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

var s = 0;
var total_s = 0;
var first_time = true;
var animate = function () {
    //console.log("updating background");
    update_size();
    delta_time = clock.getDelta();
    elapsed_time = clock.elapsedTime;

    var win = $(window);
    var prev_s = s;
    s = $(window).scrollTop();
    var ds = Math.abs(s - prev_s);
    camera.position.z = -s/outer_h*(num_rings * depth_step);
    //var color;
    //color = new THREE.Color("#efefef");
    //if (s > content_h) {
    //    if (s > content_h + 1000) {
    //        color = new THREE.Color(1, 1, 1);
    //    } else {
    //        var q = (s - content_h) / 1000;
    //        //color = new THREE.Color(r + (1-r) * q, g + (1-g) * q, b + (1-b) * q);
    //        color = new THREE.Color();
    //        color.setHSL(0, 0.5, q * 0.6 + 0.4);
    //    }
    //} else {
    //    var q = (content_h-s) / content_h;
    //    color = new THREE.Color();
    //    color.setHSL(q, 0.5, 0.4);
    //}
    //material.color = color;
    if (ds > 0 || first_time) {
        total_s += ds * 0.01;
        update_colors(ds * 0.00001, s);
        update_verts(total_s);
        mkgeometry(mesh.geometry);
        first_time = false;
    }
    renderer.render(scene, camera);
    requestAnimationFrame( animate );
};
animate();
//setInterval(animate, 500); // backup as sometimes requestAnimationFrame doesn't trigger in Firefox