function addClass(elm, c) {
    var classes = elm.className.split(" ");
    for (var i = 0; i < classes.length; i++) {
        if (classes[i] == c)
            return;
    }
    classes.push(c);
    elm.className = classes.join(" ");
}

function removeClass(elm, c) {
    var classes = elm.className.split(" ");
    var idx = -1;
    while ((idx = classes.indexOf(c)) > -1) {
        classes.splice(idx, 1);
    }
    elm.className = classes.join(" ");
}

function containsClass(elm, c) {
    return elm.className.split(" ").indexOf(c) > -1;
}

var staticImages = [
  "5748992018",
  "2959749019",
  "5882523347",
  "3022936492"
];

var NUM_STATIC_IMAGES = staticImages.length;
var NUM_DYNAMIC_IMAGES_PER_STATIC = 4;

var imagesElm;
var wrapperElm;
var imagesWidth;
var wrapperWidth;
var wrapperTop;
var wrapperHeight;
var firstMenu;
var selected = [];

function init(results) {
  imagesElm = document.getElementById("images");
  wrapperElm = document.getElementById("images-wrapper");

  // Find the image details for each of the static images.
  for (var i = 0; i < staticImages.length; i++) {
    for (var j = 0; j < images.length; j++) {
      if (images[j].file.split(".")[0] == staticImages[i]) {
        staticImages[i] = images.splice(j, 1)[0];
        break;
      }
    }
  }

  // Create the set of images to display. It will be mostly randomly
  // selected from the images array, but with some static images mixed
  // in every so often. The static images are needed so that we are
  // guaranteed to have at least one image for each of the links.
  while (staticImages.length) {
    selected.push(staticImages.shift());
    for (var i = 0; i < NUM_DYNAMIC_IMAGES_PER_STATIC; i++) {
      selected.push(results.splice(
          Math.floor(Math.random() * results.length), 1)[0]);
    }
  }

  for (var i = 0, item; item = selected[i]; i++) {
    addImage(item);
  }
}

function addImage(item) {
  var img = new Image();
  img.onload = handleImageLoad;
  if (item.tags) {
    img.className = item.tags.replace('aaronboodman', 'aaron')
                             .replace('susanlau', 'susan');
  }
  if (!item.file) throw new Error(item);
  img.src = "homepage/images/" + item.file;
  item.img = img;
}

function handleImageLoad() {
  this.loaded = true;
  for (var i = 0; i < selected.length; i++) {
    if (!selected[i].img.loaded)
      return;
    imagesElm.appendChild(selected[i].img);
  }
  initImages();
}

function initImages() {
  imagesWidth = imagesElm.offsetWidth;
  wrapperWidth = wrapperElm.offsetWidth;
  wrapperTop = wrapperElm.offsetTop;
  wrapperBottom = wrapperTop + wrapperElm.offsetHeight;
  wrapperLeft = wrapperElm.offsetLeft;
  wrapperWidth = wrapperElm.offsetWidth;

  window.addEventListener("mousemove", handleMouseMove, false);
}

var imagesAnimation = {
  lastTimestamp: 0,
  destination: null,
  running: false,
  zip: 1.25,
  minPxPerMs: null,
  maxPxPerMs: null,

  setDestination: function(dest, min, max) {
    this.minPxPerMs = min;
    this.maxPxPerMs = max;
    var maxDistance = imagesWidth - wrapperWidth;
    this.accel =
        (this.maxPxPerMs - this.minPxPerMs) / Math.pow(maxDistance, this.zip);

    this.destination = dest;
    if (!this.running)
      this.start();
  },

  start: function() {
    this.running = true;
    this.lastTimestamp = new Date().getTime();
    this.schedule();
  },

  stop: function() {
    this.running = false;
  },

  schedule: function() {
    function callback(timestamp) {
      imagesAnimation.frame(timestamp);
    }

    if (window.webkitRequestAnimationFrame)
      webkitRequestAnimationFrame(callback, imagesElm);
    else if (window.mozRequestAnimationFrame)
      mozRequestAnimationFrame(callback);
    else
      window.setTimeout(function() { callback(new Date().getTime()) }, 5);
  },

  frame: function(timestamp) {
    if (!this.running)
      return;

    var current = parseFloat(imagesElm.style.left);
    var distance = Math.abs(current - this.destination);
    var speed = this.accel * Math.pow(distance, this.zip) + this.minPxPerMs;
    var elapsed = timestamp - this.lastTimestamp;
    var step = Math.min(distance, speed * elapsed);

    if (this.destination < current)
      step = -step;

    imagesElm.style.left = current + step + "px";

    if (Math.round(imagesElm.style.left) == this.destination) {
      this.stop();
      return;
    }

    this.lastTimestamp = timestamp;
    this.schedule();
  }
};

