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

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

#include "vtkContext2D.h"
#include "vtkPen.h"
#include "vtkBrush.h"
#include "vtkColorSeries.h"

#include "vtkTransform2D.h"
#include "vtkContextScene.h"
#include "vtkContextMouseEvent.h"
#include "vtkContextKeyEvent.h"
#include "vtkContextTransform.h"
#include "vtkContextClip.h"
#include "vtkPoints2D.h"
#include "vtkVector.h"
#include "vtkVectorOperators.h"

#include "vtkPlotBar.h"
#include "vtkPlotStacked.h"
#include "vtkPlotLine.h"
#include "vtkPlotPoints.h"
#include "vtkContextMapper2D.h"

#include "vtkAxis.h"
#include "vtkPlotGrid.h"
#include "vtkChartLegend.h"
#include "vtkTooltipItem.h"

#include "vtkTable.h"
#include "vtkIdTypeArray.h"

#include "vtkAnnotationLink.h"
#include "vtkSelection.h"
#include "vtkSelectionNode.h"
#include "vtkSmartPointer.h"

#include "vtkObjectFactory.h"
#include "vtkCommand.h"

#include "vtkStdString.h"
#include "vtkTextProperty.h"

#include "vtkDataArray.h"
#include "vtkStringArray.h"

// My STL containers
#include <vector>
#include <algorithm>

//-----------------------------------------------------------------------------
class vtkChartXYPrivate
{
public:
  vtkChartXYPrivate()
    {
    this->Colors = vtkSmartPointer<vtkColorSeries>::New();
    this->Clip = vtkSmartPointer<vtkContextClip>::New();
    this->Borders[0] = 60;
    this->Borders[1] = 50;
    this->Borders[2] = 20;
    this->Borders[3] = 20;
    }

  std::vector<vtkPlot *> plots; // Charts can contain multiple plots of data
  std::vector<vtkContextTransform *> PlotCorners; // Stored by corner...
  std::vector<vtkAxis *> axes; // Charts can contain multiple axes
  vtkSmartPointer<vtkColorSeries> Colors; // Colors in the chart
  vtkSmartPointer<vtkContextClip> Clip; // Colors in the chart
  int Borders[4];
};

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkChartXY);

//-----------------------------------------------------------------------------
vtkChartXY::vtkChartXY()
{
  this->ChartPrivate = new vtkChartXYPrivate;

  this->AutoAxes = true;
  this->HiddenAxisBorder = 20;

  // The grid is drawn first.
  vtkPlotGrid *grid1 = vtkPlotGrid::New();
  this->AddItem(grid1);
  grid1->Delete();

  // The second grid for the far side/top axis
  vtkPlotGrid *grid2 = vtkPlotGrid::New();
  this->AddItem(grid2);
  grid2->Delete();

  // The plots are drawn on top of the grid, in a clipped, transformed area.
  this->AddItem(this->ChartPrivate->Clip);
  // Set up the bottom-left transform, the rest are often not required (set up
  // on demand if used later). Add it as a child item, rendered automatically.
  vtkSmartPointer<vtkContextTransform> corner =
      vtkSmartPointer<vtkContextTransform>::New();
  this->ChartPrivate->PlotCorners.push_back(corner);
  this->ChartPrivate->Clip->AddItem(corner); // Child list maintains ownership.

  // Next is the axes
  for (int i = 0; i < 4; ++i)
    {
    this->ChartPrivate->axes.push_back(vtkAxis::New());
    // By default just show the left and bottom axes
    this->ChartPrivate->axes.back()->SetVisible(i < 2 ? true : false);
    this->AttachAxisRangeListener(this->ChartPrivate->axes.back());
    this->AddItem(this->ChartPrivate->axes.back());
    }
  this->ChartPrivate->axes[vtkAxis::LEFT]->SetPosition(vtkAxis::LEFT);
  this->ChartPrivate->axes[vtkAxis::BOTTOM]->SetPosition(vtkAxis::BOTTOM);
  this->ChartPrivate->axes[vtkAxis::RIGHT]->SetPosition(vtkAxis::RIGHT);
  this->ChartPrivate->axes[vtkAxis::TOP]->SetPosition(vtkAxis::TOP);

  // Set up the x and y axes - should be configured based on data
  this->ChartPrivate->axes[vtkAxis::LEFT]->SetTitle("Y Axis");
  this->ChartPrivate->axes[vtkAxis::BOTTOM]->SetTitle("X Axis");

  grid1->SetXAxis(this->ChartPrivate->axes[vtkAxis::BOTTOM]);
  grid1->SetYAxis(this->ChartPrivate->axes[vtkAxis::LEFT]);
  grid2->SetXAxis(this->ChartPrivate->axes[vtkAxis::TOP]);
  grid2->SetYAxis(this->ChartPrivate->axes[vtkAxis::RIGHT]);

  // Then the legend is drawn
  this->Legend = vtkSmartPointer<vtkChartLegend>::New();
  this->Legend->SetChart(this);
  this->Legend->SetVisible(false);
  this->AddItem(this->Legend);

  this->PlotTransformValid = false;

  this->DrawBox = false;
  this->DrawNearestPoint = false;
  this->DrawAxesAtOrigin = false;
  this->BarWidthFraction = 0.8f;

  this->Tooltip = vtkSmartPointer<vtkTooltipItem>::New();
  this->Tooltip->SetVisible(false);
  this->AddItem(this->Tooltip);
  this->LayoutChanged = true;

  this->ForceAxesToBounds = false;
}

//-----------------------------------------------------------------------------
vtkChartXY::~vtkChartXY()
{
  for (unsigned int i = 0; i < this->ChartPrivate->plots.size(); ++i)
    {
    this->ChartPrivate->plots[i]->Delete();
    }
  for (size_t i = 0; i < 4; ++i)
    {
    this->ChartPrivate->axes[i]->Delete();
    }
  delete this->ChartPrivate;
  this->ChartPrivate = 0;
}

//-----------------------------------------------------------------------------
void vtkChartXY::Update()
{
  // Perform any necessary updates that are not graphical
  // Update the plots if necessary
  for (size_t i = 0; i < this->ChartPrivate->plots.size(); ++i)
    {
    this->ChartPrivate->plots[i]->Update();
    }
  this->Legend->Update();

  // Update the selections if necessary.
  if (this->AnnotationLink)
    {
    this->AnnotationLink->Update();
    vtkSelection *selection =
        vtkSelection::SafeDownCast(this->AnnotationLink->GetOutputDataObject(2));
    if (selection->GetNumberOfNodes())
      {
      vtkSelectionNode *node = selection->GetNode(0);
      vtkIdTypeArray *idArray =
          vtkIdTypeArray::SafeDownCast(node->GetSelectionList());
      // Now iterate through the plots to update selection data
      std::vector<vtkPlot*>::iterator it =
          this->ChartPrivate->plots.begin();
      for ( ; it != this->ChartPrivate->plots.end(); ++it)
        {
        (*it)->SetSelection(idArray);
        }
      }
    }
  else
    {
    vtkDebugMacro("No annotation link set.");
    }

  this->CalculateBarPlots();

  if (this->AutoAxes)
    {
    for (int i = 0; i < 4; ++i)
      {
      this->ChartPrivate->axes[i]->SetVisible(false);
      }
    for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
      {
      int visible = 0;
      for (unsigned int j = 0;
           j < this->ChartPrivate->PlotCorners[i]->GetNumberOfItems(); ++j)
        {
        if (vtkPlot::SafeDownCast(this->ChartPrivate->PlotCorners[i]
                                  ->GetItem(j))->GetVisible())
          {
          ++visible;
          }
        }
      if (visible)
        {
        if (i < 3)
          {
          this->ChartPrivate->axes[i]->SetVisible(true);
          this->ChartPrivate->axes[i+1]->SetVisible(true);
          }
        else
          {
          this->ChartPrivate->axes[0]->SetVisible(true);
          this->ChartPrivate->axes[3]->SetVisible(true);
          }
        }
      }
    }
}

