#include "MorphElement.hpp"
#include <gtc/matrix_transform.hpp>
#include "glew.h"

MorphElement::MorphElement(DataEntry* pDataEntry, MorphElement* pResultElement,
  int iVerticesPerSide, float fLeft, float fTop, float fBottom, float fWidth) {
  iType = MORPH_ELEMENT;
  this->pDataEntry = pDataEntry;
  this->pResultElement = pResultElement;
  this->iVerticesPerSide = iVerticesPerSide;
  this->fLeft = fLeft;
  this->fTop = fTop;
  this->fBottom = fBottom;
  this->fWidth = fWidth;
  fHeight = fTop - fBottom;
  fBeginValue = 0.0f;

  vVertices = new glm::vec4[iVerticesPerSide * 2 + 4];
  vColors = new glm::vec4[iVerticesPerSide * 2 + 4];
  vIndices = new int[(iVerticesPerSide * 2 + 2) * 3];

  float fWidthStep = fWidth / ((float) iVerticesPerSide + 1.0f);
  
  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    if (i % 2 == 0) {
      vVertices[i] = glm::vec4(fLeft + fWidth - (i / 2) * fWidthStep, fTop, 0.0f, 1.0f);
    }
    else {
      vVertices[i] = glm::vec4(fLeft + fWidth - (i / 2) * fWidthStep, fBottom, 0.0f, 1.0f);
    }

    vColors[i] = pDataEntry->GetColor();
  }

  for (int i = 0; i < iVerticesPerSide * 2 + 2; i++) {
    vIndices[i * 3] = i;
    vIndices[i * 3 + 1] = i + 1;
    vIndices[i * 3 + 2] = i + 2;
  }

  pShader = new Shader(sSolidColorVertSource, sSolidColorFragSource);
}

MorphElement::MorphElement(DataEntry* pDataEntry, MorphElement* pResultElement,
  int iVerticesPerSide, float fBeginValue, float fWidth) {
  iType = MORPH_ELEMENT;
  this->pDataEntry = pDataEntry;
  this->pResultElement = pResultElement;
  this->iVerticesPerSide = iVerticesPerSide;
  fLeft = -WIDTH;
  fTop = HEIGHT;
  this->fBottom = PIE_CHART_CENTER_Y;
  this->fWidth = fWidth;
  this->fBeginValue = fBeginValue;

  vVertices = new glm::vec4[iVerticesPerSide * 2 + 4];
  vColors = new glm::vec4[iVerticesPerSide * 2 + 4];
  vIndices = new int[(iVerticesPerSide * 2 + 2) * 3];

  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    if (i % 2 == 0) {
      vVertices[i] = glm::vec4(PIE_CHART_CENTER_X, PIE_CHART_CENTER_Y, 0.0f, 1.0f);
    }
    else {
      vVertices[i] = glm::vec4(sin(((float) (i / 2) * (fWidth / (iVerticesPerSide + 1)) + fBeginValue) / 100.0f * 2.0f * PI) /
      (fLeft / fTop) * PIE_CHART_RADIUS + PIE_CHART_CENTER_X,
      cos(((float) (i / 2) * (fWidth / (iVerticesPerSide + 1)) + fBeginValue) / 100.0f * 2.0f * PI) *
      PIE_CHART_RADIUS + PIE_CHART_CENTER_Y, 0.0f, 1.0f);
    }

    vColors[i] = pDataEntry->GetColor();
  }

  for (int i = 0; i < iVerticesPerSide * 2 + 2; i++) {
    vIndices[i * 3] = i;
    vIndices[i * 3 + 1] = i + 1;
    vIndices[i * 3 + 2] = i + 2;
  }

  pShader = new Shader(sSolidColorVertSource, sSolidColorFragSource);
}

MorphElement::~MorphElement() {
  delete vVertices;
  delete vColors;
  delete vIndices;
  delete pShader;
}

void MorphElement::Draw(QPainter* pPainter) {
  pPainter->setRenderHint(QPainter::Antialiasing);
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

  pShader->Bind();

  glEnableVertexAttribArray(pShader->GetVertexLocation());
  glVertexAttribPointer(pShader->GetVertexLocation(), 4, GL_FLOAT, GL_FALSE, 0, vVertices);

  glEnableVertexAttribArray(pShader->GetColorLocation());
  glVertexAttribPointer(pShader->GetColorLocation(), 4, GL_FLOAT, GL_FALSE, 0, vColors);

  glDrawElements(GL_TRIANGLES, (iVerticesPerSide * 2 + 2) * 3, GL_UNSIGNED_INT, vIndices);

  pShader->Unbind();
}

void MorphElement::DrawLabels(QPainter* pPainter) {
  UNREFERENCED(pPainter);
}

void MorphElement::ChangePosition(float fDeltaLeft, float fDeltaTop, float fDeltaBottom) {
  fLeft += fDeltaLeft;
  fTop += fDeltaTop;
  fBottom += fDeltaBottom;

  float fWidthStep = fWidth / ((float) iVerticesPerSide + 1.0f);
  
  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    if (i % 2 == 0) {
      vVertices[i] = glm::vec4(fLeft + (i / 2) * fWidthStep, fTop, 0.0f, 1.0f);
    }
    else {
      vVertices[i] = glm::vec4(fLeft + (i / 2) * fWidthStep, fBottom, 0.0f, 1.0f);
    }
  }
}

void MorphElement::Scale(float fDeltaWidth, float fDeltaHeight) {
  fWidth += fDeltaWidth;
  fHeight += fDeltaHeight;
  fTop = fBottom + fHeight;

  float fWidthStep = fWidth / ((float) iVerticesPerSide + 1.0f);
  
  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    if (i % 2 == 0) {
      vVertices[i] = glm::vec4(fLeft + (i / 2) * fWidthStep, fTop, 0.0f, 1.0f);
    }
    else {
      vVertices[i] = glm::vec4(fLeft + (i / 2) * fWidthStep, fBottom, 0.0f, 1.0f);
    }
  }
}

void MorphElement::ChangeAlpha(float fDeltaAlpha) {
  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    vColors[i] = vColors[i] + glm::vec4(0.0f, 0.0f, 0.0f, fDeltaAlpha);
  }
}

glm::vec4* MorphElement::GetAllPoints() {
  return vVertices;
}

int MorphElement::GetVertexCount() {
  return iVerticesPerSide * 2 + 4;
}

MorphElement* MorphElement::GetResultElement() {
  return pResultElement;
}

void MorphElement::Morph(glm::vec2* vMorphSteps) {
  for (int i = 0; i < iVerticesPerSide * 2 + 4; i++) {
    glm::vec4 vOldVertex = vVertices[i];
    glm::vec2 vMorphStep = vMorphSteps[i];

    vVertices[i] = glm::vec4(vOldVertex.x + vMorphStep.x, vOldVertex.y + vMorphStep.y, 0.0f, 1.0f);
  }
}