//=========================================================================
//  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 "pqCMBGlyphObject.h"


#include "pqApplicationCore.h"
#include "pqDataRepresentation.h"
#include "pqObjectBuilder.h"
#include "pqPipelineRepresentation.h"
#include "pqPipelineSource.h"
#include "pqRenderView.h"
#include "pqSMAdaptor.h"
#include "pqServer.h"

#include <vtkProcessModule.h>
#include "vtkPVDataInformation.h"
#include "vtkPVLASOutputBlockInformation.h"
#include "vtkPVSceneGenObjectInformation.h"
#include <vtkSMDataSourceProxy.h>
#include <vtkSMDoubleVectorProperty.h>
#include <vtkSMIntVectorProperty.h>
#include "vtkSMNewWidgetRepresentationProxy.h"
#include <vtkSMPropertyHelper.h>
#include "vtkSMRepresentationProxy.h"
#include <vtkSMProxyProperty.h>
#include <vtkSMRenderViewProxy.h>
#include <vtkSMSourceProxy.h>
#include "vtkSMProxyManager.h"
#include "vtkSMCMBGlyphPointSourceProxy.h"
#include "vtkGeometryRepresentation.h"
#include <vtkTransform.h>
#include <QFileInfo>
#include <QVariant>

#include "pqRepresentationHelperFunctions.h"
#include "vtkDataObject.h"

//-----------------------------------------------------------------------------
pqCMBGlyphObject::pqCMBGlyphObject() : pqCMBSceneObjectBase()
{
  this->SurfaceType = pqCMBSceneObjectBase::Other;
}
//-----------------------------------------------------------------------------
pqCMBGlyphObject::pqCMBGlyphObject(pqPipelineSource *glyphSource,
                                         pqRenderView *view,
                                         pqServer *server,
                                         const char *glyphFilename,
                                         const char *pointsFilename,
                                         bool updateRep)
{
  this->GlyphFileName = glyphFilename;
  this->PointsFileName = pointsFilename;
  this->GlyphSource = glyphSource;
  this->SurfaceType = pqCMBSceneObjectBase::Other;
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();
  builder->blockSignals(true);
  this->Source =  builder->createSource("sources", "CmbGlyphPointSource", server);
  builder->blockSignals(false);
  vtkSMCMBGlyphPointSourceProxy::
    SafeDownCast(this->Source->getProxy())->ReadFromFile(pointsFilename);
  this->initialize(view, server, updateRep);
}

//-----------------------------------------------------------------------------
pqCMBGlyphObject::pqCMBGlyphObject(pqPipelineSource *glyphSource,
                                         pqRenderView *view,
                                         pqServer *server,
                                         const char *glyphFilename,
                                         bool updateRep)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();
  this->GlyphSource = glyphSource;
  this->SurfaceType = pqCMBSceneObjectBase::Other;

  builder->blockSignals(true);
  this->Source =  builder->createSource("sources", "CmbGlyphPointSource", server);
  builder->blockSignals(false);
  this->GlyphFileName = glyphFilename;
  this->initialize(view, server, updateRep);
}

//-----------------------------------------------------------------------------
pqCMBGlyphObject::pqCMBGlyphObject(const char *glyphFilename,
                                         pqServer *server,
                                         pqRenderView *view,
                                         bool updateRep)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();
  QStringList files;
  files << glyphFilename;

  builder->blockSignals(true);
  this->GlyphSource =  builder->createReader("sources", "CMBGeometryReader", files, server);
  this->Source =  builder->createSource("sources", "CmbGlyphPointSource", server);
  builder->blockSignals(false);
  this->GlyphFileName = glyphFilename;
  this->SurfaceType = pqCMBSceneObjectBase::Other;
  this->initialize(view, server, updateRep);
}

//-----------------------------------------------------------------------------
pqCMBGlyphObject::pqCMBGlyphObject(const char *glyphFilename,
                                         const char *pointsFilename,
                                         pqServer *server, pqRenderView *view,
                                         bool updateRep)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();
  QStringList files;
  files << glyphFilename;

  builder->blockSignals(true);
  this->GlyphSource =  builder->createReader("sources", "CMBGeometryReader", files, server);
  this->Source =  builder->createSource("sources", "CmbGlyphPointSource", server);
  builder->blockSignals(false);
  vtkSMCMBGlyphPointSourceProxy::
    SafeDownCast(this->Source->getProxy())->ReadFromFile(pointsFilename);
  this->GlyphFileName = glyphFilename;
  this->PointsFileName = pointsFilename;
  this->SurfaceType = pqCMBSceneObjectBase::Other;
  this->initialize(view, server, updateRep);
}