//-----------------------------------------------------------------------------
bool vtkChartXY::Paint(vtkContext2D *painter)
{
  // This is where everything should be drawn, or dispatched to other methods.
  vtkDebugMacro(<< "Paint event called.");
  if (!this->Visible)
    {
    // The geometry of the chart must be valid before anything can be drawn
    return false;
    }

  vtkVector2i geometry(0, 0);
  bool recalculateTransform = false;
  if (this->LayoutStrategy == vtkChart::FILL_SCENE)
    {
    geometry = vtkVector2i(this->GetScene()->GetSceneWidth(),
                           this->GetScene()->GetSceneHeight());
    if (geometry.X() != this->Geometry[0] || geometry.Y() != this->Geometry[1])
      {
      recalculateTransform = true;
      this->LayoutChanged = true;
      }
    this->SetSize(vtkRectf(0.0, 0.0, geometry.X(), geometry.Y()));
    }

  int visiblePlots = 0;
  for (size_t i = 0; i < this->ChartPrivate->plots.size(); ++i)
    {
    if (this->ChartPrivate->plots[i]->GetVisible())
      {
      ++visiblePlots;
      }
    }
  if (visiblePlots == 0 && !this->RenderEmpty)
    {
    // Nothing to plot, so don't draw anything.
    return false;
    }

  this->Update();

  if (this->MTime < this->ChartPrivate->axes[0]->GetMTime())
    {
    // Cause the plot transform to be recalculated if necessary
    recalculateTransform = true;
    this->LayoutChanged = true;
    }

  this->UpdateLayout(painter);
  // Recalculate the plot transform, min and max values if necessary
  if (!this->PlotTransformValid)
    {
    this->RecalculatePlotBounds();
    recalculateTransform = true;
    }
  if (this->UpdateLayout(painter) || recalculateTransform)
    {
    this->RecalculatePlotTransforms();
    }

  // Update the clipping if necessary
  this->ChartPrivate->Clip->SetClip(this->Point1[0], this->Point1[1],
                                    this->Point2[0]-this->Point1[0],
                                    this->Point2[1]-this->Point1[1]);

  // draw background
  if(this->BackgroundBrush)
    {
    painter->GetPen()->SetLineType(vtkPen::NO_PEN);
    painter->ApplyBrush(this->BackgroundBrush);
    painter->DrawRect(this->Point1[0], this->Point1[1],
                      this->Geometry[0], this->Geometry[1]);
    }

  // Use the scene to render most of the chart.
  this->PaintChildren(painter);

  // Draw the selection box if necessary
  if (this->DrawBox)
    {
    painter->GetBrush()->SetColor(255, 255, 255, 0);
    painter->GetPen()->SetColor(0, 0, 0, 255);
    painter->GetPen()->SetWidth(1.0);
    painter->DrawRect(this->MouseBox.X(), this->MouseBox.Y(),
                      this->MouseBox.Width(), this->MouseBox.Height());
    }

  if (this->Title)
    {
    vtkPoints2D *rect = vtkPoints2D::New();
    rect->InsertNextPoint(this->Point1[0], this->Point2[1]);
    rect->InsertNextPoint(this->Point2[0]-this->Point1[0], 10);
    painter->ApplyTextProp(this->TitleProperties);
    painter->DrawStringRect(rect, this->Title);
    rect->Delete();
    }

  return true;
}

//-----------------------------------------------------------------------------
void vtkChartXY::CalculateBarPlots()
{
  // Calculate the width, spacing and offsets for the bar plot - they are grouped
  size_t n = this->ChartPrivate->plots.size();
  std::vector<vtkPlotBar *> bars;
  for (size_t i = 0; i < n; ++i)
    {
    vtkPlotBar* bar = vtkPlotBar::SafeDownCast(this->ChartPrivate->plots[i]);
    if (bar && bar->GetVisible())
      {
      bars.push_back(bar);
      }
    }
  if (bars.size())
    {
    // We have some bar plots - work out offsets etc.
    float barWidth = 0.1;
    vtkPlotBar* bar = bars[0];
    if (!bar->GetUseIndexForXSeries())
      {
      vtkTable *table = bar->GetData()->GetInput();
      if (table)
        {
        vtkDataArray* x = bar->GetData()->GetInputArrayToProcess(0, table);
        if (x && x->GetNumberOfTuples() > 1)
          {
          double x0 = x->GetTuple1(0);
          double x1 = x->GetTuple1(1);
          float width = static_cast<float>(fabs(x1 - x0) * this->BarWidthFraction);
          barWidth = width / bars.size();
          }
        }
      }
    else
      {
      barWidth = 1.0f / bars.size() * this->BarWidthFraction;
      }

    // Now set the offsets and widths on each bar
    // The offsetIndex deals with the fact that half the bars
    // must shift to the left of the point and half to the right
    int offsetIndex = static_cast<int>(bars.size() - 1);
    for (size_t i = 0; i < bars.size(); ++i)
      {
      bars[i]->SetWidth(barWidth);
      bars[i]->SetOffset(offsetIndex * (barWidth / 2));
      // Increment by two since we need to shift by half widths
      // but make room for entire bars. Increment backwards because
      // offsets are always subtracted and Positive offsets move
      // the bar leftwards.  Negative offsets will shift the bar
      // to the right.
      offsetIndex -= 2;
      //bars[i]->SetOffset(float(bars.size()-i-1)*(barWidth/2));
      }
    }
}

//-----------------------------------------------------------------------------
void vtkChartXY::RecalculatePlotTransforms()
{
  for (int i = 0; i < int(this->ChartPrivate->PlotCorners.size()); ++i)
    {
    if (this->ChartPrivate->PlotCorners[i]->GetNumberOfItems())
      {
      vtkAxis *xAxis = 0;
      vtkAxis *yAxis = 0;
      // Get the appropriate axes, and recalculate the transform.
      switch (i)
        {
        case 0:
          {
          xAxis = this->ChartPrivate->axes[vtkAxis::BOTTOM];
          yAxis = this->ChartPrivate->axes[vtkAxis::LEFT];
          break;
          }
        case 1:
          xAxis = this->ChartPrivate->axes[vtkAxis::BOTTOM];
          yAxis = this->ChartPrivate->axes[vtkAxis::RIGHT];
          break;
        case 2:
          xAxis = this->ChartPrivate->axes[vtkAxis::TOP];
          yAxis = this->ChartPrivate->axes[vtkAxis::RIGHT];
          break;
        case 3:
          xAxis = this->ChartPrivate->axes[vtkAxis::TOP];
          yAxis = this->ChartPrivate->axes[vtkAxis::LEFT];
          break;
        default:
          vtkWarningMacro("Error: default case in recalculate plot transforms.");
        }
      this->CalculatePlotTransform(xAxis, yAxis,
                                   this->ChartPrivate
                                   ->PlotCorners[i]->GetTransform());
      }
    }
  this->PlotTransformValid = true;
}

