//----------------------------------------------------------------------------
void vesKiwiImageWidgetRepresentation::scrollImageSlice(double deltaX, double deltaY)
{
  deltaY *= -1;

  vesSharedPtr<vesRenderer> ren = this->renderer();
  vesVector3f viewFocus = ren->camera()->focalPoint();
  vesVector3f viewFocusDisplay = ren->computeWorldToDisplay(viewFocus);
  float focalDepth = viewFocusDisplay[2];

  this->Internal->LastTouchPosition += vesVector2f(deltaX, deltaY);
  vesVector3f worldTouchPosition = ren->computeDisplayToWorld(vesVector3f(this->Internal->LastTouchPosition[0], this->Internal->LastTouchPosition[1], focalDepth));
  worldTouchPosition -= this->Internal->GrabOffset.cast<float>();

  int flatDimension = this->Internal->SelectedImageDimension;
  vesVector3f planeNormal(0, 0, 0);
  planeNormal[flatDimension] = 1.0;

  int extent[6];
  vesVector3d spacing;
  vesVector3d origin;
  this->imageData()->GetOrigin(origin.data());
  this->imageData()->GetSpacing(spacing.data());
  this->imageData()->GetExtent(extent);

  double distanceAlongInteractionAxis = worldTouchPosition.dot(planeNormal);
  double distanceFromOriginAlongAxis = distanceAlongInteractionAxis - origin[flatDimension];
  int slicesFromOrigin = distanceFromOriginAlongAxis / spacing[flatDimension] - extent[flatDimension*2]*spacing[flatDimension];

  this->scheduleSetSliceIndex(flatDimension, slicesFromOrigin);
}
//----------------------------------------------------------------------------
bool vesKiwiAnimationRepresentation::handleSingleTouchTap(int displayX, int displayY)
{
  vesVector2f textSize = this->Internal->PlayRep->textureSize();
  double margin = 30;
  textSize += vesVector2f(margin, margin);

  if (displayX <= textSize[0] && displayY <= textSize[1]) {

    this->Internal->PlayMode = !this->Internal->PlayMode;
    if (this->Internal->PlayMode) {
      this->Internal->AnimationT0 = vtkTimerLog::GetUniversalTime();
      this->Internal->AnimationFrameStart = this->Internal->CurrentFrame;
    }

    std::string playText = this->Internal->PlayMode ? "[Pause]" : "[Play]";
    this->Internal->PlayRep->setText(playText);

    return true;
  }
  else if (displayX > this->renderer()->width() - 50 && displayY < 50) {

    vesShaderProgram::Ptr newShader = this->Internal->GeometryShader;
    if (this->Internal->FrameReps[0]->shaderProgram() == newShader) {
      newShader = this->Internal->TextureShader;
    }

    for (size_t i = 0; i < this->Internal->FrameReps.size(); ++i) {
      this->Internal->FrameReps[i]->setShaderProgram(newShader);
    }

  }

  return false;
}
//----------------------------------------------------------------------------
vesSourceDataT2f::Ptr vesKiwiDataConversionTools::ConvertTCoords(vtkDataArray* tcoords)
{
  if (!tcoords || tcoords->GetNumberOfComponents() != 2) {
    return vesSourceDataT2f::Ptr();
  }

  const size_t nTuples = tcoords->GetNumberOfTuples();
  vesSourceDataT2f::Ptr texCoordSourceData(new vesSourceDataT2f());

  for (size_t i = 0; i < nTuples; ++i) {
    double* values = tcoords->GetTuple(i);
    vesVertexDataT2f textureCoordinate;
    textureCoordinate.m_textureCoordinate = vesVector2f(values[0], values[1]);
    texCoordSourceData->pushBack(textureCoordinate);
  }

  return texCoordSourceData;
}
//----------------------------------------------------------------------------
void vesKiwiAnimationRepresentation::initializeWithShader(
  vesSharedPtr<vesShaderProgram> geometryShader, 
  vesSharedPtr<vesShaderProgram> textureShader,
  vesSharedPtr<vesShaderProgram> gouraudTextureShader)
{
  this->Internal->GeometryShader = geometryShader;
  this->Internal->TextureShader = gouraudTextureShader;

  this->Internal->TextRep = new vesKiwiText2DRepresentation();
  this->Internal->TextRep->initializeWithShader(textureShader);
  this->Internal->TextRep->setDisplayPosition(vesVector2f(10, 10));
  this->Internal->TextRep->setText("Time: 0.000 s");
  this->Internal->AllReps.push_back(this->Internal->TextRep);

  this->Internal->PlayRep = new vesKiwiText2DRepresentation();
  this->Internal->PlayRep->initializeWithShader(textureShader);
  this->Internal->PlayRep->setText("[Play]");
  this->Internal->AllReps.push_back(this->Internal->PlayRep);
}
//----------------------------------------------------------------------------
void vesKiwiDataConversionTools::SetTextureCoordinates(vtkDataArray* tcoords,
  vesSharedPtr<vesGeometryData> geometryData)
{
  assert(tcoords);
  assert(tcoords->GetNumberOfComponents() == 2);
  assert(geometryData);

  const size_t nTuples = tcoords->GetNumberOfTuples();

  vesSourceDataT2f::Ptr texCoordSourceData (new vesSourceDataT2f());

  for (size_t i = 0; i < nTuples; ++i)
    {
    double* values = tcoords->GetTuple(i);
    vesVertexDataT2f textureCoordinate;
    textureCoordinate.m_textureCoordinate = vesVector2f(values[0], values[1]);
    texCoordSourceData->pushBack(textureCoordinate);
    }

  geometryData->addSource(texCoordSourceData);
}
//----------------------------------------------------------------------------
void vesKiwiAnimationRepresentation::willRender(vesSharedPtr<vesRenderer> renderer)
{
  vesNotUsed(renderer);

  if (this->Internal->PlayMode) {

    double currentTime = vtkTimerLog::GetUniversalTime();
    double elapsedTime = currentTime - this->Internal->AnimationT0;

    double animationFramesPerSecond = this->Internal->AnimationFramesPerSecond;

    int elapsedFrames = static_cast<int>(elapsedTime * animationFramesPerSecond);

    if (elapsedFrames != 0) {
      this->Internal->CurrentFrame += elapsedFrames;
      this->Internal->CurrentFrame = this->Internal->CurrentFrame % this->Internal->NumberOfFrames;
      this->Internal->AnimationT0 = currentTime;
    }
  }

  int screenHeight = this->renderer()->height();
  double margin = 10;
  vesVector2f textSize = this->Internal->PlayRep->textureSize();
  this->Internal->PlayRep->setDisplayPosition(vesVector2f(margin, screenHeight - (margin + textSize[1])));


  if (this->Internal->LastFrame != this->Internal->CurrentFrame) {

    std::stringstream str;
    str.precision(4);
    str << "Time: " << std::fixed << 0.0001*this->Internal->CurrentFrame << " s";
    this->Internal->TextRep->setText(str.str());

    this->Internal->FrameReps[this->Internal->LastFrame]->removeSelfFromRenderer(this->renderer());
    this->Internal->FrameReps[this->Internal->CurrentFrame]->addSelfToRenderer(this->renderer());
    this->Internal->LastFrame = this->Internal->CurrentFrame;
  }
}
//----------------------------------------------------------------------------
bool vesKiwiImageWidgetRepresentation::handleSingleTouchDown(int displayX, int displayY)
{
  if (!this->Internal->InteractionEnabled) {
    return false;
  }

  // calculate the focal depth so we'll know how far to move
  vesSharedPtr<vesRenderer> ren = this->renderer();

  // flip Y coordinate
  displayY = ren->height() - displayY;
  this->Internal->LastTouchPosition = vesVector2f(displayX, displayY);

  std::tr1::shared_ptr<vesCamera> camera = ren->camera();
  vesVector3f cameraFocalPoint = camera->focalPoint();
  vesVector3f cameraPosition = camera->position();
  vesVector3f displayFocus = ren->computeWorldToDisplay(cameraFocalPoint);
  float focalDepth = displayFocus[2];

  vesVector3f rayPoint0 = cameraPosition;
  vesVector3f rayPoint1 = ren->computeDisplayToWorld(vesVector3f(displayX, displayY, focalDepth));
  vesVector3f touchWorldPosition = rayPoint1;

  vesVector3f rayDirection = rayPoint1 - rayPoint0;
  rayDirection.normalize();
  rayPoint1 += rayDirection*1e6;


  vtkNew<vtkAppendPolyData> appendFilter;
  std::vector<int> cellIdToPlaneId;

  for (int i = 0; i < 3; ++i) {
    if (this->planeVisibility(i)) {
      appendFilter->AddInputData(this->Internal->SliceReps[i]->imagePlanePolyData());
      cellIdToPlaneId.push_back(i);
    }
  }

  appendFilter->Update();

  vtkNew<vtkCellLocator> locator;
  locator->SetDataSet(appendFilter->GetOutput());
  locator->BuildLocator();

  double p0[3] = {rayPoint0[0], rayPoint0[1], rayPoint0[2]};
  double p1[3] = {rayPoint1[0], rayPoint1[1], rayPoint1[2]};

  double pickPoint[3];
  double t;
  double paramCoords[3];
  vtkIdType cellId = -1;
  int subId;

  int result = locator->IntersectWithLine(p0, p1, 0.0, t, pickPoint, paramCoords, subId, cellId);
  if (result == 1) {
    this->Internal->SelectedImageDimension = cellIdToPlaneId[cellId];
    this->interactionOn();

    int currentDimension = this->Internal->SelectedImageDimension;
    int currentSliceIndex = this->Internal->CurrentSliceIndices[this->Internal->SelectedImageDimension];
    int extent[6];
    vesVector3d spacing;
    vesVector3d origin;
    this->imageData()->GetOrigin(origin.data());
    this->imageData()->GetSpacing(spacing.data());
    this->imageData()->GetExtent(extent);
    double sliceDistanceAlongAxis = spacing[currentDimension] * (currentSliceIndex + extent[currentDimension*2]);
    origin[currentDimension] += sliceDistanceAlongAxis;
    this->Internal->GrabOffset = touchWorldPosition.cast<double>() - origin;

  }
  else {
    this->Internal->SelectedImageDimension = -1;
    this->interactionOff();
  }

  return this->interactionIsActive();
}