//=========================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt 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 "vtkDiscreteLookupTable.h"

#include "vtkDoubleArray.h"
#include "vtkLookupTable.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkUnsignedCharArray.h"

#include <string>
#include <vector>

#define TABLE_CIRCLE_DEGREE 800

vtkStandardNewMacro(vtkDiscreteLookupTable);

vtkDiscreteLookupTable::vtkDiscreteLookupTable()
{
  this->Discretize = 1;
  this->NumberOfValues = 256;

  this->ValueMax = 0.9;
  this->ValueMin = 0.2;
}

vtkDiscreteLookupTable::~vtkDiscreteLookupTable()
{
}

void vtkDiscreteLookupTable::Build()
{
  // skip the vtkDiscretizableColorTransferFunction::Build()
  //this->vtkColorTransferFunction::Build();

  this->LookupTable->SetVectorMode(this->VectorMode);
  this->LookupTable->SetVectorComponent(this->VectorComponent);

  if (this->Discretize &&
    (this->GetMTime() > this->BuildTime || this->GetMTime() > this->BuildTime))
  {
    this->LookupTable->SetNumberOfTableValues(this->NumberOfValues);
    //this->LookupTable->WritePointer(0,
    //      this->NumberOfValues);
    this->LookupTable->SetRange(0, this->NumberOfValues - 1);
    this->LookupTable->Build();
    this->CreateLookupTable(this->LookupTable, this->ValueMin, this->ValueMax);

    this->BuildTime.Modified();
  }
}

void vtkDiscreteLookupTable::CalcRGB(double llimit, double ulimit, double& r, double& g, double& b)
{
  double l;
  while (1)
  {
    r = vtkMath::Random(0.0, 1.0);
    g = vtkMath::Random(0.0, 1.0);
    b = vtkMath::Random(0.0, 1.0);

    l = (0.11 * b) + (0.3 * r) + (0.59 * g);
    if ((l >= llimit) && (l <= ulimit))
    {
      return;
    }
  }
}

vtkIdType vtkDiscreteLookupTable::GetNextIndex(vtkIdType i, vtkUnsignedCharArray* avail)
{
  if (!avail->GetValue(i))
  {
    vtkIdType orig = i;
    vtkIdType n = avail->GetNumberOfTuples();
    //cout << "N = " << n << "\n";
    for (; i < n; i++)
    {
      if (avail->GetValue(i))
      {
        break;
      }
    }
    if (i == n)
    {
      for (i = 0; i < orig; i++)
      {
        if (avail->GetValue(i))
        {
          break;
        }
      }
      if (!avail->GetValue(i))
      {
        return -1;
      }
    }
  }
  avail->SetTuple1(i, 0);
  return i;
}

void vtkDiscreteLookupTable::CreateLookupTable(vtkLookupTable* lut, double llimit, double ulimit)
{
  vtkIdType n = lut->GetNumberOfTableValues();
  vtkIdType i;
  double r, g, b;
  for (i = 0; i < n; i++)
  {
    CalcRGB(llimit, ulimit, r, g, b);
    //   cout << "Color: " << i << " : ( " << r << ", " << g << ", " << b << "), l = "
    //        << ( (0.11 *b) + (0.3 *r) + (0.59*g)) << "\n";
    lut->SetTableValue(i, r, g, b);
  }
}

void vtkDiscreteLookupTable::CreateLookupTable(vtkLookupTable* lut)
{
  vtkIdType n = lut->GetNumberOfTableValues();
  vtkIdType i;

  int m = vtkMath::Round(pow(static_cast<double>(n), 1.0 / 3.0) + 0.5);
  vtkDoubleArray* colors = vtkDoubleArray::New();
  colors->SetNumberOfComponents(3);
  colors->SetNumberOfTuples(m * m * m);
  vtkUnsignedCharArray* avail = vtkUnsignedCharArray::New();
  avail->SetNumberOfComponents(1);
  avail->SetNumberOfTuples(m * m * m);
  double color[3];
  double delta, r, g, b;
  int x, y, z;
  delta = 1.0 / (static_cast<double>(m - 1));
  r = 0.0;
  for (x = 0, i = 0; (x < m); x++, r += delta)
  {
    g = 0.0;
    for (y = 0; y < m; y++, g += delta)
    {
      b = 0.0;
      for (z = 0; z < m; z++, b += delta, i++)
      {
        colors->SetTuple3(i, r, g, b);
        avail->SetTuple1(i, 1);
        //       cout << i << " (" << r <<"," << g << "," << b << ")\n";
      }
    }
  }

  //   for (i = 0; i < n; i++)
  //     {
  //     colors->GetTypedTuple(i, color);
  //     lut->SetTableValue(i, color[0], color[1], color[2]);
  //     }

  vtkIdType ci, tci;
  for (i = 0; i < n; i++)
  {
    ci = vtkMath::Round(vtkMath::Random(0, n - 1));
    tci = GetNextIndex(ci, avail);
    //   cout << "Mapping: " << i << ", " << ci << ", " << tci << "\n";
    colors->GetTypedTuple(tci, color);
    lut->SetTableValue(i, color[0], color[1], color[2]);
  }

  colors->Delete();
  avail->Delete();
}

void vtkDiscreteLookupTable::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "ValueMin: " << this->ValueMin << endl;
  os << indent << "ValueMax: " << this->ValueMax << endl;
}