//-----------------------------------------------------------------------------
int vtkChartXY::GetPlotCorner(vtkPlot *plot)
{
  vtkAxis *x = plot->GetXAxis();
  vtkAxis *y = plot->GetYAxis();
  if (x == this->ChartPrivate->axes[vtkAxis::BOTTOM] &&
      y == this->ChartPrivate->axes[vtkAxis::LEFT])
    {
    return 0;
    }
  else if (x == this->ChartPrivate->axes[vtkAxis::BOTTOM] &&
           y == this->ChartPrivate->axes[vtkAxis::RIGHT])
    {
    return 1;
    }
  else if (x == this->ChartPrivate->axes[vtkAxis::TOP] &&
           y == this->ChartPrivate->axes[vtkAxis::RIGHT])
    {
    return 2;
    }
  else if (x == this->ChartPrivate->axes[vtkAxis::TOP] &&
           y == this->ChartPrivate->axes[vtkAxis::LEFT])
    {
    return 3;
    }
  else
    {
    // Should never happen.
    return 4;
    }
}

//-----------------------------------------------------------------------------
void vtkChartXY::SetPlotCorner(vtkPlot *plot, int corner)
{
  if (corner < 0 || corner > 3)
    {
    vtkWarningMacro("Invalid corner specified, should be between 0 and 3: "
                    << corner);
    return;
    }
  this->RemovePlotFromCorners(plot);
  // Grow the plot corners if necessary
  if (int(this->ChartPrivate->PlotCorners.size()) <= corner)
    {
    while (int(this->ChartPrivate->PlotCorners.size()) <= corner)
      {
      vtkSmartPointer<vtkContextTransform> transform =
        vtkSmartPointer<vtkContextTransform>::New();
      this->ChartPrivate->PlotCorners.push_back(transform);
      this->ChartPrivate->Clip->AddItem(transform); // Clip maintains ownership.
      }
    }
  this->ChartPrivate->PlotCorners[corner]->AddItem(plot);
  if (corner == 0)
    {
    plot->SetXAxis(this->ChartPrivate->axes[vtkAxis::BOTTOM]);
    plot->SetYAxis(this->ChartPrivate->axes[vtkAxis::LEFT]);
    }
  else if (corner == 1)
    {
    plot->SetXAxis(this->ChartPrivate->axes[vtkAxis::BOTTOM]);
    plot->SetYAxis(this->ChartPrivate->axes[vtkAxis::RIGHT]);
    }
  else if (corner == 2)
    {
    plot->SetXAxis(this->ChartPrivate->axes[vtkAxis::TOP]);
    plot->SetYAxis(this->ChartPrivate->axes[vtkAxis::RIGHT]);
    }
  else if (corner == 3)
    {
    plot->SetXAxis(this->ChartPrivate->axes[vtkAxis::TOP]);
    plot->SetYAxis(this->ChartPrivate->axes[vtkAxis::LEFT]);
    }
  this->PlotTransformValid = false;
}

//-----------------------------------------------------------------------------
void vtkChartXY::RecalculatePlotBounds()
{
  // Get the bounds of each plot, and each axis  - ordering as laid out below
  double y1[] = { 0.0, 0.0 }; // left -> 0
  double x1[] = { 0.0, 0.0 }; // bottom -> 1
  double y2[] = { 0.0, 0.0 }; // right -> 2
  double x2[] = { 0.0, 0.0 }; // top -> 3
  // Store whether the ranges have been initialized - follows same order
  bool initialized[] = { false, false, false, false };

  std::vector<vtkPlot*>::iterator it;
  double bounds[4] = { 0.0, 0.0, 0.0, 0.0 };
  for (it = this->ChartPrivate->plots.begin();
       it != this->ChartPrivate->plots.end(); ++it)
    {
    if ((*it)->GetVisible() == false)
      {
      continue;
      }
    (*it)->GetBounds(bounds);
    if (bounds[1]-bounds[0] < 0.0)
      {
      // skip uninitialized bounds.
      continue;
      }
    int corner = this->GetPlotCorner(*it);

    // Initialize the appropriate ranges, or push out the ranges
    if ((corner == 0 || corner == 3)) // left
      {
      if (!initialized[0])
        {
        y1[0] = bounds[2];
        y1[1] = bounds[3];
        initialized[0] = true;
        }
      else
        {
        if (y1[0] > bounds[2]) // min
          {
          y1[0] = bounds[2];
          }
        if (y1[1] < bounds[3]) // max
          {
          y1[1] = bounds[3];
          }
        }
      }
    if ((corner == 0 || corner == 1)) // bottom
      {
      if (!initialized[1])
        {
        x1[0] = bounds[0];
        x1[1] = bounds[1];
        initialized[1] = true;
        }
      else
        {
        if (x1[0] > bounds[0]) // min
          {
          x1[0] = bounds[0];
          }
        if (x1[1] < bounds[1]) // max
          {
          x1[1] = bounds[1];
          }
        }
      }
    if ((corner == 1 || corner == 2)) // right
      {
      if (!initialized[2])
        {
        y2[0] = bounds[2];
        y2[1] = bounds[3];
        initialized[2] = true;
        }
      else
        {
        if (y2[0] > bounds[2]) // min
          {
          y2[0] = bounds[2];
          }
        if (y2[1] < bounds[3]) // max
          {
          y2[1] = bounds[3];
          }
        }
      }
    if ((corner == 2 || corner == 3)) // top
      {
      if (!initialized[3])
        {
        x2[0] = bounds[0];
        x2[1] = bounds[1];
        initialized[3] = true;
        }
      else
        {
        if (x2[0] > bounds[0]) // min
          {
          x2[0] = bounds[0];
          }
        if (x2[1] < bounds[1]) // max
          {
          x2[1] = bounds[1];
          }
        }
      }
    }

  // Now set the newly calculated bounds on the axes
  for (int i = 0; i < 4; ++i)
    {
    vtkAxis *axis = this->ChartPrivate->axes[i];
    double *range = 0;
    switch (i)
      {
      case 0:
        range = y1;
        break;
      case 1:
        range = x1;
        break;
      case 2:
        range = y2;
        break;
      case 3:
        range = x2;
        break;
      default:
        return;
      }

    if (this->ForceAxesToBounds)
      {
      axis->SetMinimumLimit(range[0]);
      axis->SetMaximumLimit(range[1]);
      }
    if (axis->GetBehavior() == vtkAxis::AUTO && initialized[i])
      {
      axis->SetRange(range[0], range[1]);
      axis->AutoScale();
      }
    }

  this->Modified();
}

