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

  Program:   ParaView
  Module:    vtkRulerSourceRepresentation.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkRulerSourceRepresentation.h"

#include "vtk3DWidgetRepresentation.h"
#include "vtkAbstractArray.h"
#include "vtkAbstractWidget.h"
#include "vtkAlgorithmOutput.h"
#include "vtkAxisActor2D.h"
#include "vtkDataSetAttributes.h"
#include "vtkDistanceRepresentation2D.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointHandleRepresentation2D.h"
#include "vtkPointSource.h"
#include "vtkPolyData.h"
#include "vtkPVCacheKeeper.h"
#include "vtkPVRenderView.h"
#include "vtkRenderer.h"
#include "vtkTextProperty.h"
#include "vtkVariant.h"

vtkStandardNewMacro(vtkRulerSourceRepresentation);
vtkCxxSetObjectMacro(vtkRulerSourceRepresentation, DistanceRepresentation,
  vtkDistanceRepresentation2D);
//----------------------------------------------------------------------------
vtkRulerSourceRepresentation::vtkRulerSourceRepresentation()
{
  std::cout<<"Creating a ruler source representation"<<std::endl;

  vtkSmartPointer<vtkPointHandleRepresentation2D> handle =
    vtkSmartPointer<vtkPointHandleRepresentation2D>::New();

  this->DistanceRepresentation = vtkDistanceRepresentation2D::New();
  this->DistanceRepresentation->SetHandleRepresentation(handle);
  this->DistanceRepresentation->InstantiateHandleRepresentation();

  this->CacheKeeper->SetInputData(this->Clone.Get());
}

//----------------------------------------------------------------------------
vtkRulerSourceRepresentation::~vtkRulerSourceRepresentation()
{
  this->SetDistanceRepresentation(0);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetVisibility(bool val)
{
  this->Superclass::SetVisibility(val);
  if (this->DistanceRepresentation)
    {
    this->DistanceRepresentation->SetVisibility(val);
    }
}

//----------------------------------------------------------------------------
int vtkRulerSourceRepresentation::FillInputPortInformation(int, vtkInformation* info)
{
  info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
  info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1);
  return 1;
}

//----------------------------------------------------------------------------
bool vtkRulerSourceRepresentation::AddToView(vtkView* view)
{
  vtkPVRenderView* rView = vtkPVRenderView::SafeDownCast(view);
  if (this->DistanceRepresentation && rView)
    {
    rView->GetRenderer()->AddActor(this->DistanceRepresentation);
    }
  return this->Superclass::AddToView(view);
}

//----------------------------------------------------------------------------
bool vtkRulerSourceRepresentation::RemoveFromView(vtkView* view)
{
  vtkPVRenderView* rView = vtkPVRenderView::SafeDownCast(view);
  if (this->DistanceRepresentation && rView)
    {
    rView->GetRenderer()->RemoveActor(this->DistanceRepresentation);
    }
  return this->Superclass::RemoveFromView(view);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::MarkModified()
{
  if (!this->GetUseCache())
    {
    // Cleanup caches when not using cache.
    this->CacheKeeper->RemoveAllCaches();
    }
  this->Superclass::MarkModified();
}

//----------------------------------------------------------------------------
bool vtkRulerSourceRepresentation::IsCached(double cache_key)
{
  return this->CacheKeeper->IsCached(cache_key);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetTextProperty(vtkTextProperty* prop)
{
  this->DistanceRepresentation->GetAxis()->SetTitleTextProperty(prop);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetLabelFormat(char* labelFormat)
{
  this->DistanceRepresentation->SetLabelFormat(labelFormat);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetRulerMode(int choice)
{
  this->DistanceRepresentation->SetRulerMode(choice);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetRulerDistance(double distance)
{
  this->DistanceRepresentation->SetRulerDistance(distance);
}

//----------------------------------------------------------------------------
void vtkRulerSourceRepresentation::SetNumberOfRulerTicks(int n)
{
  this->DistanceRepresentation->SetNumberOfRulerTicks(n);
}

//----------------------------------------------------------------------------
int vtkRulerSourceRepresentation::RequestData(
  vtkInformation* request, vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // Pass caching information to the cache keeper.
  this->CacheKeeper->SetCachingEnabled(this->GetUseCache());
  this->CacheKeeper->SetCacheTime(this->GetCacheKey());

  if (inputVector[0]->GetNumberOfInformationObjects()==1)
    {
    this->Clone->ShallowCopy(vtkPolyData::GetData(inputVector[0], 0));
    }
  this->Clone->Modified();
  this->CacheKeeper->Update();

  return this->Superclass::RequestData(request, inputVector, outputVector);
}

//----------------------------------------------------------------------------
int vtkRulerSourceRepresentation::ProcessViewRequest(
  vtkInformationRequestKey* request_type,
  vtkInformation* inInfo, vtkInformation* outInfo)
{
  if (!this->Superclass::ProcessViewRequest(request_type, inInfo, outInfo))
    {
    // i.e. this->GetVisibility() == false, hence nothing to do.
    return 0;
    }

  if (request_type == vtkPVView::REQUEST_UPDATE())
    {
    vtkPVRenderView::SetPiece(inInfo, this,
                              this->CacheKeeper->GetOutputDataObject(0));
    vtkPVRenderView::SetDeliverToClientAndRenderingProcesses(inInfo, this,
      /*deliver_to_client=*/ true, /*gather_before_delivery=*/ false);

    }
  else if (request_type == vtkPVView::REQUEST_RENDER())
    {
    vtkAlgorithmOutput* producerPort = vtkPVRenderView::GetPieceProducer(inInfo, this);

    // since there's no direct connection between the mapper and the collector,
    // we don't put an update-suppressor in the pipeline.

    vtkPolyData* line = vtkPolyData::SafeDownCast(
      producerPort->GetProducer()->GetOutputDataObject(
        producerPort->GetIndex()));
    if (line)
      {
      this->DistanceRepresentation->SetPoint1WorldPosition(
        line->GetPoints()->GetPoint(0));
      this->DistanceRepresentation->SetPoint2WorldPosition(
        line->GetPoints()->GetPoint(1));
      }
    }

  return 1;
}

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