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

  Program:   ParaView
  Module:    vtkSMExtentDomain.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 "vtkSMExtentDomain.h"

#include "vtkObjectFactory.h"
#include "vtkPVDataInformation.h"
#include "vtkSMInputProperty.h"
#include "vtkSMIntVectorProperty.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMSourceProxy.h"

vtkStandardNewMacro(vtkSMExtentDomain);

//---------------------------------------------------------------------------
vtkSMExtentDomain::vtkSMExtentDomain()
{
}

//---------------------------------------------------------------------------
vtkSMExtentDomain::~vtkSMExtentDomain()
{
}

//---------------------------------------------------------------------------
void vtkSMExtentDomain::Update(vtkSMProperty*)
{
  vtkSMProxyProperty* pp = vtkSMProxyProperty::SafeDownCast(this->GetRequiredProperty("Input"));
  if (pp)
  {
    this->Update(pp);
  }
}

//---------------------------------------------------------------------------
void vtkSMExtentDomain::Update(vtkSMProxyProperty* pp)
{
  vtkSMInputProperty* ip = vtkSMInputProperty::SafeDownCast(pp);

  unsigned int numProxs = pp->GetNumberOfUncheckedProxies();
  for (unsigned int i = 0; i < numProxs; i++)
  {
    vtkSMSourceProxy* sp = vtkSMSourceProxy::SafeDownCast(pp->GetUncheckedProxy(i));
    if (sp)
    {
      vtkPVDataInformation* info =
        sp->GetDataInformation((ip ? ip->GetUncheckedOutputPortForConnection(i) : 0));
      if (!info)
      {
        continue;
      }
      int extent[6];
      info->GetExtent(extent);

      std::vector<vtkEntry> entries;
      for (int j = 0; j < 3; j++)
      {
        entries.push_back(vtkEntry(extent[2 * j], extent[2 * j + 1]));
      }
      this->SetEntries(entries);
      return;
    }
  }
}

//---------------------------------------------------------------------------
void vtkSMExtentDomain::SetAnimationValue(vtkSMProperty* property, int idx, double value)
{
  int compare;
  int animValue = (int)(floor(value));

  vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast(property);
  if (ivp)
  {
    switch (idx)
    {
      case 0:
      case 2:
      case 4:
        compare = ivp->GetElement(idx + 1);
        if (animValue > compare)
        {
          ivp->SetElement(idx + 1, animValue);
        }
        ivp->SetElement(idx, animValue);
        break;
      case 1:
      case 3:
      case 5:
        compare = ivp->GetElement(idx - 1);
        if (animValue < compare)
        {
          ivp->SetElement(idx - 1, animValue);
        }
        ivp->SetElement(idx, animValue);
        break;
      default:
        vtkErrorMacro("Invalid extent index.");
        break;
    }
  }
}

//---------------------------------------------------------------------------
int vtkSMExtentDomain::SetDefaultValues(vtkSMProperty* property, bool use_unchecked_values)
{
  vtkSMIntVectorProperty* ivp = vtkSMIntVectorProperty::SafeDownCast(property);
  unsigned int numElems = ivp ? ivp->GetNumberOfElements() : 0;
  if (ivp && (numElems % 2 == 0))
  {
    vtkSMPropertyHelper helper(property);
    helper.SetUseUnchecked(use_unchecked_values);
    for (unsigned int cc = 0; cc < numElems / 2; cc++)
    {
      if (this->GetMinimumExists(cc))
      {
        helper.Set(2 * cc, this->GetMinimum(cc));
      }
      if (this->GetMaximumExists(cc))
      {
        helper.Set(2 * cc + 1, this->GetMaximum(cc));
      }
    }
    return 1;
  }
  return this->Superclass::SetDefaultValues(property, use_unchecked_values);
}

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