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

  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 "vtkVVReviewInterface.h"

#include "vtkImageData.h"
#include "vtkObjectFactory.h"

#include "vtkKW2DRenderWidget.h"
#include "vtkKWFrameWithLabel.h"
#include "vtkKWInternationalization.h"
#include "vtkKWSimpleAnimationWidget.h"
#include "vtkKWVolumeWidget.h"
#include "vtkKWIcon.h"
#include "vtkKWNotebook.h"
#include "vtkKWUserInterfaceManagerNotebook.h"

#include "vtkVVApplication.h"
#include "vtkVVDataItemPool.h"
#include "vtkVVSelectionFrameLayoutManager.h"
#include "vtkVVSnapshotPresetSelector.h"
#include "vtkVVSnapshotPool.h"
#include "vtkVVSnapshot.h"
#include "vtkVVWindowBase.h"

//---------------------------------------------------------------------------

#define VTK_VV_REVIEW_UIP_LABEL        "Review"

//---------------------------------------------------------------------------
vtkStandardNewMacro(vtkVVReviewInterface);
vtkCxxRevisionMacro(vtkVVReviewInterface, "$Revision: 1.40 $");

//---------------------------------------------------------------------------
vtkVVReviewInterface::vtkVVReviewInterface()
{
  this->SetName(ks_("Review Panel|Title|Review"));

  this->Window = NULL;

  // Snapshot

  this->SnapshotPresetFrame = NULL;
  this->SnapshotPresetSelector = NULL;

  // Movie

  this->AnimationFrame = NULL;
  this->AnimationWidget = NULL;
}