//-----------------------------------------------------------------------------
bool vtkChartXY::UpdateLayout(vtkContext2D* painter)
{
  // The main use of this method is currently to query the visible axes for
  // their bounds, and to update the chart in response to that.
  bool changed = false;

  // Axes
  if (this->LayoutStrategy == vtkChart::FILL_SCENE ||
      this->LayoutStrategy == vtkChart::FILL_RECT)
    {
    for (int i = 0; i < 4; ++i)
      {
      int border = 0;
      vtkAxis* axis = this->ChartPrivate->axes[i];
      axis->Update();
      if (axis->GetVisible())
        {
        vtkRectf bounds = axis->GetBoundingRect(painter);
        if (i == 1 || i == 3)
          {// Horizontal axes
          border = int(bounds.GetHeight());
          }
        else
          {// Vertical axes
          border = int(bounds.GetWidth());
          }
        }
      border += this->GetLegendBorder(painter, i);
      border = border < this->HiddenAxisBorder ? this->HiddenAxisBorder :
                                                 border;
      if (this->ChartPrivate->Borders[i] != border)
        {
        this->ChartPrivate->Borders[i] = border;
        changed = true;
        }
      }
    }

  if (this->LayoutChanged || changed)
    {
    if (this->DrawAxesAtOrigin)
      {
      this->SetBorders(this->HiddenAxisBorder,
                       this->HiddenAxisBorder,
                       this->ChartPrivate->Borders[2],
                       this->ChartPrivate->Borders[3]);
      // Get the screen coordinates for the origin, and move the axes there.
      vtkVector2f origin(0.0);
      vtkTransform2D* transform =
          this->ChartPrivate->PlotCorners[0]->GetTransform();
      transform->TransformPoints(origin.GetData(), origin.GetData(), 1);
      // Need to clamp the axes in the plot area.
      if (int(origin[0]) < this->Point1[0])
        {
        origin[0] = this->Point1[0];
        }
      if (int(origin[0]) > this->Point2[0])
        {
        origin[0] = this->Point2[0];
        }
      if (int(origin[1]) < this->Point1[1])
        {
        origin[1] = this->Point1[1];
        }
      if (int(origin[1]) > this->Point2[1])
        {
        origin[1] = this->Point2[1];
        }

      this->ChartPrivate->axes[vtkAxis::BOTTOM]
          ->SetPoint1(this->Point1[0], origin[1]);
      this->ChartPrivate->axes[vtkAxis::BOTTOM]
          ->SetPoint2(this->Point2[0], origin[1]);
      this->ChartPrivate->axes[vtkAxis::LEFT]
          ->SetPoint1(origin[0], this->Point1[1]);
      this->ChartPrivate->axes[vtkAxis::LEFT]
          ->SetPoint2(origin[0], this->Point2[1]);
      }
    else
      {
      if (this->LayoutStrategy == vtkChart::AXES_TO_RECT)
        {
        this->SetBorders(0, 0, 0, 0);
        this->ChartPrivate->axes[0]->GetBoundingRect(painter);
        this->ChartPrivate->axes[1]->GetBoundingRect(painter);
        this->ChartPrivate->axes[2]->GetBoundingRect(painter);
        this->ChartPrivate->axes[3]->GetBoundingRect(painter);
        }
      else
        {
        this->SetBorders(this->ChartPrivate->Borders[0],
                         this->ChartPrivate->Borders[1],
                         this->ChartPrivate->Borders[2],
                         this->ChartPrivate->Borders[3]);
        }
      // This is where we set the axes up too
      // Y axis (left)
      this->ChartPrivate->axes[0]->SetPoint1(this->Point1[0], this->Point1[1]);
      this->ChartPrivate->axes[0]->SetPoint2(this->Point1[0], this->Point2[1]);
      // X axis (bottom)
      this->ChartPrivate->axes[1]->SetPoint1(this->Point1[0], this->Point1[1]);
      this->ChartPrivate->axes[1]->SetPoint2(this->Point2[0], this->Point1[1]);
      }
    // Y axis (right)
    this->ChartPrivate->axes[2]->SetPoint1(this->Point2[0], this->Point1[1]);
    this->ChartPrivate->axes[2]->SetPoint2(this->Point2[0], this->Point2[1]);
    // X axis (top)
    this->ChartPrivate->axes[3]->SetPoint1(this->Point1[0], this->Point2[1]);
    this->ChartPrivate->axes[3]->SetPoint2(this->Point2[0], this->Point2[1]);

    for (int i = 0; i < 4; ++i)
      {
      this->ChartPrivate->axes[i]->Update();
      }
    }
  this->SetLegendPosition(this->Legend->GetBoundingRect(painter));

  return changed;
}

//-----------------------------------------------------------------------------
int vtkChartXY::GetLegendBorder(vtkContext2D* painter, int axisPosition)
{
  if (!this->Legend->GetVisible() || this->Legend->GetInline())
    {
    return 0;
    }

  int padding = 10;
  vtkVector2i legendSize(0, 0);
  vtkVector2i legendAlignment(this->Legend->GetHorizontalAlignment(),
                              this->Legend->GetVerticalAlignment());
  this->Legend->Update();
  vtkRectf rect = this->Legend->GetBoundingRect(painter);
  legendSize.Set(static_cast<int>(rect.Width()),
                 static_cast<int>(rect.Height()));

  // Figure out the correct place and alignment based on the legend layout.
  if (axisPosition == vtkAxis::LEFT &&
      legendAlignment.X() == vtkChartLegend::LEFT)
    {
    return legendSize.X() + padding;
    }
  else if (axisPosition == vtkAxis::RIGHT &&
           legendAlignment.X() == vtkChartLegend::RIGHT)
    {
    return legendSize.X() + padding;
    }
  else if ((axisPosition == vtkAxis::TOP || axisPosition == vtkAxis::BOTTOM) &&
           (legendAlignment.X() == vtkChartLegend::LEFT ||
            legendAlignment.X() == vtkChartLegend::RIGHT))
    {
    return 0;
    }
  else if (axisPosition == vtkAxis::TOP &&
           legendAlignment.Y() == vtkChartLegend::TOP)
    {
    return legendSize.Y() + padding;
    }
  else if (axisPosition == vtkAxis::BOTTOM &&
           legendAlignment.Y() == vtkChartLegend::BOTTOM)
    {
    return legendSize.Y() + padding;
    }
  else
    {
    return 0;
    }
}

//-----------------------------------------------------------------------------
void vtkChartXY::SetLegendPosition(const vtkRectf& rect)
{
  // Put the legend in the top corner of the chart
  vtkVector2f pos(0, 0);
  int padding = 5;
  vtkVector2i legendAlignment(this->Legend->GetHorizontalAlignment(),
                              this->Legend->GetVerticalAlignment());

  if (legendAlignment[0] == vtkChartLegend::CUSTOM ||
      legendAlignment[1] == vtkChartLegend::CUSTOM)
    {
    return;
    }

  if (this->Legend->GetInline())
    {
    switch (this->Legend->GetHorizontalAlignment())
      {
      case vtkChartLegend::LEFT:
        pos.SetX(this->Point1[0]);
        break;
      case vtkChartLegend::CENTER:
        pos.SetX(((this->Point2[0] - this->Point1[0]) / 2.0)
                 - rect.Width() / 2.0 + this->Point1[0]);
        break;
      case vtkChartLegend::RIGHT:
      default:
        pos.SetX(this->Point2[0] - rect.Width());
      }
    switch (this->Legend->GetVerticalAlignment())
      {
      case vtkChartLegend::TOP:
        pos.SetY(this->Point2[1] - rect.Height());
        break;
      case vtkChartLegend::CENTER:
        pos.SetY((this->Point2[1] - this->Point1[1]) / 2.0
                 - rect.Height() / 2.0 + this->Point1[1]);
        break;
      case vtkChartLegend::BOTTOM:
      default:
        pos.SetY(this->Point1[1]);
      }
    }
  else
    {
    // Non-inline legends.
    if (legendAlignment.X() == vtkChartLegend::LEFT)
      {
      pos.SetX(this->Point1[0] - this->ChartPrivate->Borders[vtkAxis::LEFT]
               + padding);
      }
    else if (legendAlignment.X() == vtkChartLegend::RIGHT)
      {
      pos.SetX(this->Point2[0] + this->ChartPrivate->Borders[vtkAxis::RIGHT]
               - rect.Width() - padding);
      }
    else if (legendAlignment.X() == vtkChartLegend::CENTER)
      {
      pos.SetX(((this->Point2[0] - this->Point1[0]) / 2.0)
               - (rect.Width() / 2.0) + this->Point1[0]);
      // Check for the special case where the legend is on the top or bottom
      if (legendAlignment.Y() == vtkChartLegend::TOP)
        {
        pos.SetY(this->Point2[1] + this->ChartPrivate->Borders[vtkAxis::TOP]
                 - rect.Height() - padding);
        }
      else if (legendAlignment.Y() == vtkChartLegend::BOTTOM)
        {
        pos.SetY(this->Point1[1] - this->ChartPrivate->Borders[vtkAxis::BOTTOM]
                 + padding);
        }
      }
    // Vertical alignment
    if (legendAlignment.X() != vtkChartLegend::CENTER)
      {
      if (legendAlignment.Y() == vtkChartLegend::TOP)
        {
        pos.SetY(this->Point2[1] - rect.Height());
        }
      else if (legendAlignment.Y() == vtkChartLegend::BOTTOM)
        {
        pos.SetY(this->Point1[1]);
        }
      }
    if (legendAlignment.Y() == vtkChartLegend::CENTER)
      {
      pos.SetY(((this->Point2[1] - this->Point1[1]) / 2.0)
               - (rect.Height() / 2.0) + this->Point1[1]);
      }
    }

  this->Legend->SetPoint(pos);
}

