/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkWebGLDataSet.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkWebGLDataSet.h"

#include "vtkObjectFactory.h"
#include "vtkWebGLExporter.h"

vtkStandardNewMacro(vtkWebGLDataSet);

std::string vtkWebGLDataSet::GetMD5()
{
  return this->MD5;
}

vtkWebGLDataSet::vtkWebGLDataSet()
{
  this->NumberOfVertices = 0;
  this->NumberOfPoints = 0;
  this->NumberOfIndexes = 0;
  this->vertices = nullptr;
  this->normals = nullptr;
  this->indexes = nullptr;
  this->points = nullptr;
  this->tcoords = nullptr;
  this->colors = nullptr;
  this->binary = nullptr;
  this->binarySize = 0;
  this->hasChanged = false;
}

vtkWebGLDataSet::~vtkWebGLDataSet()
{
  delete[] this->vertices;
  delete[] this->normals;
  delete[] this->indexes;
  delete[] this->points;
  delete[] this->tcoords;
  delete[] this->colors;
  delete[] this->binary;
}

void vtkWebGLDataSet::SetVertices(float* v, int size)
{
  delete[] this->vertices;
  this->vertices = v;
  this->NumberOfVertices = size;
  this->webGLType = wTRIANGLES;
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetIndexes(short* i, int size)
{
  delete[] this->indexes;
  this->indexes = i;
  this->NumberOfIndexes = size;
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetNormals(float* n)
{
  delete[] this->normals;
  this->normals = n;
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetColors(unsigned char* c)
{
  delete[] this->colors;
  this->colors = c;
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetPoints(float* p, int size)
{
  delete[] this->points;
  this->points = p;
  this->NumberOfPoints = size;
  this->webGLType = wLINES;
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetTCoords(float *t)
{
  delete[] this->tcoords;
  this->tcoords = t;
  this->hasChanged = true;
}

unsigned char* vtkWebGLDataSet::GetBinaryData()
{
  this->hasChanged = false;
  return this->binary;
}

int vtkWebGLDataSet::GetBinarySize()
{
  return this->binarySize;
}

void vtkWebGLDataSet::SetMatrix(float* m)
{
  this->Matrix = m;
  this->hasChanged = true;
}

void vtkWebGLDataSet::GenerateBinaryData()
{
  if (this->NumberOfIndexes == 0 && this->webGLType != wPOINTS)
  {
    return;
  }
  int size=0, pos=0, total=0;
  delete[] this->binary;
  this->binarySize = 0;

  if(this->webGLType == wLINES)
  {
    pos = sizeof(pos);
    size = this->NumberOfPoints*sizeof(this->points[0]);

    //Calculate the size used by each data
    total = sizeof(pos) + 1 + sizeof(this->NumberOfPoints) + size*3                     //Size, Type, NumberOfPoints, Points
        + sizeof(this->colors[0])*this->NumberOfPoints*4 + sizeof(this->NumberOfIndexes) //Color, NumberOfIndex
        + this->NumberOfIndexes*sizeof(this->indexes[0]) + sizeof(this->Matrix[0])*16;   //Index, Matrix
    this->binary = new unsigned char[total];
    memset(this->binary,0,total);

    this->binary[pos++] = 'L';
    memcpy(&this->binary[pos], &this->NumberOfPoints, sizeof(this->NumberOfPoints)); pos+=sizeof(this->NumberOfPoints); //Points
    memcpy(&this->binary[pos], this->points, size*3); pos+=size*3;
    memcpy(&this->binary[pos], this->colors, sizeof(this->colors[0])*this->NumberOfPoints*4); pos+=sizeof(this->colors[0])*this->NumberOfPoints*4;
    memcpy(&this->binary[pos], &this->NumberOfIndexes, sizeof(this->NumberOfIndexes)); pos+=sizeof(this->NumberOfIndexes);
    memcpy(&this->binary[pos], this->indexes, this->NumberOfIndexes*sizeof(this->indexes[0])); pos+=this->NumberOfIndexes*sizeof(this->indexes[0]);
    memcpy(&this->binary[pos], this->Matrix, sizeof(this->Matrix[0])*16); pos+=sizeof(this->Matrix[0])*16;              //Matrix

    memcpy(&this->binary[0], &pos, sizeof(pos));
    this->binarySize = total;
  }
  else if (this->webGLType == wTRIANGLES)
  {
    pos = sizeof(pos);
    size = sizeof(this->vertices[0])*this->NumberOfVertices;

    //Calculate the size used by each data
    total = sizeof(pos) + 1 + sizeof(this->NumberOfVertices) + size*(3+3)                   //Size, Type, VertCount, Vert, Normal
        + sizeof(this->colors[0])*this->NumberOfVertices*4 + sizeof(this->NumberOfIndexes)  //Color, IndicCount
        + this->NumberOfIndexes*sizeof(this->indexes[0]) + sizeof(this->Matrix[0])*16;      //Index, Matrix
    if (this->tcoords) total += size*2;                                                     //TCoord
    this->binary = new unsigned char[total];
    memset(this->binary,0,total);

    this->binary[pos++] = 'M';
    memcpy(&this->binary[pos], &this->NumberOfVertices, sizeof(this->NumberOfVertices)); pos+=sizeof(this->NumberOfVertices); //VertCount
    memcpy(&this->binary[pos], this->vertices, size*3); pos+=size*3;                                                          //Vertices
    memcpy(&this->binary[pos], this->normals, size*3); pos+=size*3;                                                           //Normals
    memcpy(&this->binary[pos], this->colors, sizeof(this->colors[0])*this->NumberOfVertices*4); pos+=sizeof(this->colors[0])*this->NumberOfVertices*4;//Colors
    memcpy(&this->binary[pos], &this->NumberOfIndexes, sizeof(this->NumberOfIndexes)); pos+=sizeof(this->NumberOfIndexes);    //IndCount
    memcpy(&this->binary[pos], this->indexes, this->NumberOfIndexes*sizeof(this->indexes[0])); pos+=this->NumberOfIndexes*sizeof(this->indexes[0]);
    memcpy(&this->binary[pos], this->Matrix, sizeof(this->Matrix[0])*16); pos+=sizeof(this->Matrix[0])*16;                    //Matrix
    if (this->tcoords)                                                                                                        //TCoord
    {
      memcpy(&this->binary[pos], this->tcoords, size*2);
      pos+=size*2;
    }

    memcpy(&this->binary[0], &pos, sizeof(pos));
    this->binarySize = total;
  }
  else if (this->webGLType == wPOINTS)
  {
    pos = sizeof(pos);
    size = this->NumberOfPoints*sizeof(this->points[0]);

    //Calculate the size used by each data
    total = sizeof(pos) + 1 + sizeof(this->NumberOfPoints) + size*3                    //Size, Type, NumberOfPoints, Points
        + sizeof(this->colors[0])*this->NumberOfPoints*4 + sizeof(this->Matrix[0])*16; //Color, Matrix
    this->binary = new unsigned char[total];
    memset(this->binary,0,total);

    this->binary[pos++] = 'P';
    memcpy(&this->binary[pos], &this->NumberOfPoints, sizeof(this->NumberOfPoints)); pos+=sizeof(this->NumberOfPoints); //Points
    memcpy(&this->binary[pos], this->points, size*3); pos+=size*3;
    memcpy(&this->binary[pos], this->colors, sizeof(this->colors[0])*this->NumberOfPoints*4); pos+=sizeof(this->colors[0])*this->NumberOfPoints*4;
    memcpy(&this->binary[pos], this->Matrix, sizeof(this->Matrix[0])*16); pos+=sizeof(this->Matrix[0])*16;              //Matrix

    memcpy(&this->binary[0], &pos, sizeof(pos));
    this->binarySize = total;
  }
  vtkWebGLExporter::ComputeMD5((const unsigned char*)this->binary, this->binarySize, this->MD5);
  this->hasChanged = true;
}

void vtkWebGLDataSet::SetType(WebGLObjectTypes t)
{
  this->webGLType = t;
}

bool vtkWebGLDataSet::HasChanged()
{
  return this->hasChanged;
}

void vtkWebGLDataSet::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
