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

  Program:   Visualization Toolkit
  Module:    vtkAlgorithm.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 "vtkAlgorithm.h"

#include "vtkAlgorithmOutput.h"
#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkDataArray.h"
#include "vtkDataObject.h"
#include "vtkDataSet.h"
#include "vtkErrorCode.h"
#include "vtkFieldData.h"
#include "vtkGarbageCollector.h"
#include "vtkInformation.h"
#include "vtkInformationInformationVectorKey.h"
#include "vtkInformationIntegerKey.h"
#include "vtkInformationStringKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSmartPointer.h"
#include "vtkStreamingDemandDrivenPipeline.h"

#include <vtkstd/set>
#include <vtkstd/vector>

vtkCxxRevisionMacro(vtkAlgorithm, "1.38");
vtkStandardNewMacro(vtkAlgorithm);

vtkCxxSetObjectMacro(vtkAlgorithm,Information,vtkInformation);

vtkInformationKeyMacro(vtkAlgorithm, INPUT_REQUIRED_DATA_TYPE, String);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_IS_OPTIONAL, Integer);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_IS_REPEATABLE, Integer);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_REQUIRED_FIELDS, InformationVector);
vtkInformationKeyMacro(vtkAlgorithm, PORT_REQUIREMENTS_FILLED, Integer);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_PORT, Integer);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_CONNECTION, Integer);
vtkInformationKeyMacro(vtkAlgorithm, INPUT_ARRAYS_TO_PROCESS, InformationVector);

vtkExecutive* vtkAlgorithm::DefaultExecutivePrototype = 0;
  
//----------------------------------------------------------------------------
class vtkAlgorithmInternals
{
public:
  // Proxy object instances for use in establishing connections from
  // the output ports to other algorithms.
  vtkstd::vector< vtkSmartPointer<vtkAlgorithmOutput> > Outputs;
};

//----------------------------------------------------------------------------
class vtkAlgorithmToExecutiveFriendship
{
public:
  static void SetAlgorithm(vtkExecutive* executive, vtkAlgorithm* algorithm)
    {
    executive->SetAlgorithm(algorithm);
    }
};

//----------------------------------------------------------------------------
vtkAlgorithm::vtkAlgorithm()
{
  this->AbortExecute = 0;
  this->ErrorCode = 0;
  this->Progress = 0.0;
  this->ProgressText = NULL;
  this->Executive = 0;
  this->InputPortInformation = vtkInformationVector::New();
  this->OutputPortInformation = vtkInformationVector::New();
  this->AlgorithmInternal = new vtkAlgorithmInternals;
  this->Information = vtkInformation::New();
  this->Information->Register(this);
  this->Information->Delete();
}

//----------------------------------------------------------------------------
vtkAlgorithm::~vtkAlgorithm()
{
  this->SetInformation(0);
  if(this->Executive)
    {
    this->Executive->UnRegister(this);
    this->Executive = 0;
    }
  this->InputPortInformation->Delete();
  this->OutputPortInformation->Delete();
  delete this->AlgorithmInternal;
  delete [] this->ProgressText;
  this->ProgressText = NULL;
}

//----------------------------------------------------------------------------
// Update the progress of the process object. If a ProgressMethod exists,
// executes it. Then set the Progress ivar to amount. The parameter amount
// should range between (0,1).
void vtkAlgorithm::UpdateProgress(double amount)
{
  this->Progress = amount;
  this->InvokeEvent(vtkCommand::ProgressEvent,(void *)&amount);
}


//----------------------------------------------------------------------------
vtkInformation *vtkAlgorithm
::GetInputArrayFieldInformation(int idx, vtkInformationVector **inputVector)
{
  // first get out association
  vtkInformation *info = this->GetInputArrayInformation(idx);
  
  // then get the actual info object from the pinfo
  int port = info->Get(INPUT_PORT());
  int connection = info->Get(INPUT_CONNECTION());
  int fieldAssoc = info->Get(vtkDataObject::FIELD_ASSOCIATION());
  vtkInformation *inInfo = inputVector[port]->GetInformationObject(connection);
  
  if (info->Has(vtkDataObject::FIELD_NAME()))
    {
    const char *name = info->Get(vtkDataObject::FIELD_NAME());
    return vtkDataObject::GetNamedFieldInformation(inInfo, fieldAssoc, name);
    }
  int fType = info->Get(vtkDataObject::FIELD_ATTRIBUTE_TYPE());
  return vtkDataObject::GetActiveFieldInformation(inInfo, fieldAssoc, fType);
}

