define(["three"], function(THREE) {
  var Util = {
    // Linear interpolation of t [0, 1] over [a, b]
    lerp: function(a, b, t) {
      return (1-t)*a + t*b;
    },

    randomEuler: function(random) {
      randFn = random? random.next : Math.random;

      return new THREE.Euler(
        randFn() * Util.PI2,
        randFn() * Util.PI2,
        randFn() * Util.PI2
        );
    },

    randomVec3: function(random) {
      var vec = new THREE.Vector3(
          random.next(-1, 1),
          random.next(-1, 1),
          random.next(-1, 1)
        ).normalize();

      return vec;
    },

    clamp: function(n, a, b) {
      return Math.max(a, Math.min(n, b));
    },

    lerp: function(n, a, b) {
      return (1 - n) * a + n * b;
    },

    map: function(t, a, b, c, d) {
      return (t - a) / (b - a) * (d-c) + c;
    },

    beatsToTime: function(tempo, musicTime) {
        var bars = musicTime.bars || 0;
        var beats = musicTime.beats || 0;
        var eights = musicTime.eights || 0;
        var sixteenths = musicTime.sixteenths || 0;

        var beatTime = 60 / tempo;

        var totalTime =
            (bars * beatTime * 4) +
            (beats * beatTime) +
            (eights * beatTime / 2) +
            (sixteenths * beatTime / 4);

        return totalTime;
    },

    PI2: 2 * Math.PI
  };

  Number.prototype.clamp = function(min, max) {
    return Math.min(Math.max(this, min), max);
  };

  return Util;
})