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 GRAV_CONST = 6.67e-1;
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 fleeSetup(n) {
  n = Math.floor(n); if(n < 1) n = 1;
  var w = docWidth(); var h = docHeight();
  BOUNDS = new Bounds(v_(0,0),v_(w,h),0.9);
  var world = new World(BOUNDS);
  for(var i = 0; i < n; i += 1) {
    var fleer = new Fleer(v_(Math.floor(w/2.0+50.0*Math.random()-25.0),Math.floor(h/2.0+50.0*Math.random()-25.0)),v_(0,0),v_(0,0),10.0,v_(25,25),world);
  }
  var mouse = Mouse(2000.0,world);
  world.go();
  window.world = world;
  setInterval(function(){BOUNDS.max=v_(docWidth(),docHeight())},250);
}

function Mouse(m,world) {
  this.x = v_(0,0);
  this.v = v_(0,0);
  this.a = v_(0,0);
  this.size = v_(0,0);
  this.m = m;
  this.world = world;
  this.update = function(t) { }
  window.addEventListener('mousemove',function(e) {
      this.x = v_(e.pageX,e.pageY);
    },false);
  this.world.add(this);
}

function Fleer(x,v,a,m,size,world) {
  this.x = x;
  this.v = v;
  this.a = a;
  this.m = m;
  this.size = size;
  this.world = world;
  this.active = true;
  this.img = new Image();
  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 = 'planet.gif';
      this.img.style.position = 'absolute';
      document.body.appendChild(this.img);
    }
    this.img.style.left = ""+Math.floor(this.x.x-this.size.x/2.0)+"px";
    this.img.style.top = ""+Math.floor(this.x.y-this.size.y/2.0)+"px";
  }
  this.world.add(this);
}

function World(bounds) {
  this.bounds = bounds;
  this.objects = new Array();
  this.add = function(o) {
    this.objects[this.objects.length] = o;
  }
  this.go = function() {
    var world = this;
    //setInterval(function(){world.update(0.01);},10);
    setInterval(function(){world.update(0.05);},50);
  }
  this.update = function(t) {
    this.recalc();
    for(var i = 0; i < this.objects.length; i++) {
      this.objects[i].update(t);
    }
  }
  this.apply = function(o) {
    this.bounds.apply(o);
  }
  this.recalc = function(o) {
    for(var i = 0; i < this.objects.length; i++) { this.objects[i].a = v_(0,0); }
    for(var i = 0; i < this.objects.length; i++) {
      for(var h = i+1; h < this.objects.length; h++) {
        var r = v_sub(this.objects[i].x,this.objects[h].x);
        var l = (v_lens(r)+5.0);
        if(l > 0.0) {
          //var f = v_mul(v_div(r,l*Math.sqrt(l)),GRAV_CONST);
          var f = v_mul(v_div(r,l),GRAV_CONST);
          this.objects[i].a = v_add(this.objects[i].a,v_mul(f,this.objects[h].m));
          this.objects[h].a = v_add(this.objects[h].a,v_mul(f,-this.objects[i].m));
        }
      }
    }
  }
}

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/2.0) {
      o.x.x = this.max.x-o.size.x/2.0;
      if(o.v.x > 0.0) o.v.x = -this.damp*o.v.x;
    }
    if(o.x.x <= this.min.x+o.size.x/2.0) {
      o.x.x = this.min.x+o.size.x/2.0;
      if(o.v.x < 0.0) o.v.x = -this.damp*o.v.x;
    }
    if(o.x.y >= this.max.y-o.size.y/2.0) {
      o.x.y = this.max.y-o.size.y/2.0;
      if(o.v.y > 0.0) o.v.y = -this.damp*o.v.y;
    }
    if(o.x.y <= this.min.y+o.size.y/2.0) {
      o.x.y = this.min.y+o.size.y/2.0;
      if(o.v.y < 0.0) o.v.y = -this.damp*o.v.y;
    }
    if(o.x.z >= this.max.z-o.size.z/2.0) {
      o.x.z = this.max.z-o.size.z/2.0;
      if(o.v.z > 0.0) o.v.z = -this.damp*o.v.z;
    }
    if(o.x.z <= this.min.z+o.size.z/2.0) {
      o.x.z = this.min.z+o.size.z/2.0;
      if(o.v.z < 0.0) o.v.z = -this.damp*o.v.z;
    }
  }
}