//----------------------------------------------------------------------------
vtkInformation *vtkAlgorithm::GetInputArrayInformation(int idx)
{
  // add this info into the algorithms info object
  vtkInformationVector *inArrayVec = 
    this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
  if (!inArrayVec)
    {
    inArrayVec = vtkInformationVector::New();
    this->Information->Set(INPUT_ARRAYS_TO_PROCESS(),inArrayVec);
    inArrayVec->Delete();
    }
  vtkInformation *inArrayInfo = inArrayVec->GetInformationObject(idx);
  if (!inArrayInfo)
    {
    inArrayInfo = vtkInformation::New();
    inArrayVec->SetInformationObject(idx,inArrayInfo);
    inArrayInfo->Delete();
    }
  return inArrayInfo;
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputArrayToProcess(int idx, vtkInformation *inInfo)
{
  vtkInformation *info = this->GetInputArrayInformation(idx);
  info->Copy(inInfo,1);
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputArrayToProcess(int idx, int port, int connection, 
                                          int fieldAssociation, 
                                          int attributeType)
{
  vtkInformation *info = this->GetInputArrayInformation(idx);

  info->Set(INPUT_PORT(), port);
  info->Set(INPUT_CONNECTION(), connection);
  info->Set(vtkDataObject::FIELD_ASSOCIATION(),fieldAssociation);
  info->Set(vtkDataObject::FIELD_ATTRIBUTE_TYPE(), attributeType);

  // remove name if there is one
  info->Remove(vtkDataObject::FIELD_NAME());  

  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputArrayToProcess(
  int idx, int port, int connection, 
  const char* fieldAssociation, 
  const char* fieldAttributeTypeOrName)
{
  if (!fieldAssociation)
    {
    vtkErrorMacro("Association is requied");
    return;
    }
  if (!fieldAttributeTypeOrName)
    {
    vtkErrorMacro("Attribute type or array name is required");
    return ;
    }

  int i;

  // Try to convert the string argument to an enum value
  int association = -1;
  for (i=0; i<vtkDataObject::NUMBER_OF_ASSOCIATIONS; i++)
    {
    if (strcmp(fieldAssociation, 
               vtkDataObject::GetAssociationTypeAsString(i)) == 0)
      {
      association = i;
      break;
      }
    }
  if (association == -1)
    {
    vtkErrorMacro("Unrecognized association type: " << fieldAssociation);
    return;
    }
                 
  int attributeType = -1;
  for (i=0; i<vtkDataSetAttributes::NUM_ATTRIBUTES; i++)
    {
    if (strcmp(fieldAttributeTypeOrName, 
               vtkDataSetAttributes::GetLongAttributeTypeAsString(i)) == 0)
      {
      attributeType = i;
      break;
      }
    }
  if (attributeType == -1)
    {
    // Set by association and array name
    this->SetInputArrayToProcess(
      idx, port, connection, association, fieldAttributeTypeOrName);
    return;
    }

  // Set by association and attribute type
  this->SetInputArrayToProcess(
    idx, port, connection, association, attributeType);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputArrayToProcess(int idx, int port, int connection, 
                                          int fieldAssociation, 
                                          const char *name)
{
  // ignore empty string
  if (!name || name[0] == '\0')
    {
    return;
    }
  
  vtkInformation *info = this->GetInputArrayInformation(idx);
  
  info->Set(INPUT_PORT(), port);
  info->Set(INPUT_CONNECTION(), connection);
  info->Set(vtkDataObject::FIELD_ASSOCIATION(),fieldAssociation);
  info->Set(vtkDataObject::FIELD_NAME(),name);

  // remove fieldAttr if there is one
  info->Remove(vtkDataObject::FIELD_ATTRIBUTE_TYPE());

  this->Modified();
}
//----------------------------------------------------------------------------
vtkDataArray *vtkAlgorithm::GetInputArrayToProcess(
  int idx, vtkInformationVector **inputVector)
{
  return vtkDataArray::SafeDownCast(
    this->GetInputAbstractArrayToProcess(idx, inputVector));
}

//----------------------------------------------------------------------------
vtkDataArray *vtkAlgorithm::GetInputArrayToProcess(
  int idx, int connection, vtkInformationVector **inputVector)
{
  return vtkDataArray::SafeDownCast(this->GetInputAbstractArrayToProcess(
      idx, connection, inputVector));
}

//----------------------------------------------------------------------------
vtkDataArray *vtkAlgorithm::GetInputArrayToProcess(
  int idx, vtkDataObject* input)
{
  return vtkDataArray::SafeDownCast(this->GetInputAbstractArrayToProcess(idx,
      input));
}

//----------------------------------------------------------------------------
vtkAbstractArray *vtkAlgorithm::GetInputAbstractArrayToProcess(
  int idx, vtkInformationVector **inputVector)
{
  vtkInformationVector *inArrayVec = 
    this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
  if (!inArrayVec)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }
  vtkInformation *inArrayInfo = inArrayVec->GetInformationObject(idx);
  if (!inArrayInfo)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }

  int connection = inArrayInfo->Get(INPUT_CONNECTION());
  return this->GetInputAbstractArrayToProcess(idx, connection, inputVector);
}

//----------------------------------------------------------------------------
vtkAbstractArray* vtkAlgorithm::GetInputAbstractArrayToProcess(
  int idx, int connection, vtkInformationVector **inputVector)
{
  vtkInformationVector *inArrayVec = 
    this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
  if (!inArrayVec)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }
  vtkInformation *inArrayInfo = inArrayVec->GetInformationObject(idx);
  if (!inArrayInfo)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }

  int port = inArrayInfo->Get(INPUT_PORT());
  vtkInformation *inInfo = inputVector[port]->GetInformationObject(connection);
  vtkDataObject *input = inInfo->Get(vtkDataObject::DATA_OBJECT());

  return this->GetInputAbstractArrayToProcess(idx, input);
}

