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

  Program:   Visualization Toolkit
  Module:    vtkUniformVariables.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 "vtkUniformVariables.h"
#include "vtkgl.h"
#include <cassert>
#include "vtkObjectFactory.h"
#include "vtkOpenGLError.h"

#include <map>

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkUniformVariables);

class ltstr
{
public:
  bool operator()(const char* s1, const char* s2) const
  {
    return strcmp(s1, s2) < 0;
  }
};

class vtkUniform
{
public:

  // just because dynamic__cast is forbidden in VTK. Sucks.
  enum
  {
    ClassTypeVectorInt=0,
    ClassTypeVectorFloat=1,
    ClassTypeMatrix=2,
    ClassTypeArrayInt=3,
    ClassTypeArrayFloat=4
  };

  int GetClassType() const
  {
      return this->ClassType;
  }

  vtkUniform()
  {
      this->ClassType=-1;
      this->Name=0;
  }

  const char *GetName() const
  {
      return this->Name;
  }

  void SetName(const char *n)
  {
      if(this->Name==0 && n==0)
      {
        return;
      }
      if(this->Name!=0 && n!=0 && strcmp(this->Name,n)==0)
      {
        return;
      }
      delete[] this->Name;
      if(n!=0) // copy
      {
         size_t l=strlen(n)+1;
         this->Name=new char[l];
         strncpy(this->Name,n,l);
      }
      else
      {
        this->Name=0;
      }
  }

  virtual ~vtkUniform()
  {
      delete[] Name;
  }

  virtual void Send(int location)=0;

  virtual void PrintSelf(ostream &os, vtkIndent indent)=0;

  virtual vtkUniform *Clone() const=0;

protected:
  char *Name;

  int ClassType; // just because dynamic__cast is forbidden in VTK. Sucks.
};

class vtkUniformVectorInt : public vtkUniform
{
public:
  vtkUniformVectorInt(int size,
                      int *values)
  {
      this->ClassType=ClassTypeVectorInt;
      this->Size=size;
      this->Values=new int[size];
      int i=0;
      while(i<size)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }
  virtual ~vtkUniformVectorInt()
  {
      delete[] this->Values;
  }

  int GetSize()
  {
      return this->Size;
  }