//---------------------------------------------------------------------------
vtkVVReviewInterface::~vtkVVReviewInterface()
{
  // Snapshot

  if (this->SnapshotPresetFrame)
    {
    this->SnapshotPresetFrame->Delete();
    this->SnapshotPresetFrame = NULL;
    }

  if (this->SnapshotPresetSelector)
    {
    this->SnapshotPresetSelector->Delete();
    this->SnapshotPresetSelector = NULL;
    }

  // Movie

  if (this->AnimationFrame)
    {
    this->AnimationFrame->Delete();
    this->AnimationFrame = NULL;
    }

  if (this->AnimationWidget)
    {
    this->AnimationWidget->Delete();
    this->AnimationWidget = NULL;
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::SetWindow(vtkVVWindowBase *arg)
{
  if (this->Window == arg)
    {
    return;
    }
  this->Window = arg;
  this->Modified();

  this->Update();
}

// --------------------------------------------------------------------------
void vtkVVReviewInterface::Create()
{
  if (this->IsCreated())
    {
    vtkErrorMacro("The panel is already created.");
    return;
    }

  // Create the superclass instance (and set the application)

  this->Superclass::Create();

  ostrstream tk_cmd;

  vtkKWWidget *page;
  vtkKWFrame *frame;

  // --------------------------------------------------------------
  // Add a "Review" page

  this->ReviewPageID = this->AddPage(NULL, this->GetName());
  this->SetPageIconToPredefinedIcon(
    this->ReviewPageID, vtkKWIcon::IconNuvola22x22DevicesCamera);

  page = this->GetPageWidget(this->ReviewPageID);

  // --------------------------------------------------------------
  // Snapshot : frame

  if (!this->SnapshotPresetFrame)
    {
    this->SnapshotPresetFrame = vtkKWFrameWithLabel::New();
    }

  this->SnapshotPresetFrame->SetParent(this->GetPagesParentWidget());
  this->SnapshotPresetFrame->Create();
  this->SnapshotPresetFrame->SetLabelText(ks_("Snapshot|Snapshots"));
  this->SnapshotPresetFrame->SetChangePackingOnCollapse(1);
    
  tk_cmd << "pack " << this->SnapshotPresetFrame->GetWidgetName()
         << " -side top -anchor nw -fill both -expand t -padx 2 -pady 2 " 
         << " -in " << page->GetWidgetName() << endl;

  frame = this->SnapshotPresetFrame->GetFrame();

  // --------------------------------------------------------------
  // Snapshot : snapshot list

  if (!this->SnapshotPresetSelector)
    {
    this->SnapshotPresetSelector = vtkVVSnapshotPresetSelector::New();
    }

  this->SnapshotPresetSelector->SetParent(frame);
  this->SnapshotPresetSelector->Create();
  this->SnapshotPresetSelector->SetListHeight(1);
  this->SnapshotPresetSelector->SelectSpinButtonsVisibilityOff();
  this->SnapshotPresetSelector->LocateButtonVisibilityOff();
  this->SnapshotPresetSelector->ApplyPresetOnSelectionOn();
  this->SnapshotPresetSelector->ThumbnailColumnVisibilityOn();
  this->SnapshotPresetSelector->SetPresetUpdateCommand(
    this, "SnapshotPresetUpdateCallback");
  this->SnapshotPresetSelector->SetPresetHasChangedCommand(
    this, "SnapshotPresetHasChangedCallback");
  this->SnapshotPresetSelector->SetPresetRemoveCommand(
    this, "SnapshotPresetRemoveCallback");
  this->SnapshotPresetSelector->SetPresetRemovedCommand(
    this, "SnapshotPresetRemovedCallback");
  this->SnapshotPresetSelector->SetPresetApplyCommand(
    this, "SnapshotPresetApplyCallback ");

  tk_cmd << "pack " << this->SnapshotPresetSelector->GetWidgetName()
         << " -side top -anchor nw -fill both -expand t" << endl;

  // --------------------------------------------------------------
  // Movie : main frame

  if (!this->AnimationFrame)
    {
    this->AnimationFrame = vtkKWFrameWithLabel::New();
    }

  this->AnimationFrame->SetParent(this->GetPagesParentWidget());
  this->AnimationFrame->Create();
  this->AnimationFrame->SetLabelText(k_("Movie"));

  tk_cmd << "pack " << this->AnimationFrame->GetWidgetName()
         << " -side top -anchor nw -fill x -expand f -padx 2 -pady 2 " 
         << " -in " << page->GetWidgetName() << endl;
  
  frame = this->AnimationFrame->GetFrame();

  // --------------------------------------------------------------
  // Movie : animation widget

  if (!this->AnimationWidget)
    {
    this->AnimationWidget = vtkKWSimpleAnimationWidget::New();
    }

  this->AnimationWidget->SetParent(frame);
  this->AnimationWidget->Create();

  tk_cmd << "pack " << this->AnimationWidget->GetWidgetName()
         << " -side top -anchor nw -fill both -expand y -padx 2 -pady 2" << endl;

  // --------------------------------------------------------------
  // Pack 

  tk_cmd << ends;
  this->Script(tk_cmd.str());
  tk_cmd.rdbuf()->freeze(0);

  // Update according to the current Window

  this->Update();
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::UpdateSnapshotPresetThumbnail(int id)
{
  vtkVVSelectionFrameLayoutManager *mgr = 
    this->Window->GetDataSetWidgetLayoutManager();
  if (mgr && id >= 0)
    {
    vtkImageData *screenshot = vtkImageData::New();
    mgr->AppendAllWidgetsToImageDataFast(screenshot);
    this->SnapshotPresetSelector->BuildPresetThumbnailAndScreenshotFromImage(
      id, screenshot);
    screenshot->Delete();
    vtkVVSnapshot *snapshot = 
      this->SnapshotPresetSelector->GetPresetSnapshot(id);
    if (snapshot)
      {
      vtkKWIcon *preset_thumbnail = 
        this->SnapshotPresetSelector->GetPresetThumbnail(id);
      if (preset_thumbnail)
        {
        vtkKWIcon *snapshot_thumbnail = snapshot->GetThumbnail();
        if (!snapshot_thumbnail)
          {
          snapshot_thumbnail = vtkKWIcon::New();
          snapshot->SetThumbnail(snapshot_thumbnail);
          snapshot_thumbnail->Delete();
          }
        snapshot_thumbnail->DeepCopy(preset_thumbnail);
        // make sure the preset thumb is not refreshed from the snapshot thumb
        preset_thumbnail->Modified(); 
        }
      vtkKWIcon *preset_screenshot = 
        this->SnapshotPresetSelector->GetPresetScreenshot(id);
      if (preset_screenshot)
        {
        vtkKWIcon *snapshot_screenshot = snapshot->GetScreenshot();
        if (!snapshot_screenshot)
          {
          snapshot_screenshot = vtkKWIcon::New();
          snapshot->SetScreenshot(snapshot_screenshot);
          snapshot_screenshot->Delete();
          }
        snapshot_screenshot->DeepCopy(preset_screenshot);
        // make sure the preset thumb is not refreshed from the snapshot thumb
        preset_screenshot->Modified(); 
        }
      }
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::SnapshotPresetApplyCallback(int id)
{
  if (!this->SnapshotPresetSelector || id < 0 || !this->Window)
    {
    return;
    }

  vtkVVSnapshot *snapshot = this->SnapshotPresetSelector->GetPresetSnapshot(id);
  if (!snapshot)
    {
    return;
    }

  this->Window->RestoreSnapshot(snapshot);

  if (!this->SnapshotPresetSelector->GetPresetThumbnail(id) ||
      !this->SnapshotPresetSelector->GetPresetScreenshot(id))
    {
    this->UpdateSnapshotPresetThumbnail(id);
    }
}

//---------------------------------------------------------------------------
int vtkVVReviewInterface::SnapshotPresetAddCallback()
{
  if (!this->SnapshotPresetSelector)
    {
    return -1;
    }

  int id = this->SnapshotPresetSelector->InsertPreset(
    this->SnapshotPresetSelector->GetIdOfNthPreset(0));
  if (id < 0)
    {
    return -1;
    }

  this->SnapshotPresetUpdateCallback(id);

  vtkVVSnapshot *snapshot = this->SnapshotPresetSelector->GetPresetSnapshot(id);
  if (snapshot)
    {
    this->SnapshotPresetSelector->SetPresetComment(
      id, snapshot->GetDescription());
    if (!this->SnapshotPresetSelector->GetPresetThumbnail(id))
      {
      this->SnapshotPresetSelector->SetPresetThumbnail(
        id, snapshot->GetThumbnail());
      }
    if (!this->SnapshotPresetSelector->GetPresetScreenshot(id))
      {
      this->SnapshotPresetSelector->SetPresetScreenshot(
        id, snapshot->GetScreenshot());
      }
    int old_apply = this->SnapshotPresetSelector->GetApplyPresetOnSelection();
    this->SnapshotPresetSelector->SetApplyPresetOnSelection(0);
    this->SnapshotPresetSelector->SelectPreset(id); // select without apply
    this->SnapshotPresetSelector->SetApplyPresetOnSelection(old_apply);
    }

  this->UpdateSmallPresetCounter();

  return id;
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::SnapshotPresetUpdateCallback(int id)
{
  if (!this->SnapshotPresetSelector || id < 0 || !this->Window)
    {
    return;
    }

  vtkVVSnapshot *snapshot = this->SnapshotPresetSelector->GetPresetSnapshot(id);
  if (snapshot)
    {
    this->Window->UpdateSnapshot(snapshot);
    }
  else
    {
    this->SnapshotPresetSelector->SetPresetSnapshot(
      id, this->Window->TakeSnapshot());
    }
  
  this->UpdateSnapshotPresetThumbnail(id);
}

//---------------------------------------------------------------------------
int vtkVVReviewInterface::SnapshotPresetRemoveCallback(int id)
{
  if (!this->SnapshotPresetSelector || id < 0 || !this->Window)
    {
    return 0;
    }

  vtkVVSnapshot *snapshot = this->SnapshotPresetSelector->GetPresetSnapshot(id);
  if (snapshot)
    {
    this->Window->GetSnapshotPool()->RemoveSnapshot(snapshot);
    }

  return 1;
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::SnapshotPresetRemovedCallback()
{
  this->UpdateSmallPresetCounter();
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::SnapshotPresetHasChangedCallback(int id)
{
  if (!this->SnapshotPresetSelector || id < 0 || !this->Window)
    {
    return;
    }

  vtkVVSnapshot *snapshot = this->SnapshotPresetSelector->GetPresetSnapshot(id);
  if (snapshot)
    {
    snapshot->SetDescription(
      this->SnapshotPresetSelector->GetPresetComment(id));
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::Update()
{
  this->Superclass::Update();

  if (this->AnimationWidget)
    {
    vtkKWRenderWidget *rw = this->Window->GetSelectedRenderWidget();
    vtkKW2DRenderWidget *rw2d = vtkKW2DRenderWidget::SafeDownCast(rw); 
    vtkKWVolumeWidget *vw = vtkKWVolumeWidget::SafeDownCast(rw); 

    vtkVVDataItem *data = 
      this->Window ? this->Window->GetSelectedDataItem() : NULL;
    
    if (!data || (!rw2d && !vw))
      {
      this->AnimationWidget->SetEnabled(0);
      }
    else
      {
      if (rw2d)
        {
        this->AnimationWidget->SetSliceSetCommand(rw2d, "SetSlice");
        this->AnimationWidget->SetSliceGetCommand(rw2d, "GetSlice");
        this->AnimationWidget->SetSliceRange(
          rw2d->GetSliceMin(), rw2d->GetSliceMax());
        this->AnimationWidget->SetAnimationTypeToSlice();
        if (!rw2d->GetHasSliceControl())
          {
          this->AnimationWidget->SetEnabled(0);
          }
        }
      else if (vw)
        {
        this->AnimationWidget->SetAnimationTypeToCamera();
        }
      this->AnimationWidget->SetRenderWidget(rw);
      }
    }

  int has_data = (this->Window->GetDataItemPool() && 
                  this->Window->GetDataItemPool()->GetNumberOfDataItems());
  
  if (this->SnapshotPresetSelector)
    {
    if (has_data)
      {
      this->SnapshotPresetSelector->SetPresetAddCommand(
        this, "SnapshotPresetAddCallback");
      }
    else
      {
      this->SnapshotPresetSelector->SetPresetAddCommand(NULL, NULL);
      }
    this->PopulateSnapshotPresets();
    this->SnapshotPresetSelector->Update();
    this->SnapshotPresetSelector->SetEnabled(
      has_data ? this->GetEnabled() : 0);
    this->UpdateSmallPresetCounter();
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::UpdateSmallPresetCounter()
{
  if (this->SnapshotPresetSelector)
    {
    vtkKWUserInterfaceManagerNotebook *mgr = 
      vtkKWUserInterfaceManagerNotebook::SafeDownCast(
        this->GetUserInterfaceManager());
    if (mgr)
      {
      mgr->GetNotebook()->SetPageSmallCounterValue(
        this->ReviewPageID, this->SnapshotPresetSelector->GetNumberOfPresets());
      }
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::PopulateSnapshotPresets()
{
  if (!this->SnapshotPresetSelector || !this->Window)
    {
    return;
    }

  // Add or remove presets 
  
  vtkVVSnapshotPool *snapshot_pool = this->Window->GetSnapshotPool();
  
  int i;

  // Add the snapshots in the app that are not in the preset selector

  int nb_snapshots = snapshot_pool->GetNumberOfSnapshots();
  for (i = 0; i < nb_snapshots; i++)
    {
    vtkVVSnapshot *snapshot = snapshot_pool->GetNthSnapshot(i);
    if (snapshot &&
        !this->SnapshotPresetSelector->HasPresetWithSnapshot(snapshot))
      {
      int id = this->SnapshotPresetSelector->InsertPreset(
        this->SnapshotPresetSelector->GetIdOfNthPreset(0));
      this->SnapshotPresetSelector->SetPresetSnapshot(id, snapshot);
      this->SnapshotPresetSelector->SetPresetComment(
        id, snapshot->GetDescription());
      this->SnapshotPresetSelector->SetPresetThumbnail(
        id, snapshot->GetThumbnail());
      this->SnapshotPresetSelector->SetPresetScreenshot(
        id, snapshot->GetScreenshot());
      }
    }

  // Remove the one in the preset selector that are not in the app

  int done = 0;
  while (!done)
    {
    done = 1;
    int nb_presets = this->SnapshotPresetSelector->GetNumberOfPresets();
    for (i = 0; i < nb_presets; i++)
      {
      int id = this->SnapshotPresetSelector->GetIdOfNthPreset(i);
      vtkVVSnapshot *snapshot = 
        this->SnapshotPresetSelector->GetPresetSnapshot(id);
      if (snapshot && !snapshot_pool->HasSnapshot(snapshot))
        {
        this->SnapshotPresetSelector->RemovePreset(id);
        done = 0;
        break;
        }
      }
    }
}

//---------------------------------------------------------------------------
void vtkVVReviewInterface::UpdateEnableState()
{
  this->Superclass::UpdateEnableState();

  // Snapshot

  if (this->SnapshotPresetFrame)
    {
    this->SnapshotPresetFrame->SetEnabled(this->GetEnabled());
    }

  if (this->SnapshotPresetSelector)
    {
    this->SnapshotPresetSelector->SetEnabled(this->GetEnabled());
    }

  // Movie

  if (this->AnimationFrame)
    {
    this->AnimationFrame->SetEnabled(this->GetEnabled());
    }

  if (this->AnimationWidget)
    {
    this->AnimationWidget->SetEnabled(this->GetEnabled());
    }
}

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

  os << indent << "Window: " << this->Window << endl;
}