//----------------------------------------------------------------------------
vtkAbstractArray* vtkAlgorithm::GetInputAbstractArrayToProcess(
  int idx, vtkDataObject* input)
{
  if (!input)
    {
    return NULL;
    }

  vtkInformationVector *inArrayVec = 
    this->Information->Get(INPUT_ARRAYS_TO_PROCESS());
  if (!inArrayVec)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }
  vtkInformation *inArrayInfo = inArrayVec->GetInformationObject(idx);
  if (!inArrayInfo)
    {
    vtkErrorMacro
      ("Attempt to get an input array for an index that has not been specified");
    return NULL;
    }

  int fieldAssoc = inArrayInfo->Get(vtkDataObject::FIELD_ASSOCIATION());
  
  if (inArrayInfo->Has(vtkDataObject::FIELD_NAME()))
    {
    const char *name = inArrayInfo->Get(vtkDataObject::FIELD_NAME());
  
    if (fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_NONE)
      {
      vtkFieldData *fd = input->GetFieldData();
      return fd->GetAbstractArray(name);
      }
    
    vtkDataSet *inputDS = vtkDataSet::SafeDownCast(input);
    if (!inputDS)
      {
      vtkErrorMacro("Attempt to get point or cell data from a data object");
      return NULL;
      }

    if (fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS)
      {
      return inputDS->GetPointData()->GetAbstractArray(name);
      }
    if (fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS
        && inputDS->GetPointData()->GetAbstractArray(name))
      {
      return inputDS->GetPointData()->GetAbstractArray(name);
      }
    
    return inputDS->GetCellData()->GetAbstractArray(name);
    }
  else
    {
    vtkDataSet *inputDS = vtkDataSet::SafeDownCast(input);
    if (!inputDS)
      {
      vtkErrorMacro("Attempt to get point or cell data from a data object");
      return NULL;
      }
    int fType = inArrayInfo->Get(vtkDataObject::FIELD_ATTRIBUTE_TYPE());
    if (fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS)
      {
      return inputDS->GetPointData()->GetAbstractAttribute(fType);
      }
    if (fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS
        && inputDS->GetPointData()->GetAbstractAttribute(fType))
      {
      return inputDS->GetPointData()->GetAbstractAttribute(fType);
      }
    
    return inputDS->GetCellData()->GetAbstractAttribute(fType);
    }
}


//----------------------------------------------------------------------------
void vtkAlgorithm::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  if(this->HasExecutive())
    {
    os << indent << "Executive: " << this->Executive << "\n";
    }
  else
    {
    os << indent << "Executive: (none)\n";
    }
  
  os << indent << "ErrorCode: " << 
    vtkErrorCode::GetStringFromErrorCode(this->ErrorCode) << endl;
  
  if ( this->Information )
    {
    os << indent << "Information: " << this->Information << "\n";
    }
  else
    {
    os << indent << "Information: (none)\n";
    }

  os << indent << "AbortExecute: " << (this->AbortExecute ? "On\n" : "Off\n");
  os << indent << "Progress: " << this->Progress << "\n";
  if ( this->ProgressText )
    {
    os << indent << "Progress Text: " << this->ProgressText << "\n";
    }
  else
    {
    os << indent << "Progress Text: (None)\n";
    }
}

