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

#include "vtkCMBArcManager.h"
#include "vtkCMBArc.h"
#include "vtkCMBArcEndNode.h"

#include "vtkObjectFactory.h"

#include <list>

vtkStandardNewMacro(vtkCMBArcSplitOnIndexOperator);

namespace
{
struct iPoint
  {
  public:
  double x,y,z;
  vtkIdType ptId;
  iPoint(double xin, double yin, double zin, vtkIdType id)
  : x(xin), y(yin), z(zin), ptId(id)
  {}
  };
}

//----------------------------------------------------------------------------
vtkCMBArcSplitOnIndexOperator::vtkCMBArcSplitOnIndexOperator()
{
  this->Index = -1;
}

//----------------------------------------------------------------------------
vtkCMBArcSplitOnIndexOperator::~vtkCMBArcSplitOnIndexOperator()
{

}

//----------------------------------------------------------------------------
bool vtkCMBArcSplitOnIndexOperator::Operate(vtkIdType arcId)
{
  //we have to reset the CreatedArcId everytime we split
  //so that we can use the same operator for multiple split operations
  this->CreatedArcId = -1;
  vtkCMBArc *arc = vtkCMBArcManager::GetInstance()->GetArc(arcId);
  if (!arc)
    {
    return false;
    }

  if ( this->Index < 0)
    {
    return false;
    }

  //copy of all points we iterate before the split position
  std::list<vtkCMBArc::Point> originalPoints;

  //go through the points of the arc and split it on the index
  int i=0;
  vtkCMBArc::Point point;
  bool foundSplitPoint = false;
  arc->InitTraversal();
  while (arc->GetNextPoint(point))
    {
    if (i == this->Index)
      {
      foundSplitPoint = true;
      break;
      }
    else
      {
      originalPoints.push_back(point);
      }
    ++i;
    }

  if (!foundSplitPoint)
    {
    //we can't split this arc at all
    return false;
    }

  //we found the valid index to split on.
  vtkCMBArc* createdArc = vtkCMBArc::New();

  //record the id of the arc we created with the split
  this->CreatedArcId = createdArc->GetId();

  //setup the new end nodes for both arcs
  createdArc->SetEndNode(0, point);
  vtkCMBArc::Point point2;
  arc->GetEndNode(1)->GetPosition(point2);
  createdArc->SetEndNode(1, point2);
  arc->SetEndNode(1,point);

  //now move all the interal end points after the split
  //point to the createdArc
  while (arc->GetNextPoint(point))
    {
    createdArc->InsertNextPoint(point);
    }

  //now clear the original arc internal points
  //and reset its internal points to all the points before the split
  arc->ClearPoints();

  std::list<vtkCMBArc::Point>::iterator it;
  for (it = originalPoints.begin(); it != originalPoints.end(); it++)
    {
    arc->InsertNextPoint(*it);
    }
  return true;
}

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