//-----------------------------------------------------------------------------
pqCMBGlyphObject::~pqCMBGlyphObject()
{
  if (this->GlyphSource)
    {
    pqApplicationCore* core = pqApplicationCore::instance();
    pqObjectBuilder* builder = core->getObjectBuilder();
    builder->destroy(this->GlyphSource);
    this->GlyphSource = NULL;
    }
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::initialize(pqRenderView *view, pqServer * /*server*/, bool updateRep)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();
  this->SourceProxy =
    vtkSMCMBGlyphPointSourceProxy::SafeDownCast(this->Source->getProxy());
  this->SourceProxy->UpdateVTKObjects();
  this->SourceProxy->UpdatePipeline();
  this->setRepresentation(
    builder->createDataRepresentation(
    this->Source->getOutputPort(0), view, "GeometryRepresentation"));
  this->GlyphSource->getProxy()->MarkModified(this->GlyphSource->getProxy());

  vtkSMProxy *repProxy = this->getRepresentation()->getProxy();
  RepresentationHelperFunctions::CMB_COLOR_REP_BY_ARRAY(
    repProxy, "Color", vtkDataObject::POINT);

  pqSMAdaptor::setEnumerationProperty(repProxy->GetProperty("Representation"), "3D Glyphs");
  //vtkSMPropertyHelper(repProxy, "ImmediateModeRendering").Set(0);
  vtkSMPropertyHelper(repProxy, "GlyphType").Set(this->GlyphSource->getProxy());
  vtkSMPropertyHelper(repProxy, "Scaling").Set(true);
  vtkSMPropertyHelper(repProxy, "ScaleMode").Set(2);
  vtkSMPropertyHelper(repProxy, "Orient").Set(true);
  vtkSMPropertyHelper(repProxy, "OrientationMode").Set(1);
  vtkSMPropertyHelper(repProxy, "MapScalars").Set(0);
  vtkSMPropertyHelper(repProxy,
    "SelectScaleArray").Set("Scaling");
  vtkSMPropertyHelper(repProxy,
    "SelectOrientationVectors").Set("Orientation");

  // This is a work arround for a bug in ParaView
  vtkSMPropertyHelper(repProxy, "ScaleFactor").Set(1.0);
  if (updateRep)
    {
    repProxy->UpdateVTKObjects();
    }
}
//-----------------------------------------------------------------------------
void pqCMBGlyphObject::clearSelectedPointsColor()
{
  this->SourceProxy->ResetColorsToDefault();
}
//-----------------------------------------------------------------------------
pqCMBGlyphObject::enumObjectType pqCMBGlyphObject::getType() const
{
  return pqCMBSceneObjectBase::Glyph;
}

//-----------------------------------------------------------------------------
pqPipelineSource *pqCMBGlyphObject::duplicateGlyphPipelineSource(pqServer *server)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();

  pqPipelineSource *pdSource =
    builder->createSource("sources", "HydroModelPolySource", server);

  vtkSMDataSourceProxy::SafeDownCast(pdSource->getProxy())->CopyData(
    vtkSMSourceProxy::SafeDownCast(this->GlyphSource->getProxy()));
  return pdSource;
}
//-----------------------------------------------------------------------------
pqCMBSceneObjectBase *pqCMBGlyphObject::duplicate(pqServer *server,
                                                    pqRenderView *view,
                                                    bool updateRep)
{
  pqApplicationCore* core = pqApplicationCore::instance();
  pqObjectBuilder* builder = core->getObjectBuilder();

  pqPipelineSource *pdSource =
    builder->createSource("sources", "HydroModelPolySource", server);

  vtkSMDataSourceProxy::SafeDownCast(pdSource->getProxy())->CopyData(
    vtkSMSourceProxy::SafeDownCast(this->GlyphSource->getProxy()));

  pqCMBGlyphObject *nobj = new pqCMBGlyphObject(pdSource, view, server,
                                                      this->GlyphFileName.c_str());
  this->duplicateInternals(nobj);
  nobj->SurfaceType = this->SurfaceType;

  // Duplicate the points and other information
  int i, n = this->getNumberOfPoints();
  double d[3];
  for (i = 0; i < n; i++)
    {
    this->getPoint(i, d);
    nobj->insertNextPoint(d);
    this->getScale(i, d);
    nobj->setScale(i,d);
    this->getOrientation(i,d);
    nobj->setOrientation(i,d);
    }

  if (updateRep)
    {
    nobj->getRepresentation()->getProxy()->UpdateVTKObjects();
    }

  return nobj;
}


