(function () {
  //DOM loaded
  doodle.ready(function () {
    var w = get_display_width(),   //screen size up to 600
        h = get_display_height(), //screen size up to 480
        display = doodle.createDisplay("#display", {layers:1, frameRate:20, width:w, height:h}),
        balls = [],
        numBalls = 5,
        i = 0;
    //populate
    for (; i < numBalls; i++) {
      balls.push(createBall(w, h).appendTo(display.layers[0]));
    }
    //event loop
    display.on(doodle.events.Event.ENTER_FRAME, function () {
      var ball,
          ballA,
          ballB,
          i = 0,
          j;
      //update ball position, check wall collision
      for (; i < numBalls; i++) {
        ball = balls[i];
        ball.x += ball.vx;
        ball.y += ball.vy;
        checkWalls(ball, w, h);
      }
      //check ball collision
      for (i=0; i < numBalls - 1; i++) {
        ballA = balls[i];
        for (j=i+1; j < numBalls; j++) {
          ballB = balls[j];
          checkCollision(ballA, ballB);
        }
      }
    });
  });

  function createBall (max_x, max_y) {
    return doodle.createSprite(function () {
      this.color = "#000000";
      this.x = Math.random() * max_x;
      this.y = Math.random() * max_y;
      this.vx = Math.random() * 10 - 5;
      this.vy = Math.random() * 10 - 5;
      this.mass = this.radius = 20;
      
      this.graphics.beginFill(this.color);
      this.graphics.circle(0, 0, this.radius);
      this.graphics.endFill();

      this.randomColor = function () {
        this.color = "#" + Math.floor(Math.random() * 0xFFFFFF).toString(16);
        this.graphics.clear();
        this.graphics.beginFill(this.color);
        this.graphics.circle(0, 0, this.radius);
        this.graphics.endFill();
      };
    });
  }

  function checkWalls (ball, width, height) {
    if (ball.x + ball.radius > width) {
      ball.x = width - ball.radius;
      ball.vx *= -1; //bounce = -1
    } else if (ball.x - ball.radius < 0) {
      ball.x = ball.radius;
      ball.vx *= -1;
    }
    if (ball.y + ball.radius > height) {
      ball.y = height - ball.radius;
      ball.vy *= -1;
    } else if (ball.y - ball.radius < 0) {
      ball.y = ball.radius;
      ball.vy *= -1;
    }
  }

  function checkCollision (ball0, ball1) {
    var dx = ball1.x - ball0.x,
        dy = ball1.y - ball0.y,
        dist = Math.sqrt(dx*dx + dy*dy),
        angle,
        sin,
        cos,
        pos0,
        pos1,
        vel0,
        vel1,
        vxTotal,
        absV,
        overlap,
        pos0F,
        pos1F,
        vel0F,
        vel1F;
    //collision handling code here
    if(dist < ball0.radius + ball1.radius) {
      //calculate angle, sine, and cosine
      angle = Math.atan2(dy, dx);
      sin = Math.sin(angle);
      cos = Math.cos(angle);
      //rotate ball0's position
      pos0 = {x:0, y:0}; //point
      //rotate ball1's position
      pos1 = rotate(dx, dy, sin, cos, true);
      //rotate ball0's velocity
      vel0 = rotate(ball0.vx, ball0.vy, sin, cos, true);
      //rotate ball1's velocity
      vel1 = rotate(ball1.vx, ball1.vy, sin, cos, true);
      //collision reaction
      vxTotal = vel0.x - vel1.x;
      vel0.x = ((ball0.mass - ball1.mass) * vel0.x +
                2 * ball1.mass * vel1.x) / (ball0.mass + ball1.mass);
      vel1.x = vxTotal + vel0.x;
      //update position - to avoid objects becoming stuck together at times
      absV = Math.abs(vel0.x) + Math.abs(vel1.x);
      overlap = (ball0.radius + ball1.radius) - Math.abs(pos0.x - pos1.x);
      pos0.x += vel0.x / absV * overlap;
      pos1.x += vel1.x / absV * overlap;
      //rotate positions back
      pos0F = rotate(pos0.x, pos0.y, sin, cos, false);
      pos1F = rotate(pos1.x, pos1.y, sin, cos, false);
      //adjust positions to actual screen positions
      ball1.x = ball0.x + pos1F.x;
      ball1.y = ball0.y + pos1F.y;
      ball0.x = ball0.x + pos0F.x;
      ball0.y = ball0.y + pos0F.y;
      //rotate velocities back
      vel0F = rotate(vel0.x, vel0.y, sin, cos, false);
      vel1F = rotate(vel1.x, vel1.y, sin, cos, false);
      
      ball0.vx = vel0F.x;
      ball0.vy = vel0F.y;
      ball1.vx = vel1F.x;
      ball1.vy = vel1F.y;

      ball0.randomColor();
      ball1.randomColor();
    }
  }

  function rotate (x, y, sin, cos, reverse) {
    var result =  {}; //point
    if (reverse) {
      result.x = x * cos + y * sin;
      result.y = y * cos - x * sin;
    } else {
      result.x = x * cos - y * sin;
      result.y = y * cos + x * sin;
    }
    return result;
  }

  function get_display_width () {
    var x = 0;
    if (window.innerHeight) {
      x = window.innerWidth;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      x = document.documentElement.clientWidth;
    } else if (document.body) {
      x = document.body.clientWidth;
    }
    return Math.min(x, 400);
  }

  function get_display_height() {
    var y = 0;
    if (window.innerHeight) {
      y = window.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) {
      y = document.documentElement.clientHeight;
    } else if (document.body) {
      y = document.body.clientHeight;
    }
    return y;
  }
  
}());

