function v_(x,y,z) { return {x:x||0.0,y:y||0.0,z:z||0.0}; }
function v_copy(a) { return {x:a.x,y:a.y,z:a.z}; }
function v_add(a,b) { return {x:a.x+b.x,y:a.y+b.y,z:a.z+b.z}; }
function v_sub(a,b) { return {x:a.x-b.x,y:a.y-b.y,z:a.z-b.z}; }
function v_mul(a,n) { return {x:a.x*n,y:a.y*n,z:a.z*n}; }
function v_div(a,n) { return {x:a.x/n,y:a.y/n,z:a.z/n}; }
function v_lens(a) { return a.x*a.x+a.y*a.y+a.z*a.z; }
function v_len(a) { return Math.sqrt(v_lens(a)); }
function v_hat(a) { return v_div(a,v_len(a)); }

var SCALE = 800.0;
var BOUNDS;

function docWidth() {
  if(window.innerWidth) return window.innerWidth;
  if(document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth;
  if(document.body && document.body.clientWidth) return document.body.clientWidth;
  if(document.width && document.width > 100) return document.width;
  return 1024;
}

function docHeight() {
  if(window.innerHeight) return window.innerHeight;
  if(document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight;
  if(document.body && document.body.clientHeight) return document.body.clientHeight;
  if(document.height && document.height > 100) return document.height;
  return 700;
}

function ballSetup(n) {
  n = Math.floor(n); if(n < 1) n = 1;
  BOUNDS = new Bounds(v_(0,0),v_(docWidth(),docHeight()),0.9);
  for(var i = 0; i < n; i += 1) {
    var ball = new Ball(v_(10,10),v_mul(v_(2+i,1+i),SCALE),v_mul(v_(0,9.8),SCALE),v_(100,100),BOUNDS);
    makeDraggable(ball,ball.img);
    ball.go();
  }
  setInterval(function(){BOUNDS.max=v_(docWidth(),docHeight())},250);
}

function nodeHasParent(elem,parent) {
  while(elem.parentNode) {
    if(elem == parent) return true;
    elem = elem.parentNode;
  }
  return false;
}

function makeDraggable(o,t) {
  if(!o || !t) return;
  var oldp,oldw;
  var newp,neww;
  var lastp,lastw;
  var offset,touch;
  var md = function(p) {
    oldp = null; oldw = null;
    newp = null; neww = null;
    lastp = null; lastw = null;
    offset = v_sub(p,v_(o.x.x,o.x.y));
    o.active = false;
  };
  var mm = function(p) {
    if(!offset) return;
    lastp = v_copy(p);
    lastw = (new Date()).getTime();
    if(!neww || lastw-neww > 250) {
      oldp = newp; oldw = neww;
      newp = lastp; neww = lastw;
    }
    o.x = v_sub(lastp,offset);
    if(oldp) o.v = v_mul(v_div(v_add(lastp,oldp),(lastw-oldw)/1000.0),3.0);
  };
  var mu = function(p) {
    o.active = true;
    if(!offset) return;
    offset = null;
    var pt = v_copy(p);
    var now = (new Date()).getTime();
    if(newp && now-neww > 250) { oldp = newp; oldw = neww; }
    if(lastp && now-lastw > 250) { oldp = lastp; oldw = lastw; }
    if(oldp) o.v = v_mul(v_div(v_sub(pt,oldp),(now-oldw)/1000.0),3.0);
    oldp = null; oldw = null;
    newp = null; neww = null;
    lastp = null; lastw = null;
  };
  window.addEventListener('mousedown',function(e){
      if(!e || !e.target) return;
      if(!nodeHasParent(e.target,t)) return;
      e.preventDefault();
      md(v_(e.pageX,e.pageY));
    },false);
  window.addEventListener('mousemove',function(e){
      if(!e || !offset) return;
      e.preventDefault();
      mm(v_(e.pageX,e.pageY));
    },false);
  window.addEventListener('mouseup',function(e){
      e.preventDefault();
      mu(v_(e.pageX,e.pageY));
    },false);
  document.body.addEventListener('touchstart',function(e){
      if(!e || !e.touches || e.touches.length != 1) return;
      e.preventDefault();
      if(!nodeHasParent(e.target,t)) return;
      touch = e.touches[0];
      md(v_(touch.screenX,touch.screenY));
    },false);
  document.body.addEventListener('touchmove',function(e){
      //if(!e || !e.touches || e.touches.length < 1) return;
      e.preventDefault();
      if(!offset || !touch) return;
      mm(v_(touch.screenX,touch.screenY));
    },false);
  document.body.addEventListener('touchend',function(e){
      //if(!e || !e.touches || e.touches.length < 1) return;
      e.preventDefault();
      if(!offset || !touch) return;
      //var touch = e.touches[0];
      mu(v_(touch.screenX,touch.screenY));
    },false);
  window.addEventListener('gesturestart',function(e){if(e)e.preventDefault()},false);
  window.addEventListener('gesturechange',function(e){if(e)e.preventDefault()},false);
  window.addEventListener('gestureend',function(e){if(e)e.preventDefault()},false);
}

function Ball(x,v,a,size,world) {
  this.x = x;
  this.v = v;
  this.a = a;
  this.size = size;
  this.world = world;
  this.active = true;
  this.img = new Image();
  this.go = function() {
    var ball = this;
    setInterval(function(){ball.update(0.01);},10);
    //setInterval(function(){ball.update(0.05);},50);
  }
  this.update = function(t) {
    if(this.active) {
      this.v = v_add(this.v,v_mul(this.a,t));
      this.x = v_add(this.x,v_mul(this.v,t));
    }
    this.world.apply(this);
    this._redraw();
  }
  this._redraw = function() {
    if(!this.img.src) {
      this.img.src = 'redball.png';
      this.img.style.position = 'absolute';
      document.body.appendChild(this.img);
    }
    this.img.style.left = ""+Math.floor(this.x.x)+"px";
    this.img.style.top = ""+Math.floor(this.x.y)+"px";
  }
}

function Bounds(min,max,damp) {
  this.min = min;
  this.max = max;
  this.damp = damp;
  this.apply = function(o) {
    if(o.x.x >= this.max.x-o.size.x) {
      o.x.x = this.max.x-o.size.x;
      if(o.v.x > 0.0) o.v.x = -this.damp*o.v.x;
    }
    if(o.x.x <= this.min.x) {
      o.x.x = this.min.x;
      if(o.v.x < 0.0) o.v.x = -this.damp*o.v.x;
    }
    if(o.x.y >= this.max.y-o.size.y) {
      o.x.y = this.max.y-o.size.y;
      if(o.v.y > 0.0) o.v.y = -this.damp*o.v.y;
    }
    if(o.x.y <= this.min.y) {
      o.x.y = this.min.y;
      if(o.v.y < 0.0) o.v.y = -this.damp*o.v.y;
    }
    if(o.x.z >= this.max.z-o.size.z) {
      o.x.z = this.max.z-o.size.z;
      if(o.v.z > 0.0) o.v.z = -this.damp*o.v.z;
    }
    if(o.x.z <= this.min.z) {
      o.x.z = this.min.z;
      if(o.v.z < 0.0) o.v.z = -this.damp*o.v.z;
    }
  }
}

