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

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/VolViewCopyright.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 "vtkKWInteractorStyleLightboxView.h"

#include "vtkActor2D.h"
#include "vtkCamera.h"
#include "vtkColorTransferFunction.h"
#include "vtkCornerAnnotation.h"
#include "vtkImageActor.h"
#include "vtkImageData.h"
#include "vtkKWEvent.h"
#include "vtkKWFrame.h"
#include "vtkKWImageMapToWindowLevelColors.h"
#include "vtkKWLightboxWidget.h"
#include "vtkObjectFactory.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"

vtkCxxRevisionMacro(vtkKWInteractorStyleLightboxView, "$Revision: 1.35 $");
vtkStandardNewMacro(vtkKWInteractorStyleLightboxView);

vtkCxxSetObjectMacro(vtkKWInteractorStyleLightboxView,
                     InteractiveMap,
                     vtkKWImageMapToWindowLevelColors);

vtkCxxSetObjectMacro(vtkKWInteractorStyleLightboxView,
                     ImageData, vtkImageData);

//----------------------------------------------------------------------------
vtkKWInteractorStyleLightboxView::vtkKWInteractorStyleLightboxView()
{
  this->ImageData = NULL;
  this->ImageActors = NULL;
  this->InteractiveMap = NULL;
  this->InitialRendererIndex = 0;
}

//----------------------------------------------------------------------------
vtkKWInteractorStyleLightboxView::~vtkKWInteractorStyleLightboxView()
{
  this->SetImageData(NULL);
  this->SetImageActors(NULL);
  this->SetInteractiveMap(NULL);
}

//----------------------------------------------------------------------------
void vtkKWInteractorStyleLightboxView::StartWindowLevel()
{
  if (!this->Interactor || !this->ImageMapToRGBA || !this->InteractiveMap)
    {
    return;
    }

  vtkKWLightboxWidget *widget =
    vtkKWLightboxWidget::SafeDownCast(this->GetRenderWidget());
  if (!widget)
    {
    return;
    }

  this->InitialWindow = this->ImageMapToRGBA->GetWindow();
  this->InitialLevel = this->ImageMapToRGBA->GetLevel();

  int x = this->Interactor->GetEventPosition()[0];
  int y = this->Interactor->GetEventPosition()[1];
  
  if (!widget->ComputeWorldCoordinate(x, y, 0, &this->InitialRendererIndex))
    {
    return;
    }
  
  this->InteractiveMap->SetWindow(this->InitialWindow);
  this->InteractiveMap->SetLevel(this->InitialLevel);
  this->InteractiveMap->SetInput(this->ImageMapToRGBA->GetInput());
  this->InteractiveMap->SetLookupTable(
    vtkColorTransferFunction::SafeDownCast(
      this->ImageMapToRGBA->GetLookupTable()));

  if (this->ImageActors && this->ImageActors[this->InitialRendererIndex])
    {
    this->ImageActors[this->InitialRendererIndex]->SetInput(
      this->InteractiveMap->GetOutput());
    }

  widget->GetCornerAnnotation()->SetWindowLevel(this->InteractiveMap);
  
  this->InitialX = x;
  this->InitialY = y;
}

//----------------------------------------------------------------------------
void vtkKWInteractorStyleLightboxView::StopWindowLevel()
{
  if (!this->ImageMapToRGBA || !this->ImageMapToRGBA->GetInput() )
    {
    return;
    }

  if (this->ImageActors && this->ImageActors[this->InitialRendererIndex])
    {
    this->ImageActors[this->InitialRendererIndex]->SetInput(
      this->ImageMapToRGBA->GetOutput());
    }

  vtkKWLightboxWidget *widget = 
    vtkKWLightboxWidget::SafeDownCast(this->GetRenderWidget());
  if (widget)
    {
    widget->GetCornerAnnotation()->SetWindowLevel(this->ImageMapToRGBA);
    }

  this->SetWindowLevel(this->InteractiveMap->GetWindow(), 
                       this->InteractiveMap->GetLevel());

  double args[3];
  args[0] = this->InteractiveMap->GetWindow();
  args[1] = this->InteractiveMap->GetLevel();
  args[2] = this->EventIdentifier;

  // Give two option to process this action
  // WindowLevelChangingEndEvent: since during interaction WindowLevel() was
  // invoking WindowLevelChangingEvent, let's invoke something telling that
  // the interaction is done.
  // WindowLevelChangedEvent: the usual one (for compatibility). 

  this->InvokeEvent(vtkKWEvent::WindowLevelChangingEndEvent, args);
  this->InvokeEvent(vtkKWEvent::WindowLevelChangedEvent, args);
}

//----------------------------------------------------------------------------
void vtkKWInteractorStyleLightboxView::WindowLevel()
{
  vtkKWLightboxWidget *widget =
    vtkKWLightboxWidget::SafeDownCast(this->GetRenderWidget());
  if (!widget)
    {
    return;
    }
  
  vtkWindow *window = widget->GetRenderWindow();
  if (!window)
    {
    return;
    }
  
  int *size = window->GetSize();
  
  int x = this->Interactor->GetEventPosition()[0];
  int y = this->Interactor->GetEventPosition()[1];
  
  double dx = 4.0 * (x - this->InitialX) / size[0];
  double dy = 4.0 * (y - this->InitialY) / size[1];
  
  if (fabs(this->InitialWindow) > 0.01)
    {
    dx *= this->InitialWindow;
    }
  else
    {
    dx *= (this->InitialWindow < 0 ? -0.01 : 0.01);
    }
  
  if (fabs(this->InitialLevel) > 0.01)
    {
    dy *= this->InitialLevel;
    }
  else
    {
    dy *= (this->InitialLevel < 0 ? -0.01 : 0.01);
    }
  
  if (this->InitialWindow < 0.0)
    {
    dx *= -1;
    }
  if (this->InitialLevel < 0.0)
    {
    dy *= -1;
    }
  
  // copute new window level
  double newWindow = dx + this->InitialWindow;
  double newLevel = this->InitialLevel - dy;
  
  // stay away from zero
  if (fabs(newWindow) < 0.01)
    {
    newWindow = 0.01 * (newWindow < 0 ? -1 : 1);
    }
  if (fabs(newLevel) < 0.01)
    {
    newLevel = 0.01 * (newLevel < 0 ? -1 : 1);
    }
  
  vtkImageData *input = vtkImageData::SafeDownCast(
    this->ImageMapToRGBA->GetInput());
  if (input && 
      input->GetScalarType() != VTK_FLOAT &&
      input->GetScalarType() != VTK_DOUBLE)
    {
    newWindow = (long)newWindow;
    newLevel = (long)newLevel;
    }

  if (this->InteractiveMap)
    {
    this->InteractiveMap->SetWindow(newWindow);
    this->InteractiveMap->SetLevel(newLevel);
    }

  this->PerformInteractiveRender();

  double args[3];
  args[0] = newWindow;
  args[1] = newLevel;
  args[2] = this->EventIdentifier;
  this->InvokeEvent(vtkKWEvent::WindowLevelChangingEvent, args);
}

//----------------------------------------------------------------------------
void vtkKWInteractorStyleLightboxView::SetImageActors(vtkImageActor **actors)
{
  this->ImageActors = actors;
}

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