(function game() {
  var screen = document.getElementById('screen');
  var unitlist = new LinkedList();
  var levelarray = [
  [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
  [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
  [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
  [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
  [1,0,1,0,0,0,0,0,0,1,1,0,1,1,1,0,0,1,1,1,1],
  [1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1],
  [1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1],
  [1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1],
  [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1],
  [1,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1],
  [1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1],
  [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
  ];
  var blockarray = [[],[],[],[],[],[],[],[],[],[],[],[]];
  
  var time = new Date().getTime();
  var lastupdatetime = new Date().getTime();
  var lastrendertime = new Date().getTime();
  var lastframetime = new Date().getTime();
  var updatedelay = 1000/50;
  var renderdelay = 1000/60;
  var framecount = 0;
  var timer = setInterval(cycle,0);
  
  var GRAVITY = 0.7;

  var player;

  function cycle() {
    lastcycletime = time;
    time = new Date().getTime(); //We use a static decided time per game cycle, instead of getting the time over and over each time we need it
    var cycleupdate = true; //We use this variable to determine if this cycle has the update function run. If not, then no point in updating the grapics
    while(time > lastupdatetime+updatedelay) {lastupdatetime+=updatedelay; cycleupdate=true; lastupdatetime = time; update();} //We run the update function many times if we are slowing after desired update rate
    if (cycleupdate && time > lastrendertime+renderdelay) {framecount++; lastrendertime = time; render();} //We don't run the grapic function many times. That's a waste, instead, we run it max once per game cycle, if at all
  }
  function update() {
    updateplayer(); //Here are all the controls applied
    var foreach = unitlist.first; while(foreach) { //We loop though each unit
      foreach.value.update(); //Call upon the update function for the unit. The update function do things like move the unit according to it's speed and test for collisions
    foreach = foreach.next;}
  }
  function render() {
    if (time > lastframetime + 1000) {
      //document.title = framecount;
      lastframetime = time;
      framecount = 0;
    }
    var foreach = unitlist.first; while(foreach) { //We loop though each unit
      foreach.value.draw(); //Call upon the drawing function for the unit
    foreach = foreach.next;}
  }
  function drawworld() { //This function just loops though the map and draws it.
    for(var x = 0; x < levelarray.length; x++) {
      for(var y = 0; y < levelarray[x].length; y++) {
        if (levelarray[x][y] == 1) {
          blockarray[x][y] = new Block(y,x);
	}
      }
    }
  }
  function Block(x,y) { //This is a quick hack object for the tiles
    var element = new Image();
    element.src = 'block.png';
    element.style.position = 'absolute';
    element.style.left = x * 32;
    element.style.top = y * 32;
    screen.appendChild(element);
  }
  function activateunit(unit) { //Activating a unit means it gets added to the unitlist which makes it have game physics, and appends it's element to the html document
    unitlist.add(unit); //Native function to the LinkedList
    screen.appendChild(unit.element);
  }
  function deactivateunit(unit) { //The reverse opposite of the activateunit functino
    unitlist.removebyobject(unit);
    screen.removeChild(unit.element);
  }
  function UnitBlueprint(data) { //We use blueprints for units to make mass producing of units easier
    this.xblocksize = data.xblocksize;
    this.yblocksize = data.yblocksize;
  }
  function Unit(blueprint,data) { //The blueprint is used to gain genetic data for the unit, like size. The data is used for dynamic data, like position.
    this.element = document.createElement('div');//new Image();
    this.element.style.backgroundColor = 'red';
    this.element.style.position = 'absolute';
    this.xblocksize = blueprint.xblocksize;
    this.yblocksize = blueprint.yblocksize;
    this.x = data.x;
    this.y = data.y;
    this.h = this.yblocksize*32;
    this.w = this.xblocksize*32;
    this.cx;this.cy;this.ch;this.cw; //duplicated cache current position of the element to avoid unecessary DOM changes
    this.xspeed = 0;
    this.yspeed = 0;
  }
  Unit.prototype.update = function() {
    /* We do vertical and horizontal movement separate as two steps to avoid one really nasty bug where the unit skips into a wall when they are in a corner */
    var x1,x2,x3,y1,y2,y3, i; //since we need to check a lot of directions, we simply reuse these local variables which gives us the possibility to reuse results
    // >>5 is the same as / 32
    
    /* we apply the vertical movement and collision checks */
    this.y+=this.yspeed;
    x1 = (this.x+6)>>5; //We with a bias of 6 pixels to avoid having a character standing on the very last pixel of an edge
    x2 = (this.x+30)>>5; //We test the collision of each block twice to avoid making the block as thin as a nedlee when it comes to collisions
    y1 = (this.y+this.h)>>5; //We take the y position of the unit, add the height of the unit, to get the position of the unit's feet
    var touchfloor;
    i = this.xblocksize-1; //If the unit is more than 1 block thick in width, then we need to check the collision possibilities for each block
    do {
      if(levelarray[y1][x1+i] || levelarray[y1][x2+i]) { //Again, we test the collision of each block of the unit twice. Otherwise, the percived collision size of a block is no thicker than a needle
        touchfloor = true; //The unit touched the floor! Remember this!
      }
    } while (i--) //This is just a fancy replacement for a FOR loop, that's slightly faster
    if (touchfloor) { //This unit is touching the floor, so we need to stop it from falling
      this.y = (y1-this.yblocksize)<<5; //Doing the whole >>5 <<5 thing snaps the position to a 32 pixel wide grind, making the collision result seem very smooth and not bumpy
      this.yspeed = 0; //If the unit is touching the floor, it obviously loses it's falling speed
      if(this.xspeed>0) {this.xspeed--;} //Movement slows down if we are touching the ground
      if(this.xspeed<0) {this.xspeed++;} //Same the other way
    } else { //This unit isn't touching the floor, so we apply gravity to make it fall
      this.yspeed+=GRAVITY; //Unit isn't touching the ground, apply gravity
    }
    //We are lucky! the x cordinates are identical to when testing the floor and the roof, so we don't need to redo them here.
    y1 = ((this.y)>>5); //Since we need to check for the top of the unit crashing with the roof rather than the feet, we need to recalculate the y value
    var touchroof;
    i = this.xblocksize-1; //Again, to support units thicker than 1 block in width
    do {
      if(levelarray[y1][x1+i] || levelarray[y1][x2+i]) { //Again, we test the collision of each block of the unit twice. Otherwise, the percived collision size of a block is no thicker than a needle
        touchroof = true;  //The unit touched the roof! Remember this!
      }
    } while (i--)
    if (touchroof) { //The unit touches the roof, so we need to stop it from going upwards
      this.y = (y1+1)<<5; //Again, we reverse the >>5 we did earlier with a <<5 to snap the unit perfectly to a 32 pixel grind, making the results of a collision very smooth and non-bumpy
      this.yspeed = 0; //Obviously, stop the unit that crashes into the roof.
    }

    /* we apply the horizontal movement and collision checks */
    this.x+=this.xspeed;
    x1 = (this.x+this.w)>>5;
    y1 = (this.y+6)>>5;
    y2 = (this.y+30)>>5;
    var touchright;
    i = this.yblocksize-1;
    do {
      if(levelarray[y1+i][x1] || levelarray[y2+i][x1]) { //we test on two points for each block. This is to avoid making blocks point of touching as thin as a needle
        touchright = true;
      }
    } while (i--)
    if (touchright) {
      this.x = (x1-this.xblocksize)<<5;
      this.xspeed = 0;
    }
    x1 = (this.x)>>5;
    //The y values are the same as the left collision! no need to recalculate them
    var touchleft;
    i = this.yblocksize-1;
    do {
      if(levelarray[y1+i][x1] || levelarray[y2+i][x1]) { //we test on two points for each block. This is to avoid making blocks point of touching as thin as a needle
        touchleft = true;
      }
    } while (i--)
    if (touchleft) { 
      this.x = (x1+1)<<5;
      this.xspeed = 0;
    }
    
    /* time to do the unit collisions */
    var foreach = unitlist.first; while(foreach) { //We loop though each unit, but I need to make this into a shifted grind system to only check for units that are near
      if (this == foreach.value) { break; }
      if (this.x+this.w>foreach.value.x) {
        if (this.x<foreach.value.x+foreach.value.w) {
          if (this.y+this.h>foreach.value.y) {
            if (this.y<foreach.value.y+foreach.value.h) {
              document.title = (this.x+this.w)+' vs '+foreach.value.x;
            }
          }
        }      
      }
    foreach = foreach.next;}
  }
  Unit.prototype.draw = function() { //We cache all values for the unit. If the value is not changed, then we won't touch the DOM since it's really slow
    if (this.x != this.cx) {this.element.style.left = this.cx = this.x;}
    if (this.y != this.cy) {this.element.style.top = this.cy = this.y;}
    if (this.w != this.cw) {this.element.style.width = this.cw = this.w;}
    if (this.h != this.ch) {this.element.style.height = this.ch = this.h;}
  }
  function updateplayer() { //Here is the movement
    if (key.left) {
      if (player.xspeed > -4) {
        player.xspeed-=2;
      }
    }
    if (key.right) {
      if (player.xspeed < 4) {
        player.xspeed+=2;
      }
    }
    if (key.up) {
        player.yspeed = -8;
    }
  }
  /* LinkedList is like an diffrent structured Array. It allows you to store a lot of information, and remove such information without creating "holes" in the list */
  function LinkedList() {
    this.first = null;
    this.last = null;
    this.length = 0;
  }
  LinkedList.prototype.Link = function(object) {
    this.previous;
    this.next;
    this.value = object;
  }
  LinkedList.prototype.add = function(object) {
    if (!this.first) {
      this.first = new this.Link(object);
      this.last = this.first;
    } else {
      var oldlast = this.last;
      this.last = new this.Link(object);
      oldlast.next = this.last;
      this.last.previous = oldlast;
    }
    this.length++;
  }
  LinkedList.prototype.removebynode = function(node) {
    if (node == this.first && node == this.last) {
      this.first = null;
      this.last = null;
    } else if (node != this.first && node != this.last) {
      node.previous.next = node.next;
      node.next.previous = node.previous;
    } else {
      if (node == this.first) {
        this.first = this.first.next;
      } else {
        this.last = this.last.previous;
      }
    }
    this.length--;
  }
  LinkedList.prototype.removebyobject = function(object) {
    var foreach = this.first; while(foreach) {
      if (foreach.value == object) {
        this.removebynode(foreach);
	break;
      }
    foreach = foreach.next;}
  }
  LinkedList.prototype.exist = function() {
    return (!!this.first);
  }
  LinkedList.prototype.getlast = function() {
    return this.last.value;
  }
  LinkedList.prototype.getfirst = function() {
    return this.first.value;
  }
  LinkedList.prototype.destory = function() {
    var foreach = this.first; while(foreach) {
      var temp = foreach.next;
      delete foreach.next;
      delete foreach.previous;
    foreach = temp.next;}
    delete this.first;
    delete this.last;
    this.length = 0;
  }

/*---Example---
myList = new LinkedList();
myList.add('item one');
myList.add('item two');
myList.add('item three');
myList.add('item four');
myList.remove(myList.first);
myList.remove(myList.first);
myList.remove(myList.last);
alert(myList.getfirst());
*/
/*---Foreach Loop---
var foreach = myList.first; while(foreach) {
  alert(foreach.value);
foreach = foreach.next;}
*/

  function keydown(e) {
    var keyCode = (e||event).keyCode;
    switch(keyCode) {
    case 39:
      key.right = true;
    break;
    case 37:
      key.left = true;
    break;
    case 38:
      key.up = true;
    break;    
    }
  }

  function keyup(e) {
    var keyCode = (e||event).keyCode;
    switch(keyCode) {
    case 39:
      key.right = false;
    break;
    case 37:
      key.left = false;
    break;
    case 38:
      key.up = false;
    break;
    }
  }



  var key = {
    left: false,
    right: false,
    up: false,
    down: false
  }

  document.onkeydown = keydown; //register the keypresses
  document.onkeyup = keyup;
  drawworld(); //We run this once for now, but if scrolling is going to be possible, this needs to be more dynamic
  var linkblueprint = new UnitBlueprint({xblocksize: 1,yblocksize: 2})
  var link = new Unit(linkblueprint,{x:100,y:100});
  player = link;
  activateunit(link);
})()
