#include "PieSlice.hpp"
#include "glew.h"

PieSlice::PieSlice(DataEntry* pDataEntry, float fBeginValue, float fValueScaleFactor) {
  iType = PIE_SLICE;
  this->pDataEntry = pDataEntry;
  this->fBeginValue = fBeginValue * fValueScaleFactor;
  this->fValueScaleFactor = fValueScaleFactor;
  fWidth = pDataEntry->GetValue() * fValueScaleFactor;
  fLeft = -WIDTH;
  fTop = HEIGHT;
  iOutterVertices = (int) fWidth + 2;

  vVertices = new glm::vec4[iOutterVertices + 1];
  vVertices[0] = glm::vec4(PIE_CHART_CENTER_X, PIE_CHART_CENTER_Y, 0.0f, 1.0f);

  vColors = new glm::vec4[iOutterVertices + 1];
  vColors[0] = pDataEntry->GetColor();

  vIndices = new int[(iOutterVertices - 1) * 3];

  for (int i = 0; i < iOutterVertices; i++) {
    vVertices[i + 1] = glm::vec4(sin(((float) i * (fWidth / (iOutterVertices - 1)) + this->fBeginValue) / 100.0f * 2.0f * PI) /
      (fLeft / fTop) * PIE_CHART_RADIUS + PIE_CHART_CENTER_X,
      cos(((float) i * (fWidth / (iOutterVertices - 1)) + this->fBeginValue) / 100.0f * 2.0f * PI) *
      PIE_CHART_RADIUS + PIE_CHART_CENTER_Y, 0.0f, 1.0f);

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

    if (i < iOutterVertices - 1) {
      vIndices[i * 3] = 0;
      vIndices[i * 3 + 1] = i + 1;
      vIndices[i * 3 + 2] = i + 2;
    }
  }

  pShader = new Shader(sSolidColorVertSource, sSolidColorFragSource);
}

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

void PieSlice::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, (iOutterVertices - 1) * 3, GL_UNSIGNED_INT, vIndices);

  pShader->Unbind();
}

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

void PieSlice::ChangePosition(float fDeltaLeft, float fDeltaTop, float fDeltaBottom) {
  UNREFERENCED(fDeltaBottom);

  fLeft += fDeltaLeft;
  fTop += fDeltaTop;

  for (int i = 0; i < iOutterVertices; i++) {
    float fXCoord = sin(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) /
      (fLeft / fTop) * PIE_CHART_RADIUS + PIE_CHART_CENTER_X;
    float fYCoord = cos(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) *
      PIE_CHART_RADIUS + PIE_CHART_CENTER_Y;

    vVertices[i + 1] = glm::vec4(fXCoord, fYCoord, 0.0f, 1.0f);
  }
}

void PieSlice::Scale(float fDeltaWidth, float fDeltaHeight) {
  UNREFERENCED(fDeltaHeight);

  fWidth += fDeltaWidth;

  for (int i = 0; i < iOutterVertices; i++) {
    float fXCoord = sin(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) /
      (fLeft / fTop) * PIE_CHART_RADIUS + PIE_CHART_CENTER_X;
    float fYCoord = cos(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) *
      PIE_CHART_RADIUS + PIE_CHART_CENTER_Y;

    vVertices[i + 1] = glm::vec4(fXCoord, fYCoord, 0.0f, 1.0f);
  }
}

void PieSlice::ChangeAlpha(float fDeltaAlpha) {
  for (int i = 0; i < iOutterVertices + 1; i++) {
    vColors[i] = vColors[i] + glm::vec4(0.0f, 0.0f, 0.0f, fDeltaAlpha);
  }
}

void PieSlice::Rotate(float fDeltaValue) {
  fBeginValue += fDeltaValue;

  for (int i = 0; i < iOutterVertices; i++) {
    float fXCoord = sin(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) /
      (fLeft / fTop) * PIE_CHART_RADIUS + PIE_CHART_CENTER_X;
    float fYCoord = cos(((float) i * (fWidth / (iOutterVertices - 1)) + fBeginValue) / 100.0f * 2.0f * PI) *
      PIE_CHART_RADIUS + PIE_CHART_CENTER_Y;

    vVertices[i + 1] = glm::vec4(fXCoord, fYCoord, 0.0f, 1.0f);
  }
}

void PieSlice::SetBeginValue(float fBeginValue) {
  this->fBeginValue = fBeginValue;
}

float PieSlice::GetBeginValue() {
  return fBeginValue;
}

void PieSlice::SetWidth(float fWidth) {
  this->fWidth = fWidth;
}

float PieSlice::GetValueScaleFactor() {
  return fValueScaleFactor;
}

int PieSlice::GetOutterVertices() {
  return iOutterVertices;
}