//-----------------------------------------------------------------------------
vtkPlot * vtkChartXY::AddPlot(int type)
{
  // Use a variable to return the object created (or NULL), this is necessary
  // as the HP compiler is broken (thinks this function does not return) and
  // the MS compiler generates a warning about unreachable code if a redundant
  // return is added at the end.
  vtkPlot *plot = NULL;
  vtkColor3ub color = this->ChartPrivate->Colors->GetColorRepeating(
      static_cast<int>(this->ChartPrivate->plots.size()));
  switch (type)
    {
    case LINE:
      {
      vtkPlotLine *line = vtkPlotLine::New();
      line->GetPen()->SetColor(color.GetData());
      plot = line;
      break;
      }
    case POINTS:
      {
      vtkPlotPoints *points = vtkPlotPoints::New();
      points->GetPen()->SetColor(color.GetData());
      plot = points;
      break;
      }
    case BAR:
      {
      vtkPlotBar *bar = vtkPlotBar::New();
      bar->GetBrush()->SetColor(color.GetData());
      plot = bar;
      break;
      }
    case STACKED:
      {
      vtkPlotStacked *stacked = vtkPlotStacked::New();
      stacked->SetParent(this);
      stacked->GetBrush()->SetColor(color.GetData());
      plot = stacked;
      break;
      }
    default:
      plot = NULL;
    }
  if (plot)
    {
    this->AddPlot(plot);
    plot->Delete();
    }
  return plot;
}