//----------------------------------------------------------------------------
int vtkAlgorithm::HasExecutive()
{
  return this->Executive ? 1 : 0;
}

//----------------------------------------------------------------------------
vtkExecutive* vtkAlgorithm::GetExecutive()
{
  // Create the default executive if we do not have one already.
  if(!this->HasExecutive())
    {
    vtkExecutive* e = this->CreateDefaultExecutive();
    this->SetExecutive(e);
    e->Delete();
    }
  return this->Executive;
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetExecutive(vtkExecutive* newExecutive)
{
  vtkExecutive* oldExecutive = this->Executive;
  if(newExecutive != oldExecutive)
    {
    if(newExecutive)
      {
      newExecutive->Register(this);
      vtkAlgorithmToExecutiveFriendship::SetAlgorithm(newExecutive, this);
      }
    this->Executive = newExecutive;
    if(oldExecutive)
      {
      vtkAlgorithmToExecutiveFriendship::SetAlgorithm(oldExecutive, 0);
      oldExecutive->UnRegister(this);
      }
    }
}

//----------------------------------------------------------------------------
int vtkAlgorithm::ProcessRequest(vtkInformation* /* request */,
                                 vtkInformationVector**,
                                 vtkInformationVector*)
{
  return 1;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::ComputePipelineMTime(vtkInformation* /* request */,
                                       vtkInformationVector**,
                                       vtkInformationVector*,
                                       int /* requestFromOutputPort */,
                                       unsigned long* mtime)
{
  // By default algorithms contribute only their own modified time.
  *mtime = this->GetMTime();
  return 1;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::ModifyRequest(vtkInformation* /*request*/, int /*when*/)
{
  return 1;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::GetNumberOfInputPorts()
{
  return this->InputPortInformation->GetNumberOfInformationObjects();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetNumberOfInputPorts(int n)
{
  // Sanity check.
  if(n < 0)
    {
    vtkErrorMacro("Attempt to set number of input ports to " << n);
    n = 0;
    }

  // We must remove all connections from ports that are removed.
  for(int i=n; i < this->GetNumberOfInputPorts(); ++i)
    {
    this->SetNumberOfInputConnections(i, 0);
    }

  // Set the number of input port information objects.
  this->InputPortInformation->SetNumberOfInformationObjects(n);
}

//----------------------------------------------------------------------------
int vtkAlgorithm::GetNumberOfOutputPorts()
{
  return this->OutputPortInformation->GetNumberOfInformationObjects();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetNumberOfOutputPorts(int n)
{
  // Sanity check.
  if(n < 0)
    {
    vtkErrorMacro("Attempt to set number of output ports to " << n);
    n = 0;
    }

  // We must remove all connections from ports that are removed.
  for(int i=n; i < this->GetNumberOfOutputPorts(); ++i)
    {
    // Get the producer and its output information for this port.
    vtkExecutive* producer = this->GetExecutive();
    vtkInformation* info = producer->GetOutputInformation(i);

    // Remove all consumers' references to this producer on this port.
    vtkExecutive** consumers = info->GetExecutives(vtkExecutive::CONSUMERS());
    int* consumerPorts = info->GetPorts(vtkExecutive::CONSUMERS());
    int consumerCount = info->Length(vtkExecutive::CONSUMERS());
    for(int j=0; j < consumerCount; ++j)
      {
      vtkInformationVector* inputs =
        consumers[j]->GetInputInformation(consumerPorts[j]);
      inputs->Remove(info);
      }

    // Remove this producer's references to all consumers on this port.
    info->Remove(vtkExecutive::CONSUMERS());
    }

  // Set the number of output port information objects.
  this->OutputPortInformation->SetNumberOfInformationObjects(n);

  // Set the number of connection proxy objects.
  this->AlgorithmInternal->Outputs.resize(n);
}

//----------------------------------------------------------------------------
vtkInformation* vtkAlgorithm::GetInputPortInformation(int port)
{
  if(!this->InputPortIndexInRange(port, "get information object for"))
    {
    return 0;
    }

  // Get the input port information object.
  vtkInformation* info =
    this->InputPortInformation->GetInformationObject(port);

  // Fill it if it has not yet been filled.
  if(!info->Has(PORT_REQUIREMENTS_FILLED()))
    {
    if(this->FillInputPortInformation(port, info))
      {
      info->Set(PORT_REQUIREMENTS_FILLED(), 1);
      }
    else
      {
      info->Clear();
      }
    }

  // Return ths information object.
  return info;
}

//----------------------------------------------------------------------------
vtkInformation* vtkAlgorithm::GetOutputPortInformation(int port)
{
  if(!this->OutputPortIndexInRange(port, "get information object for"))
    {
    return 0;
    }

  // Get the output port information object.
  vtkInformation* info =
    this->OutputPortInformation->GetInformationObject(port);

  // Fill it if it has not yet been filled.
  if(!info->Has(PORT_REQUIREMENTS_FILLED()))
    {
    if(this->FillOutputPortInformation(port, info))
      {
      info->Set(PORT_REQUIREMENTS_FILLED(), 1);
      }
    else
      {
      info->Clear();
      }
    }

  // Return ths information object.
  return info;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::FillInputPortInformation(int, vtkInformation*)
{
  vtkErrorMacro("FillInputPortInformation is not implemented.");
  return 0;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::FillOutputPortInformation(int, vtkInformation*)
{
  vtkErrorMacro("FillOutputPortInformation is not implemented.");
  return 0;
}


//----------------------------------------------------------------------------
int vtkAlgorithm::InputPortIndexInRange(int index, const char* action)
{
  // Make sure the index of the input port is in range.
  if(index < 0 || index >= this->GetNumberOfInputPorts())
    {
    vtkErrorMacro("Attempt to " << (action?action:"access")
                  << " input port index " << index
                  << " for an algorithm with "
                  << this->GetNumberOfInputPorts() << " input ports.");
    return 0;
    }
  return 1;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::OutputPortIndexInRange(int index, const char* action)
{
  // Make sure the index of the output port is in range.
  if(index < 0 || index >= this->GetNumberOfOutputPorts())
    {
    vtkErrorMacro("Attempt to " << (action?action:"access")
                  << " output port index " << index
                  << " for an algorithm with "
                  << this->GetNumberOfOutputPorts() << " output ports.");
    return 0;
    }
  return 1;
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetDefaultExecutivePrototype(vtkExecutive* proto)
{
  if (vtkAlgorithm::DefaultExecutivePrototype == proto)
    {
    return;
    }
  if (vtkAlgorithm::DefaultExecutivePrototype)
    {
    vtkAlgorithm::DefaultExecutivePrototype->UnRegister(0);
    vtkAlgorithm::DefaultExecutivePrototype = 0;
    }
  if (proto)
    {
    proto->Register(0);
    }
  vtkAlgorithm::DefaultExecutivePrototype = proto;
}

//----------------------------------------------------------------------------
vtkExecutive* vtkAlgorithm::CreateDefaultExecutive()
{
  if (vtkAlgorithm::DefaultExecutivePrototype)
    {
    return vtkAlgorithm::DefaultExecutivePrototype->NewInstance();
    }
  return vtkStreamingDemandDrivenPipeline::New();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::Register(vtkObjectBase* o)
{
  this->RegisterInternal(o, 1);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::UnRegister(vtkObjectBase* o)
{
  this->UnRegisterInternal(o, 1);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::ReportReferences(vtkGarbageCollector* collector)
{
  this->Superclass::ReportReferences(collector);
  vtkGarbageCollectorReport(collector, this->Executive, "Executive");
}



/// These are convenience methods to forward to the executive


//----------------------------------------------------------------------------
vtkDataObject* vtkAlgorithm::GetOutputDataObject(int port)
{
  return this->GetExecutive()->GetOutputData(port);
}

//----------------------------------------------------------------------------
vtkDataObject *vtkAlgorithm::GetInputDataObject(int port,
                                                int connection)
{
  return this->GetExecutive()->GetInputData(port,connection);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::RemoveAllInputs()
{
  this->SetInputConnection(0, 0);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputConnection(vtkAlgorithmOutput* input)
{
  this->SetInputConnection(0,input);
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetInputConnection(int port, vtkAlgorithmOutput* input)
{
  if(!this->InputPortIndexInRange(port, "connect"))
    {
    return;
    }

  // Get the producer/consumer pair for the connection.
  vtkExecutive* producer =
    (input && input->GetProducer())? input->GetProducer()->GetExecutive() : 0;
  int producerPort = producer? input->GetIndex() : 0;
  vtkExecutive* consumer = this->GetExecutive();
  int consumerPort = port;

  // Get the vector of connected input information objects.
  vtkInformationVector* inputs = consumer->GetInputInformation(consumerPort);

  // Get the information object from the producer of the new input.
  vtkInformation* newInfo =
    producer? producer->GetOutputInformation(producerPort) : 0;

  // Check if the connection is already present.
  if(!newInfo && inputs->GetNumberOfInformationObjects() == 0)
    {
    return;
    }
  else if(newInfo == inputs->GetInformationObject(0) &&
          inputs->GetNumberOfInformationObjects() == 1)
    {
    return;
    }

  // The connection is not present.
  vtkDebugMacro("Setting connection to input port index " << consumerPort
                << " from output port index " << producerPort
                << " on algorithm "
                << (producer? producer->GetAlgorithm()->GetClassName() : "")
                << "(" << (producer? producer->GetAlgorithm() : 0) << ").");

  // Add this consumer to the new input's list of consumers.
  if(newInfo)
    {
    newInfo->Append(vtkExecutive::CONSUMERS(), consumer, consumerPort);
    }

  // Remove this consumer from all old inputs' lists of consumers.
  for(int i=0; i < inputs->GetNumberOfInformationObjects(); ++i)
    {
    if(vtkInformation* oldInfo = inputs->GetInformationObject(i))
      {
      oldInfo->Remove(vtkExecutive::CONSUMERS(), consumer, consumerPort);
      }
    }

  // Make the new input the only connection.
  if(newInfo)
    {
    inputs->SetInformationObject(0, newInfo);
    inputs->SetNumberOfInformationObjects(1);
    }
  else
    {
    inputs->SetNumberOfInformationObjects(0);
    }

  // This algorithm has been modified.
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::AddInputConnection(vtkAlgorithmOutput* input)
{
  this->AddInputConnection(0, input);
}
void vtkAlgorithm::AddInputConnection(int port, vtkAlgorithmOutput* input)
{
  if(!this->InputPortIndexInRange(port, "connect"))
    {
    return;
    }

  // If there is no input do nothing.
  if(!input || !input->GetProducer())
    {
    return;
    }

  // Get the producer/consumer pair for the connection.
  vtkExecutive* producer = input->GetProducer()->GetExecutive();
  int producerPort = input->GetIndex();
  vtkExecutive* consumer = this->GetExecutive();
  int consumerPort = port;

  // Get the vector of connected input information objects.
  vtkInformationVector* inputs = consumer->GetInputInformation(consumerPort);

  // Add the new connection.
  vtkDebugMacro("Adding connection to input port index " << consumerPort
                << " from output port index " << producerPort
                << " on algorithm "
                << (producer? producer->GetAlgorithm()->GetClassName() : "")
                << "(" << (producer? producer->GetAlgorithm() : 0) << ").");

  // Get the information object from the producer of the new input.
  vtkInformation* newInfo = producer->GetOutputInformation(producerPort);

  // Add this consumer to the input's list of consumers.
  newInfo->Append(vtkExecutive::CONSUMERS(), consumer, consumerPort);

  // Add the information object to the list of inputs.
  inputs->Append(newInfo);

  // This algorithm has been modified.
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::RemoveInputConnection(int port, vtkAlgorithmOutput* input)
{
  if(!this->InputPortIndexInRange(port, "disconnect"))
    {
    return;
    }

  // If there is no input do nothing.
  if(!input || !input->GetProducer())
    {
    return;
    }

  // Get the producer/consumer pair for the connection.
  vtkExecutive* producer = input->GetProducer()->GetExecutive();
  int producerPort = input->GetIndex();
  vtkExecutive* consumer = this->GetExecutive();
  int consumerPort = port;

  // Get the vector of connected input information objects.
  vtkInformationVector* inputs = consumer->GetInputInformation(consumerPort);

  // Remove the connection.
  vtkDebugMacro("Removing connection to input port index " << consumerPort
                << " from output port index " << producerPort
                << " on algorithm "
                << (producer? producer->GetAlgorithm()->GetClassName() : "")
                << "(" << (producer? producer->GetAlgorithm() : 0) << ").");

  // Get the information object from the producer of the old input.
  vtkInformation* oldInfo = producer->GetOutputInformation(producerPort);

  // Remove this consumer from the old input's list of consumers.
  oldInfo->Remove(vtkExecutive::CONSUMERS(), consumer, consumerPort);

  // Remove the information object from the list of inputs.
  inputs->Remove(oldInfo);

  // This algorithm has been modified.
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetNthInputConnection(int port, int index,
                                         vtkAlgorithmOutput* input)
{
  if(!this->InputPortIndexInRange(port, "replace connection"))
    {
    return;
    }

  // Get the producer/consumer pair for the connection.
  vtkExecutive* producer =
    (input && input->GetProducer())? input->GetProducer()->GetExecutive() : 0;
  int producerPort = producer? input->GetIndex() : 0;
  vtkExecutive* consumer = this->GetExecutive();
  int consumerPort = port;

  // Get the vector of connected input information objects.
  vtkInformationVector* inputs = consumer->GetInputInformation(consumerPort);

  // Check for any existing connection with this index.
  vtkInformation* oldInfo = inputs->GetInformationObject(index);

  // Get the information object from the producer of the input.
  vtkInformation* newInfo =
    producer? producer->GetOutputInformation(producerPort) : 0;

  // If the connection has not changed, do nothing.
  if(newInfo == oldInfo)
    {
    return;
    }

  // Set the connection.
  vtkDebugMacro("Setting connection index " << index
                << " to input port index " << consumerPort
                << " from output port index " << producerPort
                << " on algorithm "
                << (producer? producer->GetAlgorithm()->GetClassName() : "")
                << "(" << (producer? producer->GetAlgorithm() : 0) << ").");

  // Add the consumer to the new input's list of consumers.
  if(newInfo)
    {
    newInfo->Append(vtkExecutive::CONSUMERS(), consumer, consumerPort);
    }

  // Remove the consumer from the old input's list of consumers.
  if(oldInfo)
    {
    oldInfo->Remove(vtkExecutive::CONSUMERS(), consumer, consumerPort);
    }

  // Store the information object in the vector of input connections.
  inputs->SetInformationObject(index, newInfo);

  // This algorithm has been modified.
  this->Modified();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetNumberOfInputConnections(int port, int n)
{
  // Get the consumer executive and port number.
  vtkExecutive* consumer = this->GetExecutive();
  int consumerPort = port;

  // Get the vector of connected input information objects.
  vtkInformationVector* inputs = consumer->GetInputInformation(consumerPort);

  // If the number of connections has not changed, do nothing.
  if(n == inputs->GetNumberOfInformationObjects())
    {
    return;
    }

  // Remove connections beyond the new number.
  for(int i=n; i < inputs->GetNumberOfInformationObjects(); ++i)
    {
    // Remove each input's reference to this consumer.
    if(vtkInformation* oldInfo = inputs->GetInformationObject(i))
      {
      oldInfo->Remove(vtkExecutive::CONSUMERS(), consumer, consumerPort);
      }
    }

  // Set the number of connected inputs.  Non-existing inputs will be
  // empty information objects.
  inputs->SetNumberOfInformationObjects(n);

  // This algorithm has been modified.
  this->Modified();
}

//----------------------------------------------------------------------------
vtkAlgorithmOutput* vtkAlgorithm::GetOutputPort(int port)
{
  if(!this->OutputPortIndexInRange(port, "get"))
    {
    return 0;
    }

  // Create the vtkAlgorithmOutput proxy object if there is not one.
  if(!this->AlgorithmInternal->Outputs[port])
    {
    this->AlgorithmInternal->Outputs[port] =
      vtkSmartPointer<vtkAlgorithmOutput>::New();
    this->AlgorithmInternal->Outputs[port]->SetProducer(this);
    this->AlgorithmInternal->Outputs[port]->SetIndex(port);
    }

  // Return the proxy object instance.
  return this->AlgorithmInternal->Outputs[port];
}


//----------------------------------------------------------------------------
int vtkAlgorithm::GetNumberOfInputConnections(int port)
{
  if(this->Executive)
    {
    return this->Executive->GetNumberOfInputConnections(port);
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::GetTotalNumberOfInputConnections()
{
  int i;
  int total = 0;
  for (i = 0; i < this->GetNumberOfInputPorts(); ++i)
    {
    total += this->GetNumberOfInputConnections(i);
    }
  return total;
}

//----------------------------------------------------------------------------
vtkAlgorithmOutput* vtkAlgorithm::GetInputConnection(int port, int index)
{
  if(index < 0 || index >= this->GetNumberOfInputConnections(port))
    {
    vtkErrorMacro("Attempt to get connection index " << index
                  << " for input port " << port << ", which has "
                  << this->GetNumberOfInputConnections(port)
                  << " connections.");
    return 0;
    }
  if(vtkInformation* info =
     this->GetExecutive()->GetInputInformation(port, index))
    {
    // Get the executive producing this input.  If there is none, then
    // it is a NULL input.
    vtkExecutive* producer;
    int producerPort;
    info->Get(vtkExecutive::PRODUCER(),producer,producerPort);
    if(producer)
      {
      return producer->GetAlgorithm()->GetOutputPort(producerPort);
      }
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkAlgorithm::Update()
{
  this->GetExecutive()->Update();
}

//----------------------------------------------------------------------------
void vtkAlgorithm::UpdateInformation()
{
  vtkDemandDrivenPipeline* ddp =
    vtkDemandDrivenPipeline::SafeDownCast(this->GetExecutive());
  if (ddp)
    {
    ddp->UpdateInformation();
    }
}

//----------------------------------------------------------------------------
void vtkAlgorithm::UpdateWholeExtent()
{
  vtkStreamingDemandDrivenPipeline* sddp =
    vtkStreamingDemandDrivenPipeline::SafeDownCast(this->GetExecutive());
  if (sddp)
    {
    sddp->UpdateWholeExtent();
    }
  else
    {
    this->Update();
    }
}


//----------------------------------------------------------------------------
void vtkAlgorithm::ConvertTotalInputToPortConnection(
  int ind, int &port, int &conn)
{
  port = 0;
  conn = 0;
  while (ind && port < this->GetNumberOfInputPorts())
    {
    int pNumCon;
    pNumCon = this->GetNumberOfInputConnections(port);
    if (ind >= pNumCon)
      {
      port++;
      ind -= pNumCon;
      }
    else
      {
      return;
      }
    }
}

//----------------------------------------------------------------------------
void vtkAlgorithm::ReleaseDataFlagOn()
{
  if(vtkDemandDrivenPipeline* ddp =
     vtkDemandDrivenPipeline::SafeDownCast(this->GetExecutive()))
    {
    for(int i=0; i < this->GetNumberOfOutputPorts(); ++i)
      {
      ddp->SetReleaseDataFlag(i, 1);
      }
    }
}

//----------------------------------------------------------------------------
void vtkAlgorithm::ReleaseDataFlagOff()
{
  if(vtkDemandDrivenPipeline* ddp =
     vtkDemandDrivenPipeline::SafeDownCast(this->GetExecutive()))
    {
    for(int i=0; i < this->GetNumberOfOutputPorts(); ++i)
      {
      ddp->SetReleaseDataFlag(i, 0);
      }
    }
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetReleaseDataFlag(int val)
{
  if(vtkDemandDrivenPipeline* ddp =
     vtkDemandDrivenPipeline::SafeDownCast(this->GetExecutive()))
    {
    for(int i=0; i < this->GetNumberOfOutputPorts(); ++i)
      {
      ddp->SetReleaseDataFlag(i, val);
      }
    }
}

//----------------------------------------------------------------------------
int vtkAlgorithm::GetReleaseDataFlag()
{
  if(vtkDemandDrivenPipeline* ddp =
     vtkDemandDrivenPipeline::SafeDownCast(this->GetExecutive()))
    {
    return ddp->GetReleaseDataFlag(0);
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkAlgorithm::UpdateExtentIsEmpty(vtkDataObject *output)
{
  if (output == NULL)
    {
    return 1;
    }

  // get the pinfo object then call the info signature
  return this->UpdateExtentIsEmpty(
    output->GetPipelineInformation(),
    output->GetInformation()->Get(vtkDataObject::DATA_EXTENT_TYPE()));
}

  
//----------------------------------------------------------------------------
int vtkAlgorithm::UpdateExtentIsEmpty(vtkInformation *info, int extentType)
{
  if (!info)
    {
    return 1;
    }
  
  int *ext;
  
  switch (extentType)
    {
    case VTK_PIECES_EXTENT:
      // Special way of asking for no input.
      if (info->Get(
            vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()) == 0 )
        {
        return 1;
        }
      break;
      
    case VTK_3D_EXTENT:
      ext = info->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT());
      // Special way of asking for no input. (zero volume)
      if (!ext || ext[0] == (ext[1] + 1) ||
          ext[2] == (ext[3] + 1) ||
          ext[4] == (ext[5] + 1))
        {
        return 1;
        }
      break;

      // We should never have this case occur
    default:
      vtkErrorMacro( << "Internal error - invalid extent type!" );
      break;
    }

  return 0;
}

//----------------------------------------------------------------------------
void vtkAlgorithm::SetProgressText(const char* ptext)
{
  if (!this->ProgressText  && !ptext)
    {
    return;
    }
  if (this->ProgressText && ptext && (strcmp(this->ProgressText,ptext)) == 0) 
    {
    return;
    }
  if (this->ProgressText) 
    {
    delete[] this->ProgressText;
    this->ProgressText = 0;
    }
  if (ptext)
    {
    size_t n = strlen(ptext) + 1;
    char *cp1 =  new char[n];
    const char *cp2 = ptext;
    this->ProgressText = cp1;
    do { *cp1++ = *cp2++; } while ( --n );
    }
}
