#include "Player.h"

// #include "../vsgl3/LiteMath.h"


Player::Player(int a_x, int a_y)
{
  this->posX = a_x;
  this->posY = a_y;
  m_pMesh = new PLayerTankGraphics();
  m_animTimeStart = 0.0f;
}

Player::~Player()
{
  delete m_pMesh;
}

std::vector<IGraphicsObject*> Player::getDrawList()
{
  if (dirX == 1)
    m_pMesh->rotateY(90.0f);
  else if (dirX == -1)
    m_pMesh->rotateY(-90.0f);
  else if (dirY == -1)
    m_pMesh->rotateY(180.0f);
  else
    m_pMesh->rotateY(0.0f);

  std::vector<IGraphicsObject*> res(1);
  res[0] = m_pMesh;
  return res;
}


void MulMat2x2Float2(float a_mat[2][2], float a_vec[2], float a_res[2])
{
  a_res[0] = a_mat[0][0] * a_vec[0] + a_mat[0][1] * a_vec[1];
  a_res[1] = a_mat[1][0] * a_vec[0] + a_mat[1][1] * a_vec[1];
}

extern Timer g_timer;

void Player::move(int a_flags, int a_cells)
{
  m_animTimeStart = g_timer.getElapsed();
  m_pMesh->animateStart(a_flags, m_animTimeStart);

  float mRotPositive90[2][2];
  float mRotNegative90[2][2];

  mRotPositive90[0][0] = 0;  mRotPositive90[0][1] = 1;
  mRotPositive90[1][0] = -1; mRotPositive90[1][1] = 0;

  mRotNegative90[0][0] = 0;  mRotNegative90[0][1] = -1;
  mRotNegative90[1][0] = 1;  mRotNegative90[1][1] = 0;

  float dirPrev[2] = { float(dirX), float(dirY) };
  float dirNext[2] = { 0, 0 };


  if (a_flags & TURN_LEFT)
  {
    MulMat2x2Float2(mRotPositive90, dirPrev, dirNext);

    dirX = int(dirNext[0]);
    dirY = int(dirNext[1]);
  }
  else if (a_flags & TURN_RIGHT)
  {
    MulMat2x2Float2(mRotNegative90, dirPrev, dirNext);

    dirX = int(dirNext[0]);
    dirY = int(dirNext[1]);
  }


  if (a_flags & MOVE_FORWARD)
  {
    posX += dirX; // boundary conditions ?
    posY += dirY; // boundary conditions ?
  }
  else if (a_flags & MOVE_BACK)
  {
    posX -= dirX; // boundary conditions ?
    posY -= dirY; // boundary conditions ?
  }

}

bool Player::inputIsBlocked()
{
  return ((g_timer.getElapsed() - m_animTimeStart) < ANIMATE_INTERVAL_IN_SEC*0.99f);
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


PLayerTankGraphics::PLayerTankGraphics() : m_rotY(0.0f), m_translateToWorldPos(0.0f, 0.0f, 0.0f)
{
  m_pProgram = new ShaderProgram("../main/Vertex.vert", "../main/Fragment.frag");
  //m_pMesh    = new SimpleMesh(m_pProgram->program, "../data/tank.vsgf");
  m_pTex     = new Texture2D("../data/checker2.bmp");

  m_pTurret  = new SimpleMesh(m_pProgram->program, "../data/tank_part2.vsgf");
  m_pCorpus  = new SimpleMesh(m_pProgram->program, "../data/tank_part1.vsgf");

  m_animTimeStart = g_timer.getElapsed();
  m_turretAngle = 0.0f;
}

PLayerTankGraphics::~PLayerTankGraphics()
{
  delete m_pTex;  m_pTex = NULL;
  //delete m_pMesh; m_pMesh = NULL;
  delete m_pTurret; m_pTurret = NULL;
  delete m_pCorpus; m_pCorpus = NULL;
  delete m_pProgram; m_pProgram = NULL;
}

void PLayerTankGraphics::translate(float3 a_pos)
{
  m_translateToWorldPos = a_pos;
}

void PLayerTankGraphics::rotateY(float angle)
{
  m_rotY = angle;
}


void PLayerTankGraphics::animateStart(int a_flags, float a_timeStart)
{
  m_prevCellPos   = m_translateToWorldPos;
  m_prevRotAngle  = m_rotY;
  m_animType      = a_flags;
  m_animTimeStart = a_timeStart;
}

void PLayerTankGraphics::draw(float4x4 worldViewMatrix, float4x4 projectionMatrix) const
{
  float3 currPos = m_translateToWorldPos;
  float  currRot = m_rotY;
  float currTime = g_timer.getElapsed();

  if(currTime < m_animTimeStart + ANIMATE_INTERVAL_IN_SEC)
  {
    float t = clamp((currTime - m_animTimeStart) / ANIMATE_INTERVAL_IN_SEC, 0.0f, 1.0f);

    if (m_animType & (TURN_LEFT | TURN_RIGHT))
    {
      float rotStart = m_prevRotAngle;
      float rotEnd   = m_rotY;

      if (fabs(rotStart + 90.0f) < 0.001f && fabs(rotEnd - 180.0f) < 0.001f)
        rotEnd = -180.0f;                  // == 180
      else if (fabs(rotStart - 180.0f) < 0.001f && fabs(rotEnd + 90.0f) < 0.001f)
        rotStart = -180.0f;

      currRot = m_prevRotAngle + (rotEnd - rotStart)*t;
    }
    else if (m_animType & (MOVE_FORWARD | MOVE_BACK))
    {
      currPos = m_prevCellPos + (m_translateToWorldPos - m_prevCellPos)*t;
    }
  }


  float4x4 transformMatrix1; // calc model to world transform
  {
    float4x4 rotationMatrix, scaleMatrix, translateMatrix;
    float4x4 transformMatrix2;

    glusLoadIdentityf(rotationMatrix.L());
    glusRotateRzRyRxf(rotationMatrix.L(), 0.0f, currRot, 0.0f);

    glusTranslatef(translateMatrix.L(), currPos.x + 0.0f, currPos.y + 3.0f, currPos.z + 0.0f);
    glusScalef(scaleMatrix.L(), 100, 100, 100);
    glusMultMatrixf(transformMatrix2.L(), scaleMatrix.L(), rotationMatrix.L());
    glusMultMatrixf(transformMatrix1.L(), translateMatrix.L(), transformMatrix2.L());
  }

  glUseProgram(m_pProgram->program);

  setUniform(m_pProgram->program, "worldViewMatrix", worldViewMatrix);
  setUniform(m_pProgram->program, "projectionMatrix", projectionMatrix);  // set matrix we have calculated in "reshape" funtion
  setUniform(m_pProgram->program, "objectMatrix", transformMatrix1);

  bindTexture(m_pProgram->program, 1, "diffuseTexture", m_pTex->GetColorTexId());

  //m_pMesh->Draw();
  
  m_pCorpus->Draw();

  float4x4 transformMatrix2;
  {
    float4x4 translateMatrix1, translateMatrix2;
    float4x4 temp1;

    glusTranslatef(translateMatrix1.L(), 0.0f, 0.0f, 0.0150f);

    float4x4 rotationMatrix;
    glusRotateRzRyRxf(rotationMatrix.L(), 0.0f, m_turretAngle, 0.0f);
    glusMultMatrixf(temp1.L(), translateMatrix1.L(), rotationMatrix.L());
    glusMultMatrixf(transformMatrix2.L(), transformMatrix1.L(), temp1.L());    
  }

  setUniform(m_pProgram->program, "objectMatrix", transformMatrix2);
  m_pTurret->Draw();

}