  void SetValues(int *values)
  {
      int i=0;
      while(i<this->Size)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  const int *GetValues()
  {
     return this->Values;
  }

   virtual void Send(int location)
   {
      switch(this->Size)
      {
        case 1:
          vtkgl::Uniform1i(location,this->Values[0]);
          break;
        case 2:
          vtkgl::Uniform2i(location,this->Values[0],this->Values[1]);
          break;
        case 3:
          vtkgl::Uniform3i(location,this->Values[0],this->Values[1],
                           this->Values[2]);
          break;
        case 4:
          vtkgl::Uniform4i(location,this->Values[0],this->Values[1],
                           this->Values[2],this->Values[3]);
          break;
      }
      vtkOpenGLStaticCheckErrorMacro("failed at glUniform*i");
   }

  virtual void PrintSelf(ostream &os, vtkIndent indent)
  {
      os << indent << this->Name << " (uniform" << this->Size << "i): ";
      int i=0;
      while(i<this->Size)
      {
        os << this->Values[i];
        if(i<(this->Size-1))
        {
          os <<",";
        }
        ++i;
      }
      os << endl;
  }

  virtual vtkUniform *Clone() const
  {
      vtkUniformVectorInt *result=new vtkUniformVectorInt(this->Size,
                                                          this->Values);
      result->SetName(this->Name);
      return result;
  }

protected:
  int Size;
  int *Values;
};

class vtkUniformVectorFloat : public vtkUniform
{
public:
  vtkUniformVectorFloat(int size,
                        float *values)
  {
      this->ClassType=ClassTypeVectorFloat;
      this->Size=size;
      this->Values=new float[size];
      int i=0;
      while(i<size)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  virtual ~vtkUniformVectorFloat()
  {
      delete[] this->Values;
  }

  int GetSize()
  {
      return this->Size;
  }

  void SetValues(float *values)
  {
      int i=0;
      while(i<this->Size)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  const float *GetValues()
  {
      return this->Values;
  }

  virtual void Send(int location)
  {
      switch(this->Size)
      {
        case 1:
          vtkgl::Uniform1f(location,this->Values[0]);
          break;
        case 2:
          vtkgl::Uniform2f(location,this->Values[0],this->Values[1]);
          break;
        case 3:
          vtkgl::Uniform3f(location,this->Values[0],this->Values[1],
                           this->Values[2]);
          break;
        case 4:
          vtkgl::Uniform4f(location,this->Values[0],this->Values[1],
                           this->Values[2],this->Values[3]);
          break;
      }
      vtkOpenGLStaticCheckErrorMacro("failed at glUniform*f");
  }

  virtual void PrintSelf(ostream &os, vtkIndent indent)
  {
      os << indent << this->Name << " (uniform" << this->Size << "f): ";
      int i=0;
      while(i<this->Size)
      {
        os << this->Values[i];
        if(i<(this->Size-1))
        {
          os <<",";
        }
        ++i;
      }
      os << endl;
  }

  virtual vtkUniform *Clone() const
  {
      vtkUniformVectorFloat *result=new vtkUniformVectorFloat(this->Size,
                                                              this->Values);
      result->SetName(this->Name);
      return result;
  }

protected:
  int Size;
  float *Values;
};

class vtkUniformArrayInt : public vtkUniform
{
public:
  vtkUniformArrayInt(int size,
                     int arraySize,
                     int *values)
  {
      this->ClassType=ClassTypeArrayInt;
      this->Size=size;
      this->ArraySize=arraySize;
      this->Values=new GLint[size*arraySize];
      int i=0;
      while(i<this->Size*this->ArraySize)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  // this constructor is used inside Clone()
  // It is required because GLint is long on Mac, not int.
  vtkUniformArrayInt(int size,
                     int arraySize,
                     const GLint *values)
  {
      this->ClassType=ClassTypeArrayInt;
      this->Size=size;
      this->ArraySize=arraySize;
      this->Values=new GLint[size*arraySize];
      int i=0;
      while(i<this->Size*this->ArraySize)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  virtual ~vtkUniformArrayInt()
  {
      delete[] this->Values;
  }

  int GetSize()
  {
      return this->Size;
  }

  int GetArraySize()
  {
      return this->ArraySize;
  }

  void SetValues(int *values)
  {
      int i=0;
      while(i<this->Size*this->ArraySize)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  const GLint *GetValues()
  {
      return this->Values;
  }

  virtual void Send(int location)
  {
      switch(this->Size)
      {
        case 1:
          vtkgl::Uniform1iv(location,this->ArraySize,this->Values);
          break;
        case 2:
          vtkgl::Uniform2iv(location,this->ArraySize,this->Values);
          break;
        case 3:
          vtkgl::Uniform3iv(location,this->ArraySize,this->Values);
          break;
        case 4:
          vtkgl::Uniform4iv(location,this->ArraySize,this->Values);
          break;
      }
      vtkOpenGLStaticCheckErrorMacro("failed at glUniform*iv");
  }

  virtual void PrintSelf(ostream &os, vtkIndent indent)
  {
      os << indent << this->Name << " (uniform" << this->Size << "iv[" << this->ArraySize << "]): ";
      int j=0;
      while(j<this->ArraySize)
      {
        os << "(";
        int i=0;
        while(i<this->Size)
        {
          os << this->Values[i];
          if(i<(this->Size-1))
          {
            os <<",";
          }
          ++i;
        }
        os << endl;
        ++j;
      }
  }

  virtual vtkUniform *Clone() const
  {
      vtkUniformArrayInt *result=new vtkUniformArrayInt(this->Size,
                                                        this->ArraySize,
                                                        this->Values);
      result->SetName(this->Name);
      return result;
  }

protected:
  int Size;  // size of element (eq. to float, vec2, vec2, vec4)
  int ArraySize; // number of elements
  GLint *Values; // GLint is long on Mac
};

class vtkUniformArrayFloat : public vtkUniform
{
public:
  vtkUniformArrayFloat(int size,
                       int arraySize,
                       float *values)
  {
      this->ClassType=ClassTypeArrayFloat;
      this->Size=size;
      this->ArraySize=arraySize;
      this->Values=new float[size*arraySize];
      int i=0;
      while(i<this->Size*this->ArraySize)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  virtual ~vtkUniformArrayFloat()
  {
      delete[] this->Values;
  }

  int GetSize()
  {
      return this->Size;
  }

  int GetArraySize()
  {
      return this->ArraySize;
  }

  void SetValues(float *values)
  {
      int i=0;
      while(i<this->Size*this->ArraySize)
      {
        this->Values[i]=values[i];
        ++i;
      }
  }

  const float *GetValues()
  {
      return this->Values;
  }

  virtual void Send(int location)
  {
      switch(this->Size)
      {
        case 1:
          vtkgl::Uniform1fv(location,this->ArraySize,this->Values);
          break;
        case 2:
          vtkgl::Uniform2fv(location,this->ArraySize,this->Values);
          break;
        case 3:
          vtkgl::Uniform3fv(location,this->ArraySize,this->Values);
          break;
        case 4:
          vtkgl::Uniform4fv(location,this->ArraySize,this->Values);
          break;
      }
      vtkOpenGLStaticCheckErrorMacro("failed at glUniform*fv");
  }

  virtual void PrintSelf(ostream &os, vtkIndent indent)
  {
      os << indent << this->Name << " (uniform" << this->Size << "fv[" << this->ArraySize << "]): ";
      int j=0;
      while(j<this->ArraySize)
      {
        os << "(";
        int i=0;
        while(i<this->Size)
        {
          os << this->Values[i];
          if(i<(this->Size-1))
          {
            os <<",";
          }
          ++i;
        }
        os << endl;
        ++j;
      }
  }

  virtual vtkUniform *Clone() const
  {
      vtkUniformArrayFloat *result=new vtkUniformArrayFloat(this->Size,
                                                            this->ArraySize,
                                                            this->Values);
      result->SetName(this->Name);
      return result;
  }

protected:
  int Size;  // size of element (eq. to float, vec2, vec2, vec4)
  int ArraySize; // number of elements
  float *Values;
};

// rows or columns are 2,3,4.
class vtkUniformMatrix : public vtkUniform
{
public:
  vtkUniformMatrix(int rows,
                   int columns,
                   float *values)
  {
      this->ClassType=ClassTypeMatrix;
      this->Rows=rows;
      this->Columns=columns;
      this->Values=new float[rows*columns];
      int i=0;
      while(i<rows)
      {
        int j=0;
        while(j<columns)
        {
          int index=i*columns+j;
          this->Values[index]=values[index];
          ++j;
        }
        ++i;
      }
  }

  ~vtkUniformMatrix()
  {
      delete[] this->Values;
  }

  int GetRows()
  {
      return this->Rows;
  }

  int GetColumns()
  {
      return this->Columns;
  }

  void SetValues(float *values)
  {
      int i=0;
      while(i<this->Rows)
      {
        int j=0;
        while(j<this->Columns)
        {
          int index=i*this->Columns+j;
          this->Values[index]=values[index];
          ++j;
        }
        ++i;
      }
  }

  const float* GetValues()
  {
      return this->Values;
  }

  virtual void Send(int location)
  {
      switch(this->Rows)
      {
        case 2:
          switch(this->Columns)
          {
            case 2:
              vtkgl::UniformMatrix2fv(location,1,GL_FALSE,this->Values);
              break;
            case 3:
              vtkgl::UniformMatrix2x3fv(location,1,GL_FALSE,this->Values);
              break;
            case 4:
              vtkgl::UniformMatrix2x4fv(location,1,GL_FALSE,this->Values);
              break;
          }
          break;
        case 3:
           switch(this->Columns)
           {
            case 2:
              vtkgl::UniformMatrix3x2fv(location,1,GL_FALSE,this->Values);
              break;
            case 3:
              vtkgl::UniformMatrix3fv(location,1,GL_FALSE,this->Values);
              break;
            case 4:
              vtkgl::UniformMatrix3x4fv(location,1,GL_FALSE,this->Values);
              break;
           }
           break;
        case 4:
          switch(this->Columns)
          {
            case 2:
              vtkgl::UniformMatrix4x2fv(location,1,GL_FALSE,this->Values);
              break;
            case 3:
              vtkgl::UniformMatrix4x3fv(location,1,GL_FALSE,this->Values);
              break;
            case 4:
              vtkgl::UniformMatrix4fv(location,1,GL_FALSE,this->Values);
              break;
          }
          break;
      }
      vtkOpenGLStaticCheckErrorMacro("failed at glUniformMatrix*fv");
  }

  virtual void PrintSelf(ostream &os, vtkIndent indent)
  {
      os << indent << this->Name << " (matrix " << this->Rows << "x"
         << this->Columns << "): ";

      int i=0;
      while(i<this->Rows)
      {
        int j=0;
        while(j<this->Columns)
        {
          int index=i*this->Columns+j;
          os << this->Values[index];
          if(j<(this->Columns-1))
            os << ",";
          ++j;
        }
        os << endl;
        ++i;
      }
  }

  virtual vtkUniform *Clone() const
  {
      vtkUniformMatrix *result=new vtkUniformMatrix(this->Rows,this->Columns,
                                                    this->Values);
      result->SetName(this->Name);
      return result;
  }

protected:
  float *Values;
  int Rows;
  int Columns;
};

typedef std::map<const char *, vtkUniform *, ltstr> UniformMap;
typedef std::map<const char *, vtkUniform *, ltstr>::iterator UniformMapIt;

class vtkUniformVariablesMap
{
public:
  UniformMap Map;
  UniformMapIt It; // used for external iteration.

  ~vtkUniformVariablesMap()
  {
      UniformMapIt i=this->Map.begin();
      UniformMapIt e=this->Map.end();
      while(i!=e)
      {
        vtkUniform *u=(*i).second;
        delete u;
        ++i;
      }
  }
};

// ----------------------------------------------------------------------------
vtkUniformVariables::vtkUniformVariables()
{
  this->Map=new vtkUniformVariablesMap;
}

// ----------------------------------------------------------------------------
vtkUniformVariables::~vtkUniformVariables()
{
  delete this->Map;
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::SetUniformi(const char *name,
                                      int numberOfComponents,
                                      int *value)
{
  assert("pre: name_exists" && name!=0);
  assert("pre: value_exists" && value!=0);
  assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4);

  UniformMapIt cur=this->Map->Map.find(name);

  if(cur!=this->Map->Map.end())
  {
    vtkUniform *u=(*cur).second;
    vtkUniformVectorInt *ui=0;
    if(u->GetClassType()==vtkUniform::ClassTypeVectorInt)
    {
      ui=static_cast<vtkUniformVectorInt *>(u);
    }
    if(ui==0)
    {
      vtkErrorMacro(<<"try to overwrite a value with different type.");
    }
    else
    {
      if(ui->GetSize()!=numberOfComponents)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of components.");
      }
      else
      {
        bool changed=false;
        int i=0;
        while(!changed && i<numberOfComponents)
        {
          changed=value[i]!=ui->GetValues()[i];
          ++i;
        }
        if(changed)
        {
          ui->SetValues(value);
          this->Modified();
        }
      }
    }
  }
  else
  {
    vtkUniform *u=0;
    u=new vtkUniformVectorInt(numberOfComponents,value);
    u->SetName(name);

    std::pair<const char *, vtkUniform *> p;
    p.first=u->GetName(); // cannot be `name' because
    // we don't manage this pointer.
    p.second=u;

    this->Map->Map.insert(p);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::SetUniformf(const char *name,
                                      int numberOfComponents,
                                      float *value)
{
  assert("pre: name_exists" && name!=0);
  assert("pre: value_exists" && value!=0);
  assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4);

  UniformMapIt cur=this->Map->Map.find(name);

  if(cur!=this->Map->Map.end())
  {
    vtkUniform *u=(*cur).second;
    vtkUniformVectorFloat *uf=0;
    if(u->GetClassType()==vtkUniform::ClassTypeVectorFloat)
    {
      uf=static_cast<vtkUniformVectorFloat *>(u);
    }
    if(uf==0)
    {
      vtkErrorMacro(<<"try to overwrite a value with different type.");
    }
    else
    {
      if(uf->GetSize()!=numberOfComponents)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of components.");
      }
      else
      {
        bool changed=false;
        int i=0;
        while(!changed && i<numberOfComponents)
        {
          changed=value[i]!=uf->GetValues()[i];
          ++i;
        }
        if(changed)
        {
          uf->SetValues(value);
          this->Modified();
        }
      }
    }
  }
  else
  {
    vtkUniform *u=0;
    u=new vtkUniformVectorFloat(numberOfComponents,value);
    u->SetName(name);

    std::pair<const char *, vtkUniform *> p;
    p.first=u->GetName(); // cannot be `name' because
    // we don't manage this pointer.
    p.second=u;

    this->Map->Map.insert(p);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::SetUniformiv(const char *name,
                                       int numberOfComponents,
                                       int numberOfElements,
                                       int *value)
{
  assert("pre: name_exists" && name!=0);
  assert("pre: value_exists" && value!=0);
  assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4);
  assert("pre: valid_numberOfElements" && numberOfElements>=1);

  UniformMapIt cur=this->Map->Map.find(name);

  if(cur!=this->Map->Map.end())
  {
    vtkUniform *u=(*cur).second;
    vtkUniformArrayInt *ui=0;
    if(u->GetClassType()==vtkUniform::ClassTypeArrayInt)
    {
      ui=static_cast<vtkUniformArrayInt *>(u);
    }
    if(ui==0)
    {
      vtkErrorMacro(<<"try to overwrite a value with different type.");
    }
    else
    {
      if(ui->GetSize()!=numberOfComponents)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of components.");
      }
      if(ui->GetArraySize()!=numberOfElements)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of elements.");
      }
      else
      {
        bool changed=false;
        int i=0;
        while(!changed && i<numberOfComponents*numberOfElements)
        {
          changed=value[i]!=ui->GetValues()[i];
          ++i;
        }
        if(changed)
        {
          ui->SetValues(value);
          this->Modified();
        }
      }
    }
  }
  else
  {
    vtkUniform *u=0;
    u=new vtkUniformArrayInt(numberOfComponents,numberOfElements,value);
    u->SetName(name);

    std::pair<const char *, vtkUniform *> p;
    p.first=u->GetName(); // cannot be `name' because
    // we don't manage this pointer.
    p.second=u;

    this->Map->Map.insert(p);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::SetUniformfv(const char *name,
                                       int numberOfComponents,
                                       int numberOfElements,
                                       float *value)
{
  assert("pre: name_exists" && name!=0);
  assert("pre: value_exists" && value!=0);
  assert("pre: valid_numberOfComponents" && numberOfComponents>=1 && numberOfComponents<=4);
  assert("pre: valid_numberOfElements" && numberOfElements>=1);

  UniformMapIt cur=this->Map->Map.find(name);

  if(cur!=this->Map->Map.end())
  {
    vtkUniform *u=(*cur).second;
    vtkUniformArrayFloat *uf=0;
    if(u->GetClassType()==vtkUniform::ClassTypeArrayFloat)
    {
      uf=static_cast<vtkUniformArrayFloat *>(u);
    }
    if(uf==0)
    {
      vtkErrorMacro(<<"try to overwrite a value with different type.");
    }
    else
    {
      if(uf->GetSize()!=numberOfComponents)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of components.");
      }
      if(uf->GetArraySize()!=numberOfElements)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of elements.");
      }
      else
      {
        bool changed=false;
        int i=0;
        while(!changed && i<numberOfComponents*numberOfElements)
        {
          changed=value[i]!=uf->GetValues()[i];
          ++i;
        }
        if(changed)
        {
          uf->SetValues(value);
          this->Modified();
        }
      }
    }
  }
  else
  {
    vtkUniform *u=0;
    u=new vtkUniformArrayFloat(numberOfComponents,numberOfElements,value);
    u->SetName(name);

    std::pair<const char *, vtkUniform *> p;
    p.first=u->GetName(); // cannot be `name' because
    // we don't manage this pointer.
    p.second=u;

    this->Map->Map.insert(p);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::SetUniformMatrix(const char *name,
                                           int rows,
                                           int columns,
                                           float *value)
{
  assert("pre: name_exists" && name!=0);
  assert("pre: value_exists" && value!=0);
  assert("pre: valid_rows" && rows>=2 && rows<=4);
  assert("pre: valid_columns" && columns>=2 && columns<=4);

  UniformMapIt cur=this->Map->Map.find(name);

  if(cur!=this->Map->Map.end())
  {
    vtkUniform *u=(*cur).second;
    vtkUniformMatrix *um=0;
    if(u->GetClassType()==vtkUniform::ClassTypeMatrix)
    {
      um=static_cast<vtkUniformMatrix *>(u);
    }
    if(um==0)
    {
      vtkErrorMacro(<<"try to overwrite a value with different type.");
    }
    else
    {
      if(um->GetRows()!=rows || um->GetColumns()!=columns)
      {
        vtkErrorMacro(<<"try to overwrite a value of same type but different number of components.");
      }
      else
      {
        bool changed=false;
        int i=0;
        while(!changed && i<rows*columns)
        {
          changed=value[i]!=um->GetValues()[i];
          ++i;
        }
        if(changed)
        {
          um->SetValues(value);
          this->Modified();
        }
      }
    }
  }
  else
  {
    vtkUniform *u=new vtkUniformMatrix(rows,columns,value);
    u->SetName(name);
    std::pair<const char *, vtkUniform *> p;
    p.first=u->GetName(); // cannot be `name' because
    // we don't manage this pointer.
    p.second=u;
    this->Map->Map.insert(p);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
// Description:
// Remove uniform `name' from the list.
void vtkUniformVariables::RemoveUniform(const char *name)
{
  UniformMapIt cur=this->Map->Map.find(name);
  if(cur!=this->Map->Map.end())
  {
    this->Map->Map.erase(cur);
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
// Description:
// \pre need a valid OpenGL context and a shader program in use.
void vtkUniformVariables::Send(const char *name,
                               int uniformIndex)
{
  UniformMapIt cur=this->Map->Map.find(name);
  (*cur).second->Send(uniformIndex);
}

// ----------------------------------------------------------------------------
// Description:
// Place the internal cursor on the first uniform.
void vtkUniformVariables::Start()
{
  this->Map->It=this->Map->Map.begin();
}

// ----------------------------------------------------------------------------
// Description:
// Is the iteration done?
bool vtkUniformVariables::IsAtEnd()
{
  return this->Map->It==this->Map->Map.end();
}

// ----------------------------------------------------------------------------
// Description:
// Name of the uniform at the current cursor position.
// \pre not_done: !this->IsAtEnd()
const char *vtkUniformVariables::GetCurrentName()
{
  assert("pre: not_done" && !this->IsAtEnd());
  return (*this->Map->It).first;
}

// ----------------------------------------------------------------------------
// Description:
// \pre need a valid OpenGL context and a shader program in use.
// \pre not_done: !this->IsAtEnd()
void vtkUniformVariables::SendCurrentUniform(int uniformIndex)
{
  assert("pre: not_done" && !this->IsAtEnd());
  (*this->Map->It).second->Send(uniformIndex);
}

// ----------------------------------------------------------------------------
// Description:
// Move the cursor to the next uniform.
// \pre not_done: !this->IsAtEnd()
void vtkUniformVariables::Next()
{
  assert("pre: not_done" && !this->IsAtEnd());
  ++this->Map->It;
}

// ----------------------------------------------------------------------------
// Description:
// Copy all the variables from `other'. Any existing variable will be
// overwritten.
// \pre other_exists: other!=0
// \pre not_self: other!=this
void vtkUniformVariables::Merge(vtkUniformVariables *other)
{
  assert("pre: other_exists" && other != 0);
  assert("pre: not_self" && other != this);

  other->Start();
  while (!other->IsAtEnd())
  {
    const char *name = other->GetCurrentName();
    UniformMapIt prev = this->Map->Map.find(name);
    if (prev != this->Map->Map.end())
    {
      delete prev->second;
      this->Map->Map.erase(prev);
    }
    vtkUniform* clone = other->Map->It->second->Clone();
    this->Map->Map[clone->GetName()] = clone;

    other->Next();
  }
  if (other->Map->Map.size() > 0)
  {
    this->Modified();
  }
}

// ----------------------------------------------------------------------------
// Description:
// Copy all the variables from `other'. Any existing variable will be
// deleted first.
// \pre other_exists: other!=0
// \pre not_self: other!=this
void vtkUniformVariables::DeepCopy(vtkUniformVariables *other)
{
  assert("pre: other_exists" && other!=0);
  assert("pre: not_self" && other!=this);

  if(this->Map->Map.size()>0)
  {
    delete this->Map;
    this->Map=new vtkUniformVariablesMap;
    this->Modified();
  }
  this->Merge(other);
}

// ----------------------------------------------------------------------------
void vtkUniformVariables::RemoveAllUniforms()
{
  if(this->Map->Map.size()>0)
  {
    delete this->Map;
    this->Map=new vtkUniformVariablesMap;
    this->Modified();
  }
}

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

  this->Start();
  while(!this->IsAtEnd())
  {
    const char *name=this->GetCurrentName();
    UniformMapIt cur=this->Map->Map.find(name);
    (*cur).second->PrintSelf(os,indent);
    this->Next();
  }
}
