/*
* Collision detection
* @author: Joseph 'Pcjoe' Florencio
* @date: 12-03-05
*/

COLL_BOX = 1;
COLL_LINE = 2;

// Test for collision and fix position
function testCollision( entity )
{
  var vecOrg = entity.vecOrigin;
  //Don't collide with the world
  if(vecOrg.getX() < worldMin.getX())
  {   vecOrg.setX(worldMin.getX());
  }
  else if(vecOrg.getX() > worldMax.getX()-entity.vecSize.getX())
  {   vecOrg.setX(worldMax.getX()-entity.vecSize.getX());
  }
  if(vecOrg.getY() < worldMin.getY())
  {   vecOrg.setY(worldMin.getY());
  }
  else if(vecOrg.getY() > worldMax.getY()-entity.vecSize.getY())
  {   vecOrg.setY(worldMax.getY()-entity.vecSize.getY());
  }
  // Iterate through all collision boxes
  for(var i=0; i<this.collisionBoxes.length;i++)
  {
    
    // Box collision
    if(this.pointInBox(i,vecOrg))
    {
        // Create an absurdly large move distance
        var moveDist = worldMax.getX()+worldMax.getY();
        var tempDist = 0;
        var moveDir = -1;
        // Get shortest move distance
        if(moveDist >= (tempDist=Math.abs(vecOrg.getX()-this.collisionBoxes[i][0].getX())))
        {
            moveDist = tempDist;
            moveDir = DIR_LEFT;
        }
        if(moveDist >= (tempDist=Math.abs(vecOrg.getX()-this.collisionBoxes[i][1].getX())))
        {
            moveDist = tempDist;
            moveDir = DIR_RIGHT;
        }
        if(moveDist >= (tempDist=Math.abs(vecOrg.getY()-this.collisionBoxes[i][0].getY())))
        {
            moveDist = tempDist;
            moveDir = DIR_FRONT;
        }
        if(moveDist >= (tempDist=Math.abs(vecOrg.getY()-this.collisionBoxes[i][1].getY())))
        {
            moveDist = tempDist;
            moveDir = DIR_BACK;
        }

        // Move entity out of object in shortest direction
        switch(moveDir)
        {
        case DIR_LEFT:
              vecOrg.setX(this.collisionBoxes[i][0].getX()-1);
              break;
        case DIR_RIGHT:
              vecOrg.setX(this.collisionBoxes[i][1].getX()+1);
              break;
        case DIR_FRONT:
              vecOrg.setY(this.collisionBoxes[i][0].getY()-1);
              break;
        case DIR_BACK:
              vecOrg.setY(this.collisionBoxes[i][1].getY()+1);
              break;
        }
    }
    // Line collision
 /*   else if(this.entityOnLine(i,entity))
    {
        yLine1 = this.getLineY(this.collisionBoxes[i][0], this.collisionBoxes[i][1],vecOrg.getX());
        yLine2 = this.getLineY(this.collisionBoxes[i][0], this.collisionBoxes[i][1],vecOrg.getX()+entity.vecSize.getX());
      if(this.collisionBoxes[i][3] == DIR_BACK)
      {
        if(yLine1 > yLine2)
        {
          vecDist = new Vector();
          vecDist.addVector(vecOrg);
          vecDist.subVector(new VectorSet(vecOrg.getX(),yLine1-entity.vecSize.getY()));
          // HACK HACK: Failsafe so we wont be 'shuved' into the environment
      //    if(vecDist.getLength() < entity.vecSize.getY()/2)
          {  vecOrg.setY(yLine1);
          }
        }
        else
        {
          if(yLine2 <= this.collisionBoxes[i][1].getY())
          {
            vecOrg.setY(this.collisionBoxes[i][1].getY()-entity.vecSize.getY());
          }
          else
          {
            vecOrg.setY(yLine2-entity.vecSize.getY());
          }
        }
      }
      else if(this.collisionBoxes[i][3] == DIR_FRONT)
      {
        if(yLine1 > yLine2)
        {
          vecDist = new Vector();
          vecDist.addVector(vecOrg);
          vecDist.subVector(new VectorSet(vecOrg.getX(),yLine1));
          // HACK HACK: Failsafe so we wont be 'shuved' into the environment
          if(vecDist.getLength() < entity.vecSize.getY()/2)
          {  vecOrg.setY(yLine1);
          }
        }
        else
        {
          vecDist = new Vector();
          vecDist.addVector(vecOrg);
          vecDist.subVector(new VectorSet(vecOrg.getX(),yLine2));
          // HACK HACK: Failsafe so we wont be 'shuved' into the environment
          if(vecDist.getLength() < entity.vecSize.getY()/2)
          {  vecOrg.setY(yLine2);
          }
        }
      }
    }*/
  }
  entity.vecOrigin = vecOrg;
  entity.updatePosition();
}

// Point in box
function pointInBox( idx, point )
{
    if(this.collisionBoxes[idx][2] == COLL_BOX)
    {
        // Smaller than X2, but larger than X1
        if((point.getX()<=this.collisionBoxes[idx][1].getX()) && (point.getX()>=this.collisionBoxes[idx][0].getX()))
        {
            // Smaller than Y2, but larger than Y1
            if((point.getY()<=this.collisionBoxes[idx][1].getY()) && (point.getY()>=this.collisionBoxes[idx][0].getY()))
            {
              return true;
            }
        }
    }
    return false;
}

