// Paul Irish's animation frame polyfill
window.requestAnimFrame = (function () {
  return window.requestAnimationFrame       ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame    ||
    window.oRequestAnimationFrame      ||
    window.msRequestAnimationFrame     ||
    function (callback) {
      window.setTimeout(callback, 1000 / 60);
    };
}());

// Larixk's voronoi drawing thingy based on Raymond Hill's work
(function () {
  var voronoi =  new Voronoi(), // External magic by Raymond Hill
    canvas = document.getElementById('voronoi'),
    ctx = canvas.getContext('2d'),
    palet = [
      '#ca0043',
      '#012840',
      '#012840',
      '#5d8aa6',
      '#5d8aa6',
      '#ffffff',
      '#ffffff'
    ], // Colors used
    speed = 10,
    minAmount = 3,
    maxAmount = 500,
    amount, // Number of sites
    sites, // All of the points
    bounds,
    mouseSite;

  // Randomly throw up n points with a color and direction
  function generatePoints(n) {
    var i;
    sites = [];

    for (i = 0; i < n; i += 1) {
      sites.push({
        // Random position on the canvas
        x: Math.random() * canvas.width,
        y: Math.random() * canvas.height,
        // Random color from the palet
        c: palet[Math.floor(Math.random() * palet.length)],
        // Random direction in dx, dy (pixels per iteration)
        dx: (Math.random() - 0.5) * speed,
        dy: (Math.random() - 0.5) * speed
      });
    }
  }

  // Move the sites and bounce off the walls
  function updateSites() {
    var n = sites.length,
      i,
      site;

    for (i = 0; i < n; i += 1) {
      site = sites[i];

      site.x += site.dx;
      site.y += site.dy;

      // Stepping out of line?
      if (site.x > bounds.xr || site.x < 0) {
        // Turn around
        site.dx *= -1;
        site.x += site.dx;
      }

      // Stepping out of line?
      if (site.y > bounds.yb || site.y < 0) {
        // Turn around
        site.dy *= -1;
        site.y += site.dy;
      }
    }
  }

  // Iteration, updates positions and draws
  function render() {
    updateSites();

    var totalSites = sites.concat([mouseSite]),
      diagram = voronoi.compute(totalSites, bounds),
      i,
      j,
      v,
      site,
      cell,
      halfedges,
      length;

    // Calculating f-ed up?
    if (!diagram) {
      return;
    }

    // Get all the pretty shapes
    for (i = 0; i < amount + 1; i += 1) {
      site = totalSites[i];
      cell = diagram.cells[site.voronoiId];

      halfedges = cell.halfedges;
      length = halfedges.length;

      // Fewer than three points connected? Won't be visible
      if (length <= 2) {
        continue;
      }

      // Drawing
      ctx.beginPath();
      ctx.fillStyle = site.c;
      for (j = 0; j < length; j += 1) {
        v = halfedges[j].getEndpoint();
        ctx.lineTo(v.x, v.y);
      }
      ctx.closePath();
      ctx.fill();
    }

    // Go again
    window.requestAnimFrame(render);
  }

  // Start or restart
  function build() {
    // Fill the screen with canvas
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;

    // Make sure we tell the voronoi
    bounds = {
      xl: 0,
      xr: canvas.width,
      yt: 0,
      yb: canvas.height
    };

    // Starting positions
    amount = minAmount + Math.pow(Math.random(), 5) * (maxAmount - minAmount);
    generatePoints(amount);
  }

  function setMouseSite(x, y) {
    mouseSite = {
      x: x,
      y: y,
      c: palet[0]
    };
  }

  function mousemove(ev) {
    var x, y;

    // Crossbrowser mouse position.
    if (ev.offsetX || ev.offsetX === 0) {
      x = ev.offsetX;
      y = ev.offsetY;
    } else if (ev.layerX || ev.layerX === 0) {
      x = ev.layerX;
      y = ev.layerY;
    }

    setMouseSite(x, y);
  }

  // Start or restart
  function init() {
    window.onresize = build; // Look ma, no jQuery
    build();
    setMouseSite(0, 0);
    document.addEventListener('mousemove', mousemove, false);

    render();
  }

  // Leggo!
  init();
}());