function handleMouseMove(e) {
  if (e.pageY < wrapperTop || e.pageY > wrapperBottom) {
    // imagesAnimation.stop();
    return;
  }

  var position = e.pageX - wrapperLeft;
  position = Math.max(0, Math.min(position, wrapperWidth));

  var percent = position / wrapperWidth;
  var offset = (imagesWidth - wrapperWidth) * percent;

  imagesAnimation.setDestination(-offset, 0.2, 10);
}

function animateTo(pos, time) {
  // If we're scrolling, don't do anything.
  if (Accelimation.instances.length)
    return;

  imagesAnimation.setDestination(pos, 0.75, 50);
}

var direction = true;
function animateToTag(tag) {
  // Find the current left-most image index
  var pos = -parseInt(imagesElm.style.left);
  var images = imagesElm.getElementsByTagName("img");
  for (var i = 0; i < images.length; i++) {
    if (pos >= images[i].offsetLeft &&
        pos < (images[i].offsetLeft + images[i].offsetWidth)) {
      var currentImage = i;
      break;
    }
  }

  if (direction) {
    for (i = currentImage + 1; i < images.length; i++) {
      if (containsClass(images[i], tag)) {
        animateTo(-images[i].offsetLeft, 250);
        return;
      }
    }
    direction = false;
    animateToTag(tag);
    return;
  }

  for (i = currentImage - 1; i >= 0; i--) {
    if (containsClass(images[i], tag)) {
      animateTo(-images[i].offsetLeft, 250);
      return;
    }
  }
  direction = true;
  animateToTag(tag);
}

function switchTab(menu, dest) {
  var currentMenu = document.querySelector('#menu a.active');
  var currentTab = document.querySelector('.tab.active');

  if (currentMenu) {
    removeClass(currentMenu, "active");
    removeClass(currentTab, "active");
  }

  if (menu != currentMenu) {
    addClass(menu, "active");
    addClass(document.getElementById(dest), "active");

    addClass(document.body, "tab-open");
    resetFirstTabOpen();

    var top = document.getElementById("top");
    document.body.style.minHeight =
        top.offsetHeight + window.innerHeight + "px";
    if (!currentMenu)
      scrollTo(top.offsetTop + top.offsetHeight);
  } else {
    removeClass(document.body, "tab-open");

    // hack: WebKit doesn't update the hover state when the menu moves under the
    // mouse, so we have to force it.
    addClass(menu, "force-no-hover");
    window.addEventListener("mousemove", function() {
      removeClass(menu, "force-no-hover");
      window.removeEventListener("mousemove", arguments.callee, false);
    }, false);

    scrollTo(0, function() {
      document.body.style.minHeight = "";
    });
  }

  return false;
}

function resetFirstTabOpen() {
  if (containsClass(firstMenu, "active"))
    addClass(document.body, "first-tab-open");
  else
    removeClass(document.body, "first-tab-open");
}

var scrollAnimation;
function scrollTo(pos, onEnd) {
  if (imagesAnimation)
    imagesAnimation.stop();

  if (scrollAnimation)
    scrollAnimation.stop();

  var elm = navigator.userAgent.toLowerCase().indexOf("webkit") > -1 ?
      document.body : document.documentElement;
  scrollAnimation = new Accelimation(elm, "scrollTop", pos, 200, 0.4, "");
  scrollAnimation.onend = onEnd;
  scrollAnimation.start();
}