//-----------------------------------------------------------------------------
void pqCMBGlyphObject::insertNextPoint(double *p)
{
  this->SourceProxy->InsertNextPoint(p);
}

//-----------------------------------------------------------------------------
vtkIdType pqCMBGlyphObject::getNumberOfPoints()
{
  return const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->GetNumberOfPoints();
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::getAveragePoint(double *pa)
{
  int i, n = this->getNumberOfPoints();
  pa[0] = pa[1] = pa[2] = 0.0;
  if (n == 0)
    {
    return;
    }

  double p[3];
  for (i = 0; i < n; i++)
    {
    const_cast<vtkSMCMBGlyphPointSourceProxy*>
      (this->SourceProxy)->GetPoint(i, p);
    pa[0] += p[0];
    pa[1] += p[1];
    pa[2] += p[2];
    }
  pa[0] /= n;
  pa[1] /= n;
  pa[2] /= n;
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::getPoint(vtkIdType i, double *p) const
{
  const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->GetPoint(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::setPoint(vtkIdType i, double *p)
{
    this->SourceProxy->SetPoint(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::getScale(vtkIdType i, double *p) const
{
  const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->GetScale(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::setScale(vtkIdType i, double *p)
{
  const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->SetScale(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::getOrientation(vtkIdType i, double *p) const
{
  const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->GetOrientation(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::setOrientation(vtkIdType i, double *p)
{
  const_cast<vtkSMCMBGlyphPointSourceProxy*>
    (this->SourceProxy)->SetOrientation(i, p);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::writePointsFile() const
{
  if (this->PointsFileName != "")
    {
    const_cast<vtkSMCMBGlyphPointSourceProxy*>
      (this->SourceProxy)->WriteToFile(this->PointsFileName.c_str());
    }
}
//-----------------------------------------------------------------------------
std::string pqCMBGlyphObject::getSurfaceTypeAsString() const
{
  return this->convertSurfaceTypeToString(this->SurfaceType);
}

//-----------------------------------------------------------------------------
pqPipelineSource * pqCMBGlyphObject::getGlyphSource() const
{
  return this->GlyphSource;
}
//-----------------------------------------------------------------------------
void pqCMBGlyphObject::getColor(double color[4]) const
{
  this->SourceProxy->GetDefaultColor(color);
}

//-----------------------------------------------------------------------------
void pqCMBGlyphObject::setColor(double color[4], bool updateRep)
{
  this->SourceProxy->SetDefaultColor(color);
  this->SourceProxy->MarkModified(NULL);
  if (updateRep)
    {
    this->getRepresentation()->getProxy()->UpdateVTKObjects();
    }
}
//-----------------------------------------------------------------------------
void pqCMBGlyphObject::applyTransform(double scaleDelta[3],
                                         double orientationDelta[3],
                                         double translationDelta[3])
{
  this->SourceProxy->
    ApplyTransform(orientationDelta, translationDelta, scaleDelta);
  this->getRepresentation()->getProxy()->UpdateVTKObjects();
}
//-----------------------------------------------------------------------------
void pqCMBGlyphObject::copyAttributes(pqCMBSceneObjectBase *obj)
{
  double ori[3], scale[3], trans[3], color[4];
  obj->getOrientation(ori);
  obj->getScale(scale);
  trans[0] = trans[1] = trans[2] = 0.0;
  obj->getColor(color);
  this->applyTransform(scale, ori, trans);
  this->setColor(color);
  this->getRepresentation()->getProxy()->UpdateVTKObjects();
}
//-----------------------------------------------------------------------------