function getLineY( vec1, vec2, x )
{
  var slope = (vec2.getY()-vec1.getY())/(vec2.getX()-vec1.getX());
  var b = vec2.getY()-slope*vec2.getX();
  return parseFloat(slope)*parseFloat(x)+b;
}

// Entity on line
function entityOnLine(idx, entity)
{
  var yLine = 0;
  var returnVal = false;
  if(this.collisionBoxes[idx][2] == COLL_LINE)
  {
   /*   document.getElementById('blkbox1').style.top = this.collisionBoxes[idx][0].getY();
      document.getElementById('blkbox1').style.left = this.collisionBoxes[idx][0].getX();
      document.getElementById('blkbox2').style.top = this.collisionBoxes[idx][1].getY();
      document.getElementById('blkbox2').style.left = this.collisionBoxes[idx][1].getX();*/
      // Create an element for every point on the bounding box
      // -1: not included, 1 = over line, 2 = under line
      var pointList = new Array();
      pointList.push(new Array(new VectorSet(entity.vecOrigin.getX(),entity.vecOrigin.getY()), -1));
      pointList.push(new Array(new VectorSet(entity.vecOrigin.getX(),entity.vecOrigin.getY()+entity.vecSize.getY()), -1));
      pointList.push(new Array(new VectorSet(entity.vecOrigin.getX()+entity.vecSize.getX(),entity.vecOrigin.getY()), -1));
      pointList.push(new Array(new VectorSet(entity.vecOrigin.getX()+entity.vecSize.getX(),entity.vecOrigin.getY()+entity.vecSize.getY()), -1));
      
      // Loop through all points
      for(var i = 0; i < pointList.length; i++)
      {
        // In range
        if((pointList[i][0].getX() > this.collisionBoxes[idx][0].getX()) &&
            (pointList[i][0].getX() < this.collisionBoxes[idx][1].getX()))
        {
            // Get corresponding Y point on the line
            yLine = this.getLineY(this.collisionBoxes[idx][0], this.collisionBoxes[idx][1],pointList[i][0].getX());
              
            if(pointList[i][0].getY() > yLine)
            {
              pointList[i][1] = 1;
            
            }
            else
            {
              pointList[i][1] = 2;
            }
          document.getElementById('debug').dtext.value = document.getElementById('debug').dtext.value + Math.round(yLine) + "&" + Math.round(pointList[i][0].getY()) + "|";
        }
      }

      // Loop through all point values, set return val as true once we see a point
      // that's above AND below the line (intercepting)
      var same = -1;
      for(var n = 0; n < pointList.length; n++)
      {
        if(pointList[n][1] == -1)
        {   continue;
        }
        if(same == -1)
        {
          same = pointList[n][1];
        }
        else if(same != pointList[n][1])
        {
          returnVal = true;
          break;
        }
      }
  }
  return returnVal;
}

function makeBox(x1,y1,x2,y2)
{
  this.collisionBoxes.push(new Array(new VectorSet(x1,y1),new VectorSet(x2,y2), COLL_BOX));
}

function makeLine(x1,y1,x2,y2, pushdir)
{
  this.collisionBoxes.push(new Array(new VectorSet(x1,y1),new VectorSet(x2,y2), COLL_LINE, pushdir));
}

// Add collision boxes
function addCollisionBoxes()
{
  // Lines - Can't get this to work right for the time being, just do everything with cheap boxes
/*  this.makeLine(57,209,64,182,DIR_BACK); // Cliffs surrounding links house
  this.makeLine(55,209+22,80,182+22,DIR_BACK); // Cliffs surrounding links house
  this.makeLine(57,229,104,182,DIR_FRONT);*/
  // HACK HACK: Use this fudge factor (lol @ proff hicks) so character wont squeeze between collision boxes
  var fudge = 5;
  this.makeBox(0-fudge,0-fudge,40,174); // Trees
  this.makeBox(40-fudge,0-fudge,64,116);
  this.makeBox(66-fudge,0-fudge,137,78);
  this.makeBox(137-fudge,0-fudge,159,23);
  this.makeBox(130,153,240,255); // Links house
  
  this.makeBox(0-fudge,209,57+2,229); // Cliffs surrounding links house
  this.makeBox(67,135-2,103,183+3);
  this.makeBox(124-16,98,228+16,117);
  this.makeBox(267,151,305,321+4);
  this.makeBox(129-16,320,275,362);
  this.makeBox(0-fudge,318,52,362);
  this.makeBox(61-16,184,104,230); // Cliff slants (HACK)
  this.makeBox(82-16,97+2,118,134);
  this.makeBox(247-16,97+2,304,150+2);
  this.makeBox(276-16,322-2,300,359);
  this.makeBox(383-13,0-fudge,496+fudge,373-16); // Water
  this.makeBox(0-fudge,402,206,488+fudge); // Mountains at bottom
  this.makeBox(257-16,414,496+fudge,488+fudge);
  
}


// Constructor
function Collision()
{
  this.collisionBoxes = new Array();
  this.makeBox = makeBox;
  this.makeLine = makeLine;
  this.addCollisionBoxes = addCollisionBoxes;
  this.testCollision = testCollision;
  this.pointInBox = pointInBox;
  this.getLineY = getLineY;
  this.entityOnLine = entityOnLine;
  
  // Add collision boxes
  this.addCollisionBoxes();
}