//-----------------------------------------------------------------------------
vtkIdType vtkChartXY::AddPlot(vtkPlot * plot)
{
  if (plot == NULL)
    {
    return -1;
    }
  plot->Register(this);
  this->ChartPrivate->plots.push_back(plot);
  vtkIdType plotIndex = this->ChartPrivate->plots.size() - 1;
  this->SetPlotCorner(plot, 0);
  // Ensure that the bounds are recalculated
  this->PlotTransformValid = false;
  // Mark the scene as dirty
  if (this->Scene)
    {
    this->Scene->SetDirty(true);
    }
  return plotIndex;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::RemovePlot(vtkIdType index)
{
  if (index < static_cast<vtkIdType>(this->ChartPrivate->plots.size()))
    {
    this->RemovePlotFromCorners(this->ChartPrivate->plots[index]);
    this->ChartPrivate->plots[index]->Delete();
    this->ChartPrivate->plots.erase(this->ChartPrivate->plots.begin()+index);

    // Ensure that the bounds are recalculated
    this->PlotTransformValid = false;
    // Mark the scene as dirty
    this->Scene->SetDirty(true);
    return true;
    }
  else
    {
    return false;
    }
}

//-----------------------------------------------------------------------------
void vtkChartXY::ClearPlots()
{
  for (unsigned int i = 0; i < this->ChartPrivate->plots.size(); ++i)
    {
    this->ChartPrivate->plots[i]->Delete();
    }
  this->ChartPrivate->plots.clear();
  // Clear the corners too
  for (int i = 0; i < int(this->ChartPrivate->PlotCorners.size()); ++i)
    {
    this->ChartPrivate->PlotCorners[i]->ClearItems();
    }

  // Ensure that the bounds are recalculated
  this->PlotTransformValid = false;
  // Mark the scene as dirty
  this->Scene->SetDirty(true);
}

//-----------------------------------------------------------------------------
vtkPlot* vtkChartXY::GetPlot(vtkIdType index)
{
  if (static_cast<vtkIdType>(this->ChartPrivate->plots.size()) > index)
    {
    return this->ChartPrivate->plots[index];
    }
  else
    {
    return NULL;
    }
}

//-----------------------------------------------------------------------------
void vtkChartXY::SetShowLegend(bool visible)
{
  this->vtkChart::SetShowLegend(visible);
  this->Legend->SetVisible(visible);
}

//-----------------------------------------------------------------------------
vtkChartLegend* vtkChartXY::GetLegend()
{
  return this->Legend;
}

//-----------------------------------------------------------------------------
vtkTooltipItem* vtkChartXY::GetTooltip()
{
  return this->Tooltip;
}

//-----------------------------------------------------------------------------
vtkIdType vtkChartXY::GetNumberOfPlots()
{
  return this->ChartPrivate->plots.size();
}

//-----------------------------------------------------------------------------
vtkAxis* vtkChartXY::GetAxis(int axisIndex)
{
  if (axisIndex < 4)
    {
    return this->ChartPrivate->axes[axisIndex];
    }
  else
    {
    return NULL;
    }
}

//-----------------------------------------------------------------------------
vtkIdType vtkChartXY::GetNumberOfAxes()
{
  return 4;
}


//-----------------------------------------------------------------------------
void vtkChartXY::RecalculateBounds()
{
  // Ensure that the bounds are recalculated
  this->PlotTransformValid = false;
  // Mark the scene as dirty
  this->Scene->SetDirty(true);
}

//-----------------------------------------------------------------------------
bool vtkChartXY::Hit(const vtkContextMouseEvent &mouse)
{
  vtkVector2i pos(mouse.GetScreenPos());
  if (pos[0] > this->Point1[0] &&
      pos[0] < this->Point2[0] &&
      pos[1] > this->Point1[1] &&
      pos[1] < this->Point2[1])
    {
    return true;
    }
  else
    {
    return false;
    }
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseEnterEvent(const vtkContextMouseEvent &)
{
  // Find the nearest point on the curves and snap to it
  this->DrawNearestPoint = true;
  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
  // Iterate through each corner, and check for a nearby point
  for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
    {
    if (this->ChartPrivate->PlotCorners[i]->MouseMoveEvent(mouse))
      {
      return true;
      }
    }

  if (mouse.GetButton() == this->Actions.Pan())
    {
    // Figure out how much the mouse has moved by in plot coordinates - pan
    vtkVector2d screenPos(mouse.GetScreenPos().Cast<double>().GetData());
    vtkVector2d lastScreenPos(mouse.GetLastScreenPos().Cast<double>().GetData());
    vtkVector2d pos(0.0, 0.0);
    vtkVector2d last(0.0, 0.0);

    // Go from screen to scene coordinates to work out the delta
    vtkTransform2D *transform =
        this->ChartPrivate->PlotCorners[0]->GetTransform();
    transform->InverseTransformPoints(screenPos.GetData(), pos.GetData(), 1);
    transform->InverseTransformPoints(lastScreenPos.GetData(), last.GetData(), 1);
    vtkVector2d delta = last - pos;

    // Now move the axes and recalculate the transform
    vtkAxis* xAxis = this->ChartPrivate->axes[vtkAxis::BOTTOM];
    vtkAxis* yAxis = this->ChartPrivate->axes[vtkAxis::LEFT];
    delta[0] = delta[0] > 0 ?
      std::min(delta[0], xAxis->GetMaximumLimit() - xAxis->GetMaximum()) :
      std::max(delta[0], xAxis->GetMinimumLimit() - xAxis->GetMinimum());
    delta[1] = delta[1] > 0 ?
      std::min(delta[1], yAxis->GetMaximumLimit() - yAxis->GetMaximum()) :
      std::max(delta[1], yAxis->GetMinimumLimit() - yAxis->GetMinimum());
    xAxis->SetMinimum(xAxis->GetMinimum() + delta[0]);
    xAxis->SetMaximum(xAxis->GetMaximum() + delta[0]);
    yAxis->SetMinimum(yAxis->GetMinimum() + delta[1]);
    yAxis->SetMaximum(yAxis->GetMaximum() + delta[1]);

    // Same again for the axes in the top right
    if (this->ChartPrivate->PlotCorners.size() > 2)
      {
      // Go from screen to scene coordinates to work out the delta
      screenPos = vtkVector2d(mouse.GetScreenPos().Cast<double>().GetData());
      lastScreenPos =
          vtkVector2d(mouse.GetLastScreenPos().Cast<double>().GetData());
      pos = vtkVector2d(0.0, 0.0);
      last = vtkVector2d(0.0, 0.0);
      transform = this->ChartPrivate->PlotCorners[2]->GetTransform();
      transform->InverseTransformPoints(screenPos.GetData(), pos.GetData(), 1);
      transform->InverseTransformPoints(lastScreenPos.GetData(), last.GetData(), 1);
      delta = last - pos;

      // Now move the axes and recalculate the transform
      xAxis = this->ChartPrivate->axes[vtkAxis::TOP];
      yAxis = this->ChartPrivate->axes[vtkAxis::RIGHT];
      delta[0] = delta[0] > 0 ?
        std::min(delta[0], xAxis->GetMaximumLimit() - xAxis->GetMaximum()) :
        std::max(delta[0], xAxis->GetMinimumLimit() - xAxis->GetMinimum());
      delta[1] = delta[1] > 0 ?
        std::min(delta[1], yAxis->GetMaximumLimit() - yAxis->GetMaximum()) :
        std::max(delta[1], yAxis->GetMinimumLimit() - yAxis->GetMinimum());
      xAxis->SetMinimum(xAxis->GetMinimum() + delta[0]);
      xAxis->SetMaximum(xAxis->GetMaximum() + delta[0]);
      yAxis->SetMinimum(yAxis->GetMinimum() + delta[1]);
      yAxis->SetMaximum(yAxis->GetMaximum() + delta[1]);
      }

    this->RecalculatePlotTransforms();
    // Mark the scene as dirty
    this->Scene->SetDirty(true);
    }
  else if (mouse.GetButton() == this->Actions.Zoom() ||
           mouse.GetButton() == this->Actions.Select())
    {
    this->MouseBox.SetWidth(mouse.GetPos().X() - this->MouseBox.X());
    this->MouseBox.SetHeight(mouse.GetPos().Y() - this->MouseBox.Y());
    // Mark the scene as dirty
    this->Scene->SetDirty(true);
    }
  else if (mouse.GetButton() == vtkContextMouseEvent::NO_BUTTON)
    {
    this->Scene->SetDirty(true);
    this->Tooltip->SetVisible(this->LocatePointInPlots(mouse));
    }

  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::LocatePointInPlots(const vtkContextMouseEvent &mouse,
                                    int invokeEvent)
{
  size_t n = this->ChartPrivate->plots.size();
  vtkVector2i pos(mouse.GetScreenPos());
  if (pos[0] > this->Point1[0] &&
      pos[0] < this->Point2[0] &&
      pos[1] > this->Point1[1] &&
      pos[1] < this->Point2[1] && n)
    {
    // Iterate through each corner, and check for a nearby point
    for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
      {
      int items = static_cast<int>(this->ChartPrivate->PlotCorners[i]
                                   ->GetNumberOfItems());
      if (items)
        {
        vtkVector2f plotPos, position;
        vtkTransform2D* transform =
            this->ChartPrivate->PlotCorners[i]->GetTransform();
        transform->InverseTransformPoints(mouse.GetPos().GetData(),
                                          position.GetData(), 1);
        // Use a tolerance of +/- 5 pixels
        vtkVector2f tolerance(5*(1.0/transform->GetMatrix()->GetElement(0, 0)),
                              5*(1.0/transform->GetMatrix()->GetElement(1, 1)));
        // Iterate through the visible plots and return on the first hit
        for (int j = items-1; j >= 0; --j)
          {
          vtkPlot* plot = vtkPlot::SafeDownCast(this->ChartPrivate->
                                                PlotCorners[i]->GetItem(j));
          if (plot && plot->GetVisible())
            {
            int seriesIndex;
            vtkIdType segmentIndex = -1;
            vtkPlotBar* plotBar = vtkPlotBar::SafeDownCast(plot);
            if (plotBar)
              {
              // If the plot is a vtkPlotBar, get the segment index too
              seriesIndex = plotBar->GetNearestPoint(position, tolerance,
                                                     &plotPos, &segmentIndex);
              }
            else
              {
              seriesIndex = plot->GetNearestPoint(position, tolerance,
                                                  &plotPos);
              }
            if (seriesIndex >= 0)
              {
              // We found a point, set up the tooltip and return
              this->SetTooltipInfo(mouse, plotPos, seriesIndex, plot,
                                   segmentIndex);
              if (invokeEvent >= 0)
                {
                vtkChartPlotData plotIndex;
                plotIndex.SeriesName = plot->GetLabel();
                plotIndex.Position = plotPos;
                plotIndex.ScreenPosition = mouse.GetScreenPos();
                plotIndex.Index = seriesIndex;
                // Invoke an event, with the client data supplied
                this->InvokeEvent(invokeEvent, static_cast<void*>(&plotIndex));

                if (invokeEvent == vtkCommand::SelectionChangedEvent)
                  {
                  vtkNew<vtkIdTypeArray> selectionIds;
                  selectionIds->InsertNextValue(seriesIndex);
                  plot->SetSelection(selectionIds.GetPointer());

                  if (this->AnnotationLink)
                    {
                    vtkNew<vtkSelection> selection;
                    vtkNew<vtkSelectionNode> node;
                    selection->AddNode(node.GetPointer());
                    node->SetContentType(vtkSelectionNode::INDICES);
                    node->SetFieldType(vtkSelectionNode::POINT);
                    node->SetSelectionList(selectionIds.GetPointer());
                    this->AnnotationLink
                        ->SetCurrentSelection(selection.GetPointer());
                    }
                  }
                }
              return true;
              }
            }
          }
        }
      }
    }
  return false;
}

void vtkChartXY::SetTooltipInfo(const vtkContextMouseEvent& mouse,
                                const vtkVector2f &plotPos,
                                vtkIdType seriesIndex, vtkPlot* plot,
                                vtkIdType segmentIndex)
{
  // Have the plot generate its tooltip label
  vtkStdString tooltipLabel = plot->GetTooltipLabel(plotPos, seriesIndex,
                                                    segmentIndex);

  // Set the tooltip
  this->Tooltip->SetText(tooltipLabel);
  this->Tooltip->SetPosition(mouse.GetScreenPos()[0] + 2,
                             mouse.GetScreenPos()[1] + 2);
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseLeaveEvent(const vtkContextMouseEvent &)
{
  this->DrawNearestPoint = false;
  this->Tooltip->SetVisible(false);
  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
  this->Tooltip->SetVisible(false);
  // Iterate through each corner, and check for a nearby point
  for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
    {
    if (this->ChartPrivate->PlotCorners[i]->MouseButtonPressEvent(mouse))
      {
      return true;
      }
    }
  if (mouse.GetButton() == this->Actions.Pan())
    {
    // The mouse panning action.
    this->MouseBox.Set(mouse.GetPos().X(), mouse.GetPos().Y(), 0.0, 0.0);
    this->DrawBox = false;
    return true;
    }
  else if (mouse.GetButton() == this->Actions.Zoom() ||
           mouse.GetButton() == this->Actions.Select())
    {
    // Selection, for now at least...
    this->MouseBox.Set(mouse.GetPos().X(), mouse.GetPos().Y(), 0.0, 0.0);
    this->DrawBox = true;
    return true;
    }
  else if (mouse.GetButton() == this->ActionsClick.Select() ||
           mouse.GetButton() == this->ActionsClick.Notify())
    {
    return true;
    }
  else
    {
    return false;
    }
}

//-----------------------------------------------------------------------------
namespace {
void MinusSelection(vtkIdTypeArray *selection, vtkIdTypeArray *oldSelection)
{
  // We rely on the selection id arrays being sorted.
  std::vector<vtkIdType> output;
  vtkIdType *ptrSelection =
      static_cast<vtkIdType *>(selection->GetVoidPointer(0));
  vtkIdType *ptrOldSelection =
      static_cast<vtkIdType *>(oldSelection->GetVoidPointer(0));
  vtkIdType oldSize = oldSelection->GetNumberOfTuples();
  vtkIdType size = selection->GetNumberOfTuples();
  vtkIdType i = 0;
  vtkIdType iOld = 0;

  while (i < size && iOld < oldSize)
    {
    if (ptrSelection[i] > ptrOldSelection[iOld]) // Skip the value.
      {
      output.push_back(ptrOldSelection[iOld++]);
      }
    else if (ptrSelection[i] == ptrOldSelection[iOld]) // Match - remove.
      {
      ++i;
      ++iOld;
      }
    else if (ptrSelection[i] < ptrOldSelection[iOld]) // Add the new value.
      {
      ++i;
      }
    }
  while (iOld < oldSize)
    {
    output.push_back(ptrOldSelection[iOld++]);
    }
  selection->SetNumberOfTuples(output.size());
  ptrSelection = static_cast<vtkIdType *>(selection->GetVoidPointer(0));
  for (std::vector<vtkIdType>::iterator it = output.begin();
       it != output.end(); ++it, ++ptrSelection)
    {
    *ptrSelection = *it;
    }
  }
}

void BuildSelection(vtkIdTypeArray *selection, vtkIdTypeArray *oldSelection,
                    bool add, bool toggle)
{
  // Add all unique array indices to create a new combined array.
  if (add)
    {
    vtkIdType *ptrSelection =
        static_cast<vtkIdType *>(selection->GetVoidPointer(0));
    vtkIdType *ptrOldSelection =
        static_cast<vtkIdType *>(oldSelection->GetVoidPointer(0));
    std::vector<vtkIdType> output(selection->GetNumberOfTuples()
                                  + oldSelection->GetNumberOfTuples());
    std::vector<vtkIdType>::iterator it;
    it = std::set_union(ptrSelection,
                        ptrSelection + selection->GetNumberOfTuples(),
                        ptrOldSelection,
                        ptrOldSelection + oldSelection->GetNumberOfTuples(),
                        output.begin());
    int newSize = int(it - output.begin());
    selection->SetNumberOfTuples(newSize);
    ptrSelection = static_cast<vtkIdType *>(selection->GetVoidPointer(0));
    for (std::vector<vtkIdType>::iterator i = output.begin(); i != it;
         ++i, ++ptrSelection)
      {
      *ptrSelection = *i;
      }
    }
  else if (toggle)
    {
    // We rely on the selection id arrays being sorted.
    std::vector<vtkIdType> output;
    vtkIdType *ptrSelection =
        static_cast<vtkIdType *>(selection->GetVoidPointer(0));
    vtkIdType *ptrOldSelection =
        static_cast<vtkIdType *>(oldSelection->GetVoidPointer(0));
    vtkIdType oldSize = oldSelection->GetNumberOfTuples();
    vtkIdType size = selection->GetNumberOfTuples();
    vtkIdType i = 0;
    vtkIdType iOld = 0;
    while (i < size && iOld < oldSize)
      {
      if (ptrSelection[i] > ptrOldSelection[iOld]) // Retain the value.
        {
        output.push_back(ptrOldSelection[iOld++]);
        }
      else if (ptrSelection[i] == ptrOldSelection[iOld]) // Match - toggle.
        {
        ++i;
        ++iOld;
        }
      else if (ptrSelection[i] < ptrOldSelection[iOld]) // Add the new value.
        {
        output.push_back(ptrSelection[i++]);
        }
      }
    while (i < size)
      {
      output.push_back(ptrSelection[i++]);
      }
    while (iOld < oldSize)
      {
      output.push_back(ptrOldSelection[iOld++]);
      }
    selection->SetNumberOfTuples(output.size());
    ptrSelection = static_cast<vtkIdType *>(selection->GetVoidPointer(0));
    for (std::vector<vtkIdType>::iterator it = output.begin();
         it != output.end(); ++it, ++ptrSelection)
      {
      *ptrSelection = *it;
      }
    }
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)
{
  // Iterate through each corner, and check for a nearby point
  for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
    {
    if (this->ChartPrivate->PlotCorners[i]->MouseButtonReleaseEvent(mouse))
      {
      return true;
      }
    }
  if (mouse.GetButton() > vtkContextMouseEvent::NO_BUTTON &&
      mouse.GetButton() <= vtkContextMouseEvent::RIGHT_BUTTON)
    {
    this->MouseBox.SetWidth(mouse.GetPos().X() - this->MouseBox.X());
    this->MouseBox.SetHeight(mouse.GetPos().Y() - this->MouseBox.Y());
    if ((fabs(this->MouseBox.Width()) < 0.5 && fabs(this->MouseBox.Height()) < 0.5)
        && (mouse.GetButton() == this->Actions.Select() ||
            mouse.GetButton() == this->Actions.Pan()))
      {
      // Invalid box size - treat as a single clicke event
      this->MouseBox.SetWidth(0.0);
      this->MouseBox.SetHeight(0.0);
      this->DrawBox = false;
      if (mouse.GetButton() == this->ActionsClick.Notify())
        {
        this->LocatePointInPlots(mouse, vtkCommand::InteractionEvent);
        return true;
        }
      else if (mouse.GetButton() == this->ActionsClick.Select())
        {
        this->LocatePointInPlots(mouse, vtkCommand::SelectionChangedEvent);
        return true;
        }
      else
        {
        return false;
        }
      }
    }
  if (mouse.GetButton() == this->Actions.Select())
    {
    // Add to the selection if the shift key was pressed.
    bool addToSelection =
          (mouse.GetModifiers() & vtkContextMouseEvent::SHIFT_MODIFIER) != 0;
    if (this->SelectionMode == vtkContextScene::SELECTION_ADDITION)
      {
      addToSelection = true;
      }
    bool toggleSelection =
          (mouse.GetModifiers() & vtkContextMouseEvent::CONTROL_MODIFIER) != 0;
    if (this->SelectionMode == vtkContextScene::SELECTION_TOGGLE)
      {
      toggleSelection = true;
      }
    if (fabs(this->MouseBox.Width()) < 0.5 || fabs(this->MouseBox.Height()) < 0.5)
      {
      // Invalid box size - do nothing
      this->MouseBox.SetWidth(0.0);
      this->MouseBox.SetHeight(0.0);
      this->DrawBox = false;
      return true;
      }
    // Iterate through the plots and build a selection
    vtkNew<vtkIdTypeArray> oldSelection;
    for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
      {
      int items = static_cast<int>(this->ChartPrivate->PlotCorners[i]
                                   ->GetNumberOfItems());
      if (items)
        {
        vtkTransform2D *transform =
            this->ChartPrivate->PlotCorners[i]->GetTransform();
        transform->InverseTransformPoints(this->MouseBox.GetData(),
                                          this->MouseBox.GetData(), 1);
        vtkVector2f point2(mouse.GetPos());
        transform->InverseTransformPoints(point2.GetData(), point2.GetData(), 1);

        vtkVector2f min(this->MouseBox.GetData());
        vtkVector2f max(point2);
        if (min.X() > max.X())
          {
          float tmp = min.X();
          min.SetX(max.X());
          max.SetX(tmp);
          }
        if (min.Y() > max.Y())
          {
          float tmp = min.Y();
          min.SetY(max.Y());
          max.SetY(tmp);
          }

        for (int j = 0; j < items; ++j)
          {
          vtkPlot* plot = vtkPlot::SafeDownCast(this->ChartPrivate->
                                                PlotCorners[i]->GetItem(j));
          if (plot && plot->GetVisible())
            {
            oldSelection->DeepCopy(plot->GetSelection());
            /*
             * Populate the internal selection.  This will be referenced later
             * to subsequently populate the selection inside the annotation link.
             */
            plot->SelectPoints(min, max);

            if (this->AnnotationLink)
              {
              // FIXME: Build up a selection from each plot?
              vtkSelection* selection = vtkSelection::New();
              vtkSelectionNode* node = vtkSelectionNode::New();
              selection->AddNode(node);
              node->SetContentType(vtkSelectionNode::INDICES);
              node->SetFieldType(vtkSelectionNode::POINT);
              if (addToSelection || toggleSelection)
                {
                BuildSelection(plot->GetSelection(), oldSelection.GetPointer(),
                               addToSelection, toggleSelection);
                }
              else if (this->SelectionMode == vtkContextScene::SELECTION_SUBTRACTION)
                {
                MinusSelection(plot->GetSelection(), oldSelection.GetPointer());
                }
              node->SetSelectionList(plot->GetSelection());
              this->AnnotationLink->SetCurrentSelection(selection);
              node->Delete();
              selection->Delete();
              }
            }
          }
        }
      }

    this->InvokeEvent(vtkCommand::SelectionChangedEvent);
    this->MouseBox.SetWidth(0.0);
    this->MouseBox.SetHeight(0.0);
    this->DrawBox = false;
    // Mark the scene as dirty
    this->Scene->SetDirty(true);
    return true;
    }
  else if (mouse.GetButton() == this->Actions.Zoom())
    {
    // Check whether a valid zoom box was drawn
    if (fabs(this->MouseBox.Width()) < 0.5 || fabs(this->MouseBox.Height()) < 0.5)
      {
      // Invalid box size - do nothing
      this->MouseBox.SetWidth(0.0);
      this->MouseBox.SetHeight(0.0);
      this->DrawBox = false;
      return true;
      }

    // Zoom into the chart by the specified amount, and recalculate the bounds
    vtkVector2f point2(mouse.GetPos());

    this->ZoomInAxes(this->ChartPrivate->axes[vtkAxis::BOTTOM],
                     this->ChartPrivate->axes[vtkAxis::LEFT],
                     this->MouseBox.GetData(), point2.GetData());
    this->ZoomInAxes(this->ChartPrivate->axes[vtkAxis::TOP],
                     this->ChartPrivate->axes[vtkAxis::RIGHT],
                     this->MouseBox.GetData(), point2.GetData());

    this->RecalculatePlotTransforms();
    this->MouseBox.SetWidth(0.0);
    this->MouseBox.SetHeight(0.0);
    this->DrawBox = false;
    // Mark the scene as dirty
    this->Scene->SetDirty(true);
    return true;
    }
  return false;
}

void vtkChartXY::ZoomInAxes(vtkAxis *x, vtkAxis *y, float *origin, float *max)
{
  vtkTransform2D *transform = vtkTransform2D::New();
  this->CalculatePlotTransform(x, y, transform);
  float torigin[2];
  transform->InverseTransformPoints(origin, torigin, 1);
  float tmax[2];
  transform->InverseTransformPoints(max, tmax, 1);

  // Ensure we preserve the directionality of the axes
  if (x->GetMaximum() > x->GetMinimum())
    {
    x->SetMaximum(torigin[0] > tmax[0] ? torigin[0] : tmax[0]);
    x->SetMinimum(torigin[0] < tmax[0] ? torigin[0] : tmax[0]);
    }
  else
    {
    x->SetMaximum(torigin[0] < tmax[0] ? torigin[0] : tmax[0]);
    x->SetMinimum(torigin[0] > tmax[0] ? torigin[0] : tmax[0]);
    }
  if (y->GetMaximum() > y->GetMinimum())
    {
    y->SetMaximum(torigin[1] > tmax[1] ? torigin[1] : tmax[1]);
    y->SetMinimum(torigin[1] < tmax[1] ? torigin[1] : tmax[1]);
    }
  else
    {
    y->SetMaximum(torigin[1] < tmax[1] ? torigin[1] : tmax[1]);
    y->SetMinimum(torigin[1] > tmax[1] ? torigin[1] : tmax[1]);
    }
  x->RecalculateTickSpacing();
  y->RecalculateTickSpacing();
  transform->Delete();
}

//-----------------------------------------------------------------------------
bool vtkChartXY::MouseWheelEvent(const vtkContextMouseEvent &, int delta)
{
  this->Tooltip->SetVisible(false);
  // Get the bounds of each plot.
  for (int i = 0; i < 4; ++i)
    {
    vtkAxis *axis = this->ChartPrivate->axes[i];
    double min = axis->GetMinimum();
    double max = axis->GetMaximum();
    double frac = (max - min) * 0.1;
    if (frac > 0.0)
      {
      min += delta*frac;
      max -= delta*frac;
      }
    else
      {
      min -= delta*frac;
      max += delta*frac;
      }
    axis->SetMinimum(min);
    axis->SetMaximum(max);
    axis->RecalculateTickSpacing();
    }

  this->RecalculatePlotTransforms();

  // Mark the scene as dirty
  this->Scene->SetDirty(true);

  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::KeyPressEvent(const vtkContextKeyEvent &key)
{
  switch (key.GetKeyCode())
    {
    // Reset the chart axes
    case 'r':
    case 'R':
      this->RecalculateBounds();
      this->Scene->SetDirty(true);
    }

  return true;
}

//-----------------------------------------------------------------------------
bool vtkChartXY::RemovePlotFromCorners(vtkPlot *plot)
{
  // We know the plot will only ever be in one of the corners
  for (size_t i = 0; i < this->ChartPrivate->PlotCorners.size(); ++i)
    {
    if(this->ChartPrivate->PlotCorners[i]->RemoveItem(plot))
      {
      return true;
      }
    }
  return false;
}

//-----------------------------------------------------------------------------
void vtkChartXY::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "Axes: " << endl;
  for (int i = 0; i < 4; ++i)
    {
    this->ChartPrivate->axes[i]->PrintSelf(os, indent.GetNextIndent());
    }
  if (this->ChartPrivate)
    {
    os << indent << "Number of plots: " << this->ChartPrivate->plots.size()
       << endl;
    for (unsigned int i = 0; i < this->ChartPrivate->plots.size(); ++i)
      {
      os << indent << "Plot " << i << ":" << endl;
      this->ChartPrivate->plots[i]->PrintSelf(os, indent.GetNextIndent());
      }
    }

}
