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

  Program:   ParaView
  Module:    vtkPVAnimationInterface.cxx

  Copyright (c) Kitware, Inc.
  All rights reserved.
  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkPVAnimationInterface.h"

#include "vtkErrorCode.h"
#include "vtkKWCheckButton.h"
#include "vtkKWEntry.h"
#include "vtkKWFrame.h"
#include "vtkKWLabel.h"
#include "vtkKWLabeledEntry.h"
#include "vtkKWLabeledFrame.h"
#include "vtkKWMenu.h"
#include "vtkKWMenuButton.h"
#include "vtkKWMessageDialog.h"
#include "vtkKWPushButton.h"
#include "vtkKWScale.h"
#include "vtkKWText.h"
#include "vtkKWView.h"
#include "vtkObjectFactory.h"
#include "vtkPVApplication.h"
#include "vtkPVData.h"
#include "vtkPVRenderModule.h"
#include "vtkPVRenderView.h"
#include "vtkPVSource.h"
#include "vtkPVSourceCollection.h"
#include "vtkPVWidget.h"
#include "vtkPVWidgetCollection.h"
#include "vtkPVWidgetProperty.h"
#include "vtkPVWindow.h"
#include "vtkKWLoadSaveDialog.h"
#include "vtkWindowToImageFilter.h"
#include "vtkJPEGWriter.h"
#include "vtkTIFFWriter.h"
#include "vtkPNGWriter.h"
#include "vtkRenderWindow.h"
#include "vtkPVProcessModule.h"
#include "vtkPVPart.h"
#include "vtkPVPartDisplay.h"
#include "vtkCompleteArrays.h"

#include "vtkPVAnimationInterfaceEntry.h"
#include "vtkCollectionIterator.h"
#include "vtkString.h"
#include "vtkKWRange.h"
#include "vtkCommand.h"
#include "vtkKWEvent.h"

#ifndef _WIN32
# include <unistd.h>
#endif

#include <vtkstd/vector>
#include <vtkstd/string>
#include <vtkstd/map>

// We need to:
// Format min/max/resolution entries better.
// Add callbacks to take the place of accept button.
// Handle methods with multiple entries.
// Handle special sources (contour, probe, threshold).

/* 
 * This part was generated by ImageConvert from image:
 *    play.png (zlib, base64)
 */
#define image_play_width         16
#define image_play_height        16
#define image_play_pixel_size    4
#define image_play_buffer_length 108

static unsigned char image_play[] = 
  "eNr7//8/w/9BhoFACYgFGbAAIvW7APEZbGaQoP8/NjNI1I9hBhn6UcwgUz/cDAr0g3AoBf"
  "rTKHB/GgXhl0ZB/KVRkH7SyE2/9MQARXskxQ==";

/* 
 * This part was generated by ImageConvert from image:
 *    stop.png (zlib, base64)
 */
#define image_stop_width         16
#define image_stop_height        16
#define image_stop_pixel_size    4
#define image_stop_buffer_length 64

static unsigned char image_stop[] = 
  "eNr7//8/w/9hgoFACYhdCGAlPPrLgfg/AVw+qn/Y6k8D4t0EcNr/YZRnAMXDIoM=";

/* 
 * This part was generated by ImageConvert from image:
 *    loop.png (zlib, base64)
 */
#define image_loop_width         16
#define image_loop_height        16
#define image_loop_pixel_size    4
#define image_loop_buffer_length 212

static unsigned char image_loop[] = 
  "eNrNk1ENwCAMRLGAhVnAAhZmYRZqYRawMAtYwMIszEJHk9tCSMuWfe2S+6H3CLTAzI5/4K"
  "pQTY2jG0jhRUlKMH3g5wd+QUbjffUBLhk8IeMVXmp7kw3G0SVDCp+rV/csyWSDpxc8Gbzc"
  "eXvBSyYp/NX7acBOyMzG/OQOBbPo5VHLg/lfmQN9ivCKtXtvg297VJq3VPre8k/+3QkrPX"
  "VE";

/* 
 * This part was generated by ImageConvert from image:
 *    goto_beginning.png (zlib, base64)
 */
#define image_goto_beginning_width         16
#define image_goto_beginning_height        16
#define image_goto_beginning_pixel_size    4
#define image_goto_beginning_buffer_length 188

static unsigned char image_goto_beginning[] = 
  "eNrN00ENgDAMBdBZmAUsYAELWJiFWcBCPaFlFkq30KQpLesNlpTDz94nwEDEhB8PrX7Z0n"
  "MVJ19p6sQXJ++2TTxbnbPFFy+tzKX1vLaca2v5w7B4dzYj136nOZ37Q8D3fdno4OeHgE9G"
  "h3z/EPC6Q39/CHjZYZ0/UL7SLMa+7OTjPOAP/r0LX11aGw==";

/* 
 * This part was generated by ImageConvert from image:
 *    goto_end.png (zlib, base64)
 */
#define image_goto_end_width         16
#define image_goto_end_height        16
#define image_goto_end_pixel_size    4
#define image_goto_end_buffer_length 184

static unsigned char image_goto_end[] = 
  "eNrNk1sNgDAMRWcBC1jAAhawMAuzgIV6QgsWykbSpCn3bvxBk/vT7Jy9VTXpx6lVapb0rL"
  "Umk74G/gSOexxwIF6Bw/joYHx0eN47erx3RN4cI94cGfRb9he8kPmPmm3AC9l/Y6fB+oWc"
  "v7G98xNy/55lvJB3FlnEo7fbagas9Yv+4O9dh3laGw==";


//===========================================================================
//***************************************************************************
class vtkPVAnimationInterfaceObserver: public vtkCommand
{
public:
  static vtkPVAnimationInterfaceObserver *New() 
    {return new vtkPVAnimationInterfaceObserver;};

  vtkPVAnimationInterfaceObserver()
    {
      this->AnimationInterface = 0;
    }

  virtual void Execute(vtkObject* wdg, unsigned long event,  
                       void* calldata)
    {
      if ( this->AnimationInterface)
        {
        this->AnimationInterface->ExecuteEvent(wdg, event, calldata);
        }
    }

  vtkPVAnimationInterface* AnimationInterface;
};

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

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkPVAnimationInterface);
vtkCxxRevisionMacro(vtkPVAnimationInterface, "1.102.2.1");

vtkCxxSetObjectMacro(vtkPVAnimationInterface,ControlledWidget, vtkPVWidget);

int vtkPVAnimationInterfaceCommand(ClientData cd, Tcl_Interp *interp,
                           int argc, char *argv[]);

//-----------------------------------------------------------------------------
vtkPVAnimationInterface::vtkPVAnimationInterface()
{
  this->Observer = vtkPVAnimationInterfaceObserver::New();
  this->Observer->AnimationInterface = this;
  this->ErrorEventTag = 0;

  this->CommandFunction = vtkPVAnimationInterfaceCommand;

  this->NumberOfFrames = 100;

  this->StopFlag = 0;
  this->InPlay = 0;
  this->Loop = 0;

  this->PVSource = NULL;

  this->View = NULL;
  this->Window = NULL;

  // Animation control
  //
  this->TopFrame = vtkKWFrame::New();

  this->ControlFrame = vtkKWLabeledFrame::New();

  this->ControlButtonFrame = vtkKWWidget::New();

  this->PlayButton = vtkKWPushButton::New();

  this->StopButton = vtkKWPushButton::New();

  this->GoToBeginningButton = vtkKWPushButton::New();

  this->GoToEndButton = vtkKWPushButton::New();

  this->LoopCheckButton = vtkKWCheckButton::New();

  this->TimeFrame = vtkKWWidget::New();

  this->NumberOfFramesEntry = vtkKWLabeledEntry::New();

  this->TimeScale = vtkKWScale::New();
  this->AnimationDelayScale = vtkKWScale::New();
  this->TimeRange = vtkKWRange::New();

  // Action and script editing

  this->ActionFrame = vtkKWLabeledFrame::New();

  this->ScriptCheckButtonFrame = vtkKWWidget::New();

  this->ScriptCheckButton = vtkKWCheckButton::New();

  this->ScriptEditor = vtkKWText::New();

  this->ControlledWidget = NULL;

  // Save button frame
  this->SaveFrame = vtkKWLabeledFrame::New();
  this->SaveButtonFrame = vtkKWWidget::New();
  this->SaveImagesButton = vtkKWPushButton::New();
  this->SaveGeometryButton = vtkKWPushButton::New();
  this->CacheGeometryCheck = vtkKWCheckButton::New();

  this->AnimationEntries = vtkCollection::New();
  this->AnimationEntriesIterator = this->AnimationEntries->NewIterator();
  this->AnimationEntriesFrame = vtkKWLabeledFrame::New();
  this->AddItemButton = vtkKWPushButton::New();
  this->DeleteItemButton = vtkKWPushButton::New();
  this->NewScriptString = 0;
  this->InShowEntryInFrame = 0;

  this->AnimationEntryInformation = vtkKWFrame::New();
  this->AnimationEntriesMenu = vtkKWMenuButton::New();

  this->Dirty = 1;
  this->ScriptAvailable = 0;
  this->UpdatingScript = 0;
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterface::~vtkPVAnimationInterface()
{
  this->Observer->Delete();

  if ( this->TopFrame )
    {
    this->TopFrame->Delete();
    this->TopFrame = 0;
    }
  if (this->ControlFrame)
    {
    this->ControlFrame->Delete();
    this->ControlFrame = NULL;
    }
  if (this->ControlButtonFrame)
    {
    this->ControlButtonFrame->Delete();
    this->ControlButtonFrame = NULL;
    }
  if (this->PlayButton)
    {
    this->PlayButton->Delete();
    this->PlayButton = NULL;
    }
  if (this->StopButton)
    {
    this->StopButton->Delete();
    this->StopButton = NULL;
    }
  if (this->GoToBeginningButton)
    {
    this->GoToBeginningButton->Delete();
    this->GoToBeginningButton = NULL;
    }
  if (this->GoToEndButton)
    {
    this->GoToEndButton->Delete();
    this->GoToEndButton = NULL;
    }
  if (this->LoopCheckButton)
    {
    this->LoopCheckButton->Delete();
    this->LoopCheckButton = NULL;
    }
  if (this->TimeScale)
    {
    this->TimeScale->Delete();
    this->TimeScale = NULL;
    }
  if (this->AnimationDelayScale)
    {
    this->AnimationDelayScale->Delete();
    this->AnimationDelayScale = 0;
    }
  if (this->TimeFrame)
    {
    this->TimeFrame->Delete();
    this->TimeFrame = NULL;
    }
  if (this->NumberOfFramesEntry)
    {
    this->NumberOfFramesEntry->Delete();
    this->NumberOfFramesEntry = NULL;
    }
  if (this->TimeRange)
    {
    this->TimeRange->Delete();
    this->TimeRange = 0;
    }

  if (this->ScriptEditor)
    {
    this->ScriptEditor->Delete();
    this->ScriptEditor = NULL;
    }
  
  if (this->ActionFrame)
    {
    this->ActionFrame->Delete();
    this->ActionFrame = NULL;
    }
  if (this->ScriptCheckButtonFrame)
    {
    this->ScriptCheckButtonFrame->Delete();
    this->ScriptCheckButtonFrame = NULL;
    }
  if (this->ScriptCheckButton)
    {
    this->ScriptCheckButton->Delete();
    this->ScriptCheckButton = NULL;
    }

  this->SaveFrame->Delete();
  this->SaveFrame = NULL;
  this->SaveButtonFrame->Delete();
  this->SaveButtonFrame = NULL;
  this->SaveImagesButton->Delete();
  this->SaveImagesButton = NULL;
  this->SaveGeometryButton->Delete();
  this->SaveGeometryButton = NULL;
  this->CacheGeometryCheck->Delete();
  this->CacheGeometryCheck = NULL;

  if ( this->AnimationEntries )
    {
    this->AnimationEntries->Delete();
    }
  this->AnimationEntries = 0;
  if ( this->AnimationEntriesIterator )
    {
    this->AnimationEntriesIterator->Delete();
    }
  this->AnimationEntriesIterator = 0;
  this->AnimationEntriesFrame->Delete();
  this->AnimationEntriesFrame = 0;
  this->AddItemButton->Delete();
  this->AddItemButton = 0;
  this->DeleteItemButton->Delete();
  this->DeleteItemButton = 0;
  this->AnimationEntryInformation->Delete();
  this->AnimationEntryInformation = 0;
  this->AnimationEntriesMenu->Delete();
  this->AnimationEntriesMenu = 0;

  this->SetControlledWidget(NULL);
  this->SetView(NULL);
  this->SetWindow(NULL);

  this->SetNewScriptString(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Create(vtkKWApplication *app, const char *frameArgs)
{  
  vtkPVApplication *pvApp = vtkPVApplication::SafeDownCast(app);

  if (this->Application)
    {
    vtkErrorMacro("Widget has already been created.");
    return;
    }

  if (pvApp == NULL)
    {
    vtkErrorMacro("Need the subclass vtkPVApplication to create this object.");
    return;
    }

  this->SetApplication(app);

  // Create the frame for this widget.

  this->Script("frame %s %s", this->GetWidgetName(), frameArgs);

  this->TopFrame->SetParent(this);
  this->TopFrame->ScrollableOn();
  this->TopFrame->Create(this->Application, 0);
  this->Script("pack %s -side top -fill both -expand t -anchor center", 
               this->TopFrame->GetWidgetName());

  // Animation Control

  this->ControlFrame->SetParent(this->TopFrame->GetFrame());
  this->ControlFrame->ShowHideFrameOn();
  this->ControlFrame->Create(this->Application, 0);
  this->ControlFrame->SetLabel("Animation Control");

  this->ControlButtonFrame->SetParent(this->ControlFrame->GetFrame());
  this->ControlButtonFrame->Create(this->Application, "frame", "");

  this->Script("pack %s -side top -fill none -expand t -anchor center", 
               this->ControlButtonFrame->GetWidgetName());

  // Animation Control: Play button to start the animation.

  this->PlayButton->SetParent(this->ControlButtonFrame);
  this->PlayButton->Create(this->Application, "");
  this->PlayButton->SetCommand(this, "Play");

  this->PlayButton->SetImageOption(image_play, 
                                   image_play_width, 
                                   image_play_height, 
                                   image_play_pixel_size,
                                   image_play_buffer_length);
  
  // Animation Control: Stop button to stop the animation.

  this->StopButton->SetParent(this->ControlButtonFrame);
  this->StopButton->Create(this->Application, "");
  this->StopButton->SetCommand(this, "Stop");
  
  this->StopButton->SetImageOption(image_stop, 
                                   image_stop_width, 
                                   image_stop_height, 
                                   image_stop_pixel_size,
                                   image_stop_buffer_length);

  // Animation Control: "go to beginning" button.

  this->GoToBeginningButton->SetParent(this->ControlButtonFrame);
  this->GoToBeginningButton->Create(this->Application, "");
  this->GoToBeginningButton->SetCommand(this, "GoToBeginning");

  this->GoToBeginningButton->SetImageOption(
    image_goto_beginning, 
    image_goto_beginning_width, 
    image_goto_beginning_height, 
    image_goto_beginning_pixel_size,
    image_goto_beginning_buffer_length);

  // Animation Control: "go to beginning" button.

  this->GoToEndButton->SetParent(this->ControlButtonFrame);
  this->GoToEndButton->Create(this->Application, "");
  this->GoToEndButton->SetCommand(this, "GoToEnd");

  this->GoToEndButton->SetImageOption(image_goto_end, 
                                      image_goto_end_width, 
                                      image_goto_end_height, 
                                      image_goto_end_pixel_size,
                                      image_goto_end_buffer_length);

  //  Animation Control: loop button to loop the animation.

  this->LoopCheckButton->SetParent(this->ControlButtonFrame);
  this->LoopCheckButton->Create(this->Application, "");
  this->LoopCheckButton->SetCommand(this, "LoopCheckButtonCallback");
  this->LoopCheckButton->SetState(this->Loop ? 1 : 0);
  this->LoopCheckButton->SetIndicator(0);

  this->LoopCheckButton->SetImageOption(image_loop, 
                                        image_loop_width, 
                                        image_loop_height, 
                                        image_loop_pixel_size,
                                        image_loop_buffer_length);

  //  Animation Control: pack the transport buttons

  this->Script("pack %s %s %s %s %s -side left -fill both -padx 1", 
               this->GoToBeginningButton->GetWidgetName(), 
               this->PlayButton->GetWidgetName(), 
               this->StopButton->GetWidgetName(),
               this->GoToEndButton->GetWidgetName(), 
               this->LoopCheckButton->GetWidgetName());

  // Animation Control: Time scale

  this->TimeScale->SetParent(this->ControlFrame->GetFrame());
  this->TimeScale->Create(this->Application, "");
  this->TimeScale->DisplayEntry();
  this->TimeScale->DisplayEntryAndLabelOnTopOff();
  this->TimeScale->DisplayLabel("Frame:");
  this->TimeScale->SetEndCommand(this, "TimeScaleCallback");
  this->TimeScale->SetEntryCommand(this, "TimeScaleCallback");

  this->Script("pack %s -side top -expand t -fill x", 
               this->TimeScale->GetWidgetName());

  this->TimeFrame->SetParent(this->ControlFrame->GetFrame());
  this->TimeFrame->Create(this->Application, "frame", "");

  this->Script("pack %s -side top -expand t -fill x", 
               this->TimeFrame->GetWidgetName());

  this->NumberOfFramesEntry->SetParent(this->TimeFrame);
  this->NumberOfFramesEntry->Create(this->Application);
  this->NumberOfFramesEntry->GetEntry()->SetWidth(6);
  this->NumberOfFramesEntry->SetLabel("Number Of Frames:");
  this->NumberOfFramesEntry->GetEntry()->SetValue(this->NumberOfFrames);


  this->Script("bind %s <KeyPress-Return> {%s NumberOfFramesEntryCallback}",
               this->NumberOfFramesEntry->GetEntry()->GetWidgetName(),
               this->GetTclName());

  this->Script("bind %s <FocusOut> {%s NumberOfFramesEntryCallback}",
               this->NumberOfFramesEntry->GetEntry()->GetWidgetName(),
               this->GetTclName());

  this->Script("pack %s -side left -expand t -fill x", 
               this->NumberOfFramesEntry->GetWidgetName());

  this->TimeRange->SetParent(this->ControlFrame->GetFrame());
  this->TimeRange->ShowEntriesOn();
  this->TimeRange->Create(this->Application, 0);

  //this->Script("pack %s -side top -expand t -fill x", 
  //             this->TimeRange->GetWidgetName());

  this->AnimationDelayScale->SetParent(this->ControlFrame->GetFrame());
  this->AnimationDelayScale->Create(this->Application, "");
  this->AnimationDelayScale->DisplayEntry();
  this->AnimationDelayScale->DisplayEntryAndLabelOnTopOff();
  this->AnimationDelayScale->DisplayLabel("Delay:");
  this->AnimationDelayScale->SetRange(0, 500);

  this->Script("pack %s -side top -expand t -fill x", 
               this->AnimationDelayScale->GetWidgetName());
  // New Interface ----------------------------------------------------
  this->AnimationEntriesFrame->SetParent(this->TopFrame->GetFrame());
  this->AnimationEntriesFrame->ShowHideFrameOn();
  this->AnimationEntriesFrame->Create(this->Application, 0);
  this->AnimationEntriesFrame->SetLabel("Actions");
  this->AnimationEntryInformation->SetParent(this->AnimationEntriesFrame->GetFrame());
  this->AnimationEntryInformation->Create(this->Application, 0);
  this->AnimationEntriesMenu->SetParent(this->AnimationEntriesFrame->GetFrame());
  this->AnimationEntriesMenu->Create(this->Application, 0);
  vtkKWFrame* frame = vtkKWFrame::New();
  frame->SetParent(this->AnimationEntriesFrame->GetFrame());
  frame->Create(this->Application, 0);
  this->AddItemButton->SetParent(frame->GetFrame());
  this->AddItemButton->Create(this->Application, 0);
  this->AddItemButton->SetLabel("Add Action");
  this->DeleteItemButton->SetParent(frame->GetFrame());
  this->DeleteItemButton->Create(this->Application, 0);
  this->DeleteItemButton->SetLabel("Delete Action");
  this->Script("pack %s %s %s -side top -fill both -expand 1", 
    this->AnimationEntriesMenu->GetWidgetName(),
    this->AnimationEntryInformation->GetWidgetName(),
    frame->GetWidgetName());


  vtkKWFrame* fr = vtkKWFrame::New();
  fr->SetParent(frame->GetFrame());
  fr->Create(this->Application, 0);
  this->Script("pack %s -side left -fill both -expand 0", 
    this->AddItemButton->GetWidgetName());
  this->Script("pack %s -side left -fill both -expand 1", 
    fr->GetWidgetName());
  this->Script("pack %s -side left -fill both -expand 0", 
    this->DeleteItemButton->GetWidgetName());
  fr->Delete();
  //this->Script("%s configure -bg red", this->AnimationEntryInformation->GetWidgetName());
  frame->Delete();
  this->AddItemButton->SetCommand(this, "AddEmptySourceItem");

  // New Interface ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  // Action frame

  this->ActionFrame->SetParent(this->TopFrame->GetFrame());
  this->ActionFrame->ShowHideFrameOn();
  this->ActionFrame->Create(this->Application, 0);
  this->ActionFrame->SetLabel("Script");

  // Action frame: Script check button and script editor

  this->ScriptCheckButtonFrame->SetParent(this->ActionFrame->GetFrame());
  this->ScriptCheckButtonFrame->Create(this->Application, "frame", "");


  //this->Script("pack %s -side top -expand t -fill x", 
  //             this->ScriptCheckButtonFrame->GetWidgetName());

  this->ScriptCheckButton->SetParent(this->ScriptCheckButtonFrame);
  this->ScriptCheckButton->Create(this->Application, "-text {Script Editor}");
  this->ScriptCheckButton->SetCommand(this, "ScriptCheckButtonCallback");

  this->Script("pack %s -side left -expand f", 
               this->ScriptCheckButton->GetWidgetName());

  this->ScriptEditor->SetParent(this->ActionFrame->GetFrame());
  this->ScriptEditor->Create(this->Application, "-relief sunken -bd 2");

  this->Script("bind %s <FocusOut> {%s ScriptEditorCallback}",
    this->ScriptEditor->GetWidgetName(), this->GetTclName());
  this->Script("bind %s <KeyPress-Return> {%s ScriptEditorCallback}",
    this->ScriptEditor->GetWidgetName(), this->GetTclName());

  // Save frame stuff
  this->SaveFrame->SetParent(this->TopFrame->GetFrame());
  this->SaveFrame->ShowHideFrameOn();
  this->SaveFrame->SetLabel("Save");
  this->SaveFrame->Create(this->Application, 0);
  this->SaveButtonFrame->SetParent(this->SaveFrame->GetFrame());
  this->SaveButtonFrame->Create(this->Application, "frame", 0);
  this->SaveImagesButton->SetParent(this->SaveButtonFrame);
  this->SaveImagesButton->Create(this->Application, 0);
  this->SaveImagesButton->SetLabel("Save Images");
  this->SaveImagesButton->SetCommand(this, "SaveImagesCallback");
  this->SaveGeometryButton->SetParent(this->SaveButtonFrame);
  this->SaveGeometryButton->Create(this->Application, 0);
  this->SaveGeometryButton->SetLabel("Save Geometry");
  this->SaveGeometryButton->SetCommand(this, "SaveGeometryCallback");
  this->Script("pack %s %s -side left -expand t -fill x -padx 2 -pady 2", 
               this->SaveImagesButton->GetWidgetName(),
               this->SaveGeometryButton->GetWidgetName());

  this->CacheGeometryCheck->SetParent(this->SaveFrame->GetFrame());
  this->CacheGeometryCheck->Create(this->Application, 0);
  this->CacheGeometryCheck->SetText("Cache Geometry");
  this->CacheGeometryCheck->SetCommand(this, "CacheGeometryCheckCallback");

  this->Script("pack %s %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->SaveButtonFrame->GetWidgetName(),
               this->CacheGeometryCheck->GetWidgetName());

  // Pack frames

  this->Script("pack %s %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->ControlFrame->GetWidgetName(),
               this->AnimationEntriesFrame->GetWidgetName());

  //this->Script("pack %s -side top -expand t -fill x -padx 2 -pady 2", 
  //             this->ActionFrame->GetWidgetName());

  this->Script("pack %s -side top -expand t -fill x -padx 2 -pady 2", 
               this->SaveFrame->GetWidgetName());

  this->TimeRange->SetWholeRange(0, this->NumberOfFrames-1);
  this->TimeRange->SetRange(0, this->NumberOfFrames-1);
  this->UpdateInterface();

  this->AddEmptySourceItem();

  this->PlayButton->SetBalloonHelpString("Play animation.");
  this->StopButton->SetBalloonHelpString("Stop animation.");
  this->GoToBeginningButton->SetBalloonHelpString(
    "Go to the beginning of the animation.");
  this->GoToEndButton->SetBalloonHelpString(
    "Go to the end of the animation.");
  this->LoopCheckButton->SetBalloonHelpString(
    "Enable/Disable animation loop.");
  this->TimeScale->SetBalloonHelpString(
    "Current frame of the animation.");
  this->NumberOfFramesEntry->SetBalloonHelpString(
    "Total number of frames for the animation.");
  this->AnimationDelayScale->SetBalloonHelpString(
    "Set the delay between each frame (in ms). This delay does not include "
    "the computation and rendering times.");
  this->AnimationEntriesMenu->SetBalloonHelpString(
    "Select an animation action to edit.");
  this->AddItemButton->SetBalloonHelpString(
    "Add new action to the animation.");
  this->DeleteItemButton->SetBalloonHelpString(
    "Delete current action from the animation.");
  this->ScriptCheckButtonFrame->SetBalloonHelpString(
    "Open/Close the editor for manually editing the action Tcl script.");
  this->SaveImagesButton->SetBalloonHelpString(
    "Save each animation frame as an image.");
  this->SaveGeometryButton->SetBalloonHelpString(
    "Save geometry from each frame. This will create a series of .vtp files.");
  this->CacheGeometryCheck->SetBalloonHelpString(
    "Cache geometry when doing animation. This will "
    "speedup animation after the initial run at the cost "
    "of memory.");


}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrepareAnimationInterface(vtkPVWindow* win)
{
  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    this->UpdateSourceMenu(cc);
    }
  (void)win;
  // Try to find a good default value for the source.
  /*
  if (this->AnimationInterface->GetPVSource() == NULL)
    {
    vtkPVSource *pvs = this->GetCurrentPVSource();
    if (pvs == NULL && this->GetSourceList("Sources")->GetNumberOfItems() > 0)
      {
      pvs = (vtkPVSource*)this->GetSourceList("Sources")->GetItemAsObject(0);
      }
    this->AnimationInterface->SetPVSource(pvs);
    }
*/
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateInterface()
{
  if ( !this->AnimationEntries )
    {
    return;
    }
  if (this->PlayButton && this->PlayButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->PlayButton->EnabledOff();
      }
    else
      {
      this->PlayButton->EnabledOn();
      }
    }

  if (this->StopButton && this->StopButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->StopButton->EnabledOn();
      }
    else
      {
      this->StopButton->EnabledOff();
      }
    }

  if (this->GoToBeginningButton && this->GoToBeginningButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->GoToBeginningButton->EnabledOff();
      }
    else
      {
      this->GoToBeginningButton->EnabledOn();
      }
    }

  if (this->GoToEndButton && this->GoToEndButton->IsCreated())
    {
    if (this->InPlay)
      {
      this->GoToEndButton->EnabledOff();
      }
    else
      {
      this->GoToEndButton->EnabledOn();
      }
    }

  if (this->NumberOfFramesEntry && this->NumberOfFramesEntry->IsCreated())
    {
    this->NumberOfFramesEntry->GetEntry()->SetValue(this->NumberOfFrames);
    if (this->InPlay)
      {
      this->NumberOfFramesEntry->EnabledOff();
      }
    else
      {
      this->NumberOfFramesEntry->EnabledOn();
      }
    }

  if (this->TimeScale && this->TimeScale->IsCreated())
    {
    this->TimeScale->SetRange(0, this->NumberOfFrames-1);
    this->TimeScale->SetResolution(1);
    this->TimeRange->SetWholeRange(0, this->NumberOfFrames-1);
    this->TimeRange->SetResolution(1);
    if (this->InPlay)
      {
      // We do not disable it so that the slider will still be updated
      // during "Play"
      this->TimeScale->UnBind();
      }
    else
      {
      this->TimeScale->Bind();
      }
    }

  if (this->LoopCheckButton && this->LoopCheckButton->IsCreated())
    {
    this->LoopCheckButton->SetState(this->Loop);
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetNumberOfFrames(int t)
{
  if (t==this->NumberOfFrames)
    {
    return;
    }
  //cout << "Set NumberOfFrames: " << t << endl;
  this->NumberOfFrames= t;
  this->NumberOfFramesEntry->GetEntry()->SetValue(t);
  float range[2];
  this->TimeRange->SetWholeRange(0, t);
  this->TimeRange->GetRange(range);
  this->TimeRange->SetRange(range[0], t);
  this->TimeScale->GetRange(range);
  this->TimeScale->SetRange(0, t-1);
  vtkPVApplication* app = this->GetPVApplication();
  if (app)
    {
    app->GetRenderModule()->InvalidateAllGeometries();
    }
  if ( !this->IsCreated() )
    {
    return;
    }
  this->AddTraceEntry("$kw(%s) SetNumberOfFrames %d", this->GetTclName(), t);

}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::NumberOfFramesEntryCallback()
{
  //cout << "NumberOfFramesEntryCallback" << endl;
  this->SetNumberOfFrames(static_cast<int>(this->NumberOfFramesEntry->GetEntry()->GetValueAsFloat()));
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::EntryCallback()
{
  this->NumberOfFramesEntryCallback();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetLoop(int v)
{
  if (this->Loop == v)
    {
    return;
    }
  this->Loop = v;
  this->Modified();

  this->AddTraceEntry("$kw(%s) SetLoop %d",
                      this->GetTclName(), this->GetLoop());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::LoopCheckButtonCallback()
{
  this->SetLoop(this->LoopCheckButton->GetState());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ScriptCheckButtonCallback()
{
  if (this->ScriptCheckButton->GetState())
    {
    this->AddTraceEntry("$kw(%s) SetScriptCheckButtonState 1", 
                        this->GetTclName());
    this->Script("pack %s -side top -expand yes -fill x -padx 2",
                 this->ScriptEditor->GetWidgetName());
    }
  else
    {
    this->AddTraceEntry("$kw(%s) SetScriptCheckButtonState 0", 
                        this->GetTclName());
    this->Script("pack forget %s", 
                 this->ScriptEditor->GetWidgetName());
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetScriptCheckButtonState(int val)
{
  if (this->ScriptCheckButton->GetState() == val)
    {
    return;
    }

  this->ScriptCheckButton->SetState(val);
  this->ScriptCheckButtonCallback();
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetCurrentTime()
{
  return static_cast<int>(this->TimeScale->GetValue());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetCurrentTime(int time)
{
  this->TimeScale->SetValue(time);

  vtkPVApplication *pvApp = vtkPVApplication::SafeDownCast(this->Application);
  if (pvApp)
    {
    float ctime = static_cast<float>(this->GetCurrentTime()) / 
      static_cast<float>(this->NumberOfFrames-1);

    this->Script("set globalPVTime %g", ctime);
    
    if (this->ControlledWidget)
      {
      this->ControlledWidget->ModifiedCallback();
      this->ControlledWidget->Reset();
      }
    
    vtkCollectionIterator* it = this->AnimationEntriesIterator;
    for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
      {
      vtkPVAnimationInterfaceEntry* entry
        = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
      vtkPVWidgetProperty *prop = entry->GetCurrentProperty();
      if (prop)
        {
        this->Script(entry->GetTimeEquation());
        prop->SetAnimationTime(vtkKWObject::GetFloatResult(pvApp));
        prop->GetWidget()->ModifiedCallback();
        }
      if ( entry->GetPVSource() )
        {
        entry->GetPVSource()->UpdateVTKSourceParameters();
        }
      }
      
    // Generate the cache, or use previous cache.
    if (this->GetCacheGeometry())
      {
      if (pvApp)
        {
        pvApp->GetRenderModule()->CacheUpdate(time, this->NumberOfFrames);
        }
      if (this->View)
        {
        this->View->EventuallyRender();
        }
      // This is a hack. Calling prop->GetWidget()->ModifiedCallback() has
      // the side effect of making the Accept button red. Here is we
      // set to white again. Ideally, we should only work with properties.
      // TODO: Fix this.
      vtkCollectionIterator* it = this->AnimationEntriesIterator;
      for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
        {
        vtkPVAnimationInterfaceEntry* entry
          = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
        vtkPVWidgetProperty *prop = entry->GetCurrentProperty();
        if ( entry->GetPVSource() )
          {
          entry->GetPVSource()->SetAcceptButtonColorToWhite();
          }
        }
      }
    else
      {
      for (it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem())
        {
        vtkPVAnimationInterfaceEntry *entry =
          vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
        if (entry->GetPVSource())
          {
          entry->GetPVSource()->AcceptCallback();
          vtkKWMenu *menu = entry->GetPVSource()->GetPVWindow()->GetMenuView();
          menu->CheckRadioButton(menu, "Radio", VTK_PV_ANIMATION_MENU_INDEX);
          }
        }
      }

    this->AddTraceEntry("$kw(%s) SetCurrentTime %d", 
                        this->GetTclName(), this->GetCurrentTime());

    
    // Allow the application GUI to be refreshed (ex: in a trace file)

    this->Script("update");
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::TimeScaleCallback()
{
  this->SetCurrentTime(static_cast<int>(this->TimeScale->GetValue()));
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Play()
{  
  // If playing, do not do anything

  if (this->InPlay)
    {
    return;
    }
  this->InPlay = 1;

  // Make sure we have the up to date entries for end and step.

  this->EntryCallback();

  // Make sure script is up to date
  
  this->UpdateNewScript();

  // Update the buttons according to the play status

  this->UpdateInterface();

  // We need a different end test if the step is negative.

  int t;

  // NOTE: the object registers itself for the following reason. The call
  // to "update" in the loop below (through SetCurrentTime()) enables the
  // user to exit the application. 
  // In that case all objects, including this one, are deleted, and this 
  // object's ivars will be trashed, resulting in a crash.
  // To prevent this object from being deleted, it registers itself before
  // the loop, and unregisters itself after the loop. If objects deletion
  // were scheduled, they will happen When UnRegister() is called.
  // Of course, the loop has to end, so the parent of this object should
  // make a call to Stop() before deleting it.

  this->Register(this);

  int cc = 0;
  this->StopFlag = 0;
  do
    {
    //cout << "T: " << t << endl;
    t = this->GetCurrentTime();
    if (t >= this->GetGlobalEnd())
      {
      this->SetCurrentTime(this->GetGlobalStart());
      t = this->GetCurrentTime();
      }
    while (t < this->GetGlobalEnd() && !this->StopFlag)
      {
      ++t;
      if (t > this->GetGlobalEnd())
        {
        t = this->GetGlobalEnd();
        }
      this->SetCurrentTime(t);
      // The stop button can be used here because SetCurrentTime()
      // makes a call to "update"
      int delay = static_cast<int>(this->AnimationDelayScale->GetValue());
      Tcl_Sleep(delay);
      cc ++;
      }
    } while (this->Loop && !this->StopFlag);

  this->InPlay = 0;
  this->StopFlag = 0;
  this->UpdateInterface();

  this->UnRegister(this);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::Stop()
{  
  this->StopFlag = 1;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::GoToBeginning()
{  
  this->SetCurrentTime(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::GoToEnd()
{  
  this->SetCurrentTime(this->GetNumberOfFrames()-1);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateSourceMenu(int idx)
{
  char methodAndArgString[1024];
  int sourceValid = 0;

  vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(idx);

  // Remove all previous items form the menu.
  vtkKWMenu* menu = entry->GetSourceMenuButton()->GetMenu();
  menu->DeleteAllMenuItems();

  if (this->Window == NULL)
    {
    return;
    }

  // Update the selection menu.
  vtkPVSourceCollection* col = this->Window->GetSourceList("Sources");
  if (col)
    {
    vtkPVSource *source;
    col->InitTraversal();
    while ( (source = col->GetNextPVSource()) )
      {
      sprintf(methodAndArgString, "SetPVSource %s", source->GetTclName());
      menu->AddCommand(source->GetName(), entry, methodAndArgString);
      if (entry->GetPVSource() == source)
        {
        sourceValid = 1;
        }
      }
    }

  // The source may have been deleted. If so, then set our source to NULL.
  if ( ! sourceValid)
    {
    entry->SetPVSource(0);
    this->Dirty = 1;
    }
}

//-----------------------------------------------------------------------------
const char* vtkPVAnimationInterface::GetScript()
{
  return this->ScriptEditor->GetValue();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetWindow(vtkPVWindow *window)
{
  if ( this->Window == window )
    {
    return;
    }
  if ( this->Window )
    {
    this->Window->RemoveObserver(this->ErrorEventTag);
    }
  this->Window = window;
  if ( this->Window )
    {
    this->ErrorEventTag = this->Window->AddObserver(vtkKWEvent::ErrorMessageEvent, this->Observer);
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetView(vtkPVRenderView *renderView)
{
  this->View = renderView;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveImagesCallback()
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  vtkKWLoadSaveDialog* saveDialog = pm->NewLoadSaveDialog();
  this->GetWindow()->RetrieveLastPath(saveDialog, "SaveAnimationFile");
  saveDialog->SetParent(this);
  saveDialog->SaveDialogOn();
  saveDialog->Create(this->Application, 0);
  saveDialog->SetTitle("Save Animation Images");
  saveDialog->SetDefaultExtension(".jpg");
  saveDialog->SetFileTypes("{{jpeg} {.jpg}} {{tiff} {.tif}} {{Portable Network Graphics} {.png}}");

  if ( saveDialog->Invoke() &&
       strlen(saveDialog->GetFileName())>0 )
    {
    this->GetWindow()->SaveLastPath(saveDialog, "SaveAnimationFile");
    const char* filename = saveDialog->GetFileName();  

    // Split into root and extension.
    char* fileRoot;
    char* ptr;
    char* ext = NULL;
    fileRoot = new char[strlen(filename)+1];
    strcpy(fileRoot, filename);
    // Find extension (last .)
    ptr = fileRoot;
    while (*ptr != '\0')
      {
      if (*ptr == '.')
        {
        ext = ptr;
        }
      ++ptr;
      }
    if (ext == NULL)
      {
      vtkErrorMacro(<< "Could not find extension in " << filename);
      delete [] fileRoot;
      fileRoot = NULL;
      saveDialog->Delete();
      saveDialog = NULL;
      return;
      }
    // Separate the root from the extension.
    *ext = '\0';
    ++ext;

    this->SaveImages(fileRoot, ext);
    delete [] fileRoot;
    fileRoot = NULL;
    ext = NULL;
    }

  saveDialog->Delete();
  saveDialog = NULL;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveImages(const char* fileRoot, 
                                         const char* ext) 
{
  vtkWindowToImageFilter* winToImage;
  vtkImageWriter* writer;
  char *fileName;
  int fileCount;
  int t;

  winToImage = vtkWindowToImageFilter::New();
  winToImage->SetInput(this->View->GetRenderWindow());
  if (strcmp(ext,"jpg") == 0)
    {
    writer = vtkJPEGWriter::New();
    }
  else if (strcmp(ext,"tif") == 0)
    {
    writer = vtkTIFFWriter::New();
    }
  else if (strcmp(ext,"png") == 0)
    {
    writer = vtkPNGWriter::New();
    }
  else
    {
    vtkErrorMacro("Unknown extension " << ext << ", try: jpg, tif or png.");
    return;
    }
  writer->SetInput(winToImage->GetOutput());
  fileName = new char[strlen(fileRoot) + strlen(ext) + 25];      

  // Loop through all of the time steps.
  t = this->GetGlobalStart();
  fileCount = 0;
  
  int i, success = 1;
  
  while (t <= this->GetGlobalEnd())
    {
    this->SetCurrentTime(t);
    this->View->EventuallyRender();
    this->Script("update");

    // Create a file name for this image.
    sprintf(fileName, "%s%04d.%s", fileRoot, fileCount, ext);
    writer->SetFileName(fileName);
    winToImage->Modified();
    writer->Write();
    if (writer->GetErrorCode() == vtkErrorCode::OutOfDiskSpaceError)
      {
      for (i = 0; i < fileCount; i++)
        {
        sprintf(fileName, "%s%04d.%s", fileRoot, i, ext);
        unlink(fileName);
        }
      success = 0;
      break;
      }
    ++fileCount;
    ++t;
    }

  winToImage->Delete();
  winToImage = NULL;
  writer->Delete();
  writer = NULL;
  delete [] fileName;
  fileName = NULL;
  
  if (!success)
    {
    vtkKWMessageDialog::PopupMessage(
      this->Application, this->Window, "Write Error",
      "There is insufficient disk space to save the images for this "
      "animation. The file(s) already written will be deleted.");
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveGeometryCallback()
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  int numPartitions = pm->GetNumberOfPartitions();
  
  vtkKWLoadSaveDialog* saveDialog = pm->NewLoadSaveDialog();
  this->GetWindow()->RetrieveLastPath(saveDialog, "SaveGeometryFile");
  saveDialog->SetParent(this);
  saveDialog->SaveDialogOn();
  saveDialog->Create(this->Application, 0);
  saveDialog->SetTitle("Save Animation Geometry");
  saveDialog->SetDefaultExtension(".pvd");
  saveDialog->SetFileTypes("{{ParaView Data Files} {.pvd}}");
  if(saveDialog->Invoke() && (strlen(saveDialog->GetFileName()) > 0))
    {
    this->GetWindow()->SaveLastPath(saveDialog, "SaveGeometryFile");
    this->SaveGeometry(saveDialog->GetFileName(), numPartitions);
    }

  saveDialog->Delete();
  saveDialog = NULL;
}


//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveGeometry(const char* fileName, 
                                           int numPartitions) 
{
  vtkPVProcessModule* pm = this->GetPVApplication()->GetProcessModule();
  vtkPVSourceCollection* sources = this->GetWindow()->GetSourceList("Sources");
  
  // Create the animation writer pipeline.
  vtkClientServerID pvAnimWriterID = pm->NewStreamObject("vtkXMLPVAnimationWriter");
  pm->GetStream() << vtkClientServerStream::Invoke 
                  << pvAnimWriterID
                  << "SetFileName"
                  << fileName
                  << vtkClientServerStream::End;
  pm->GetStream() << vtkClientServerStream::Invoke 
                  << pvAnimWriterID
                  << "SetNumberOfPieces"
                  << numPartitions
                  << vtkClientServerStream::End;
  pm->GetStream() << vtkClientServerStream::Invoke 
                  << pm->GetProcessModuleID()
                  << "GetPartitionId"
                  << vtkClientServerStream::End;
  pm->GetStream() << vtkClientServerStream::Invoke 
                  << pvAnimWriterID
                  << "SetPiece"
                  << vtkClientServerStream::LastResult
                  << vtkClientServerStream::End;
  
  vtkstd::vector<vtkClientServerID> arrays;
  if(numPartitions > 1)
    {
    vtkPVSource* source;
    sources->InitTraversal();
    while((source = sources->GetNextPVSource()))
      {
      if(source->GetVisibility())
        {
        const char* sourceName = source->GetName();
        int numParts = source->GetNumberOfParts();
        for(int partIdx = 0; partIdx < numParts; ++partIdx)
          {
          vtkPVPart* part = source->GetPart(partIdx);
          vtkClientServerID animCompleteArraysID = pm->NewStreamObject("vtkCompleteArrays");
          arrays.push_back(animCompleteArraysID);
          pm->GetStream() << vtkClientServerStream::Invoke << part->GetGeometryID()
                          << "GetOutput"
                          << vtkClientServerStream::End;
          pm->GetStream() << vtkClientServerStream::Invoke << animCompleteArraysID
                          << "SetInput"
                          << vtkClientServerStream::LastResult
                          << vtkClientServerStream::End;
          pm->GetStream() << vtkClientServerStream::Invoke 
                          << animCompleteArraysID
                          << "GetOutput"
                          << vtkClientServerStream::End;
          pm->GetStream() << vtkClientServerStream::Invoke 
                          << pvAnimWriterID
                          << "AddInput"
                          << vtkClientServerStream::LastResult
                          << sourceName
                          << vtkClientServerStream::End;
          }
        }
      }
    
    // Only write the animation file once on each disk.
    vtkClientServerID pvAnimHelperID = pm->NewStreamObject("vtkPVSummaryHelper");
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimHelperID 
                    << "SetWriter"
                    << pvAnimWriterID
                    << vtkClientServerStream::End;
    pm->GetStream() << vtkClientServerStream::Invoke << pm->GetApplicationID() 
                    << "GetController"
                    << vtkClientServerStream::End;
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimHelperID
                    << "SetController" 
                    << vtkClientServerStream::LastResult
                    << vtkClientServerStream::End;
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimHelperID
                    << "SynchronizeSummaryFiles" 
                    << vtkClientServerStream::End;
    pm->DeleteStreamObject(pvAnimHelperID);
    }
  else
    {
    vtkPVSource* source;
    sources->InitTraversal();
    while((source = sources->GetNextPVSource()))
      {
      if(source->GetVisibility())
        {
        int numParts = source->GetNumberOfParts();
        for(int partIdx = 0; partIdx < numParts; ++partIdx)
          {
          vtkPVPart* part = source->GetPart(partIdx);
          pm->GetStream() << vtkClientServerStream::Invoke << part->GetGeometryID()
                          << "GetOutput"
                          << vtkClientServerStream::End;
          pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                          << "AddInput"
                          << vtkClientServerStream::LastResult
                          << vtkClientServerStream::End;
          }
        }
      }
    }
  
  // Start the animation.
  pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                  << "Start"
                  << vtkClientServerStream::End;
  pm->SendStreamToServer();
  int retVal, success = 1;
  vtkPVApplication *pvApp = this->GetPVApplication();
  
  // Loop through all of the time steps.
  for(int t = this->GetGlobalStart(); t <= this->GetGlobalEnd(); ++t)
    {
    // Update the animation to this time step.
    this->SetCurrentTime(t);
    this->View->EventuallyRender();
    this->Script("update");
    
    // Write this time step. 
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                    << "WriteTime" << t
                    << vtkClientServerStream::End;
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                    << "GetErrorCode" 
                    << vtkClientServerStream::End;
    pm->SendStreamToServer();
    pm->GetLastServerResult().GetArgument(0, 0, &retVal);
    if (retVal == vtkErrorCode::OutOfDiskSpaceError)
      {
      success = 0;
      vtkKWMessageDialog::PopupMessage(
        pvApp, pvApp->GetMainWindow(),
        "Write Error", "There is insufficient disk space to save the geometry "
        "for this animation. The file(s) already written will be deleted.");
      break;
      }
    }
  
  if (success)
    {
    // Finish the animation. 
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                    << "Finish" 
                    << vtkClientServerStream::End;
    pm->GetStream() << vtkClientServerStream::Invoke << pvAnimWriterID
                    << "GetErrorCode" 
                    << vtkClientServerStream::End;
    pm->SendStreamToServer();
    pm->GetLastServerResult().GetArgument(0, 0, &retVal);
    if (retVal == vtkErrorCode::OutOfDiskSpaceError)
      {
      vtkKWMessageDialog::PopupMessage(
        pvApp, pvApp->GetMainWindow(),
        "Write Error", "There is insufficient disk space to save the geometry "
        "for this animation. The file(s) already written will be deleted.");
      }
    }
  pm->DeleteStreamObject(pvAnimWriterID);
  pm->SendStreamToServer();
  
  if(numPartitions > 1)
    {
    sources->InitTraversal();
    for(vtkstd::vector<vtkClientServerID>::iterator i = arrays.begin();
        i != arrays.end(); ++i)
      {
      pm->DeleteStreamObject(*i);
      }
    pm->SendStreamToServer();
    }  
}


//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::IsAnimationValid()
{
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    if ( entry->IsActionValid() )
      {
      return 1;
      }
    }
  return 0;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveInBatchScript(ofstream *file, 
                                                const char* imageFileName,
                                                const char* geometryFileName)
{
  char *root;
  char *ext;
  char *ptr;
  int t;
  int timeIdx;
  char countStr[10];

  // Loop through all of the time steps.
  t = this->GetGlobalStart();
  timeIdx = 0;
  while (t < this->GetGlobalEnd())
    {
    float ctime = static_cast<float>(t) / 
      static_cast<float>(this->NumberOfFrames-1);

    *file << "set globalPVTime " << ctime << "\n";
    *file << this->GetScript() << endl;
    sprintf(countStr, "%05d", (int)(timeIdx));
    if (imageFileName)
      {
      *file << "RenWin1 Render\n";
      *file << "compManager Composite\n";
      *file << "if {$myProcId == 0} {\n";  
      root = new char[strlen(imageFileName)+1];
      strcpy(root, imageFileName);
      ext = NULL;
      ptr = root;
      while(*ptr)
        { // Find the extenstion
        if (*ptr == '.')
          {
          ext = ptr;
          }
        ++ptr;
        }
      if (ext)
        {
        *ext = '\0';
        ++ext;
        *file << "\t" << "ImageWriter SetFileName {" << root << countStr
              << "." << ext << "}\n";
        }
      else
        {
        *file << "\t" << "ImageWriter SetFileName {" << root << countStr << "}\n";
        }
      *file << "\t" << "ImageWriter Write\n";
      *file << "}\n";
      delete [] root;
      }
    if (geometryFileName)
      {
      this->GetWindow()->SaveGeometryInBatchFile(file, 
                                                 geometryFileName,
                                                 timeIdx);
      }
    *file << endl;
    ++timeIdx;
    ++t;
    }
}


//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::CacheGeometryCheckCallback()
{
  if ( ! this->GetCacheGeometry())
    {
    vtkPVApplication* app = this->GetPVApplication();
    if (app)
      {
      app->GetRenderModule()->InvalidateAllGeometries();
      }
    }
  this->AddTraceEntry("$kw(%s) SetCacheGeometry %d",
                      this->GetTclName(), this->GetCacheGeometry());
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetCacheGeometry()
{
  return this->CacheGeometryCheck->GetState();
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::SetCacheGeometry(int flag)
{
  this->CacheGeometryCheck->SetState(flag);
  this->CacheGeometryCheckCallback();
}

//-----------------------------------------------------------------------------
vtkPVApplication* vtkPVAnimationInterface::GetPVApplication()
{
  return vtkPVApplication::SafeDownCast(this->Application);
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterfaceEntry* vtkPVAnimationInterface::AddEmptySourceItem()
{
  vtkPVAnimationInterfaceEntry* entry = vtkPVAnimationInterfaceEntry::New();
  entry->SetApplication(this->Application);
  entry->SetParent(this);
  this->AnimationEntries->AddItem(entry);
  entry->SetParent(this->AnimationEntryInformation->GetFrame());
  entry->SetTraceReferenceObject(this);
  int idx = this->AnimationEntries->GetNumberOfItems()-1;
  entry->SetCurrentIndex(idx);
  entry->Create(this->GetPVApplication(), 0);
  this->UpdateEntries();
  this->ShowEntryInFrame(idx);
  this->AddTraceEntry("$kw(%s) AddEmptySourceItem", this->GetTclName());
  entry->Delete();
  this->Dirty = 1;
  return entry;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::DeleteSourceItem(int item)
{
  this->AnimationEntries->InitTraversal();
  if ( item < 0 && item >= this->AnimationEntries->GetNumberOfItems() )
    {
    vtkErrorMacro(<< "Item " << item << " is not in the collection (" 
      << this->AnimationEntries->GetNumberOfItems() << ")");
    return;
    }
  
  this->Dirty = 1;
  this->AnimationEntries->RemoveItem(item);
  this->AddTraceEntry("$kw(%s) DeleteSourceItem %d", this->GetTclName(), item);
  this->UpdateEntries();
  this->ShowEntryInFrame(0);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::EmptyEntryFrame()
{
  vtkKWWidget* frame = this->AnimationEntryInformation->GetFrame();
  this->Script("catch {eval pack forget [pack slaves %s]}",
    frame->GetWidgetName());
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ShowEntryInFrame(int idx)
{
  vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(idx);
  this->ShowEntryInFrame(entry, idx);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ShowEntryInFrameCallback(int idx)
{
  vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(idx);
  this->ShowEntryInFrame(entry, idx);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ShowEntryInFrame(
  vtkPVAnimationInterfaceEntry* entry, int in_idx)
{
  this->EmptyEntryFrame();
  if ( !entry )
    {
    this->AnimationEntriesMenu->SetButtonText("");
    this->DeleteItemButton->EnabledOff();
    return;
    }
  this->Script("pack %s -side top -expand 1 -fill both", entry->GetWidgetName());
  int idx = in_idx;
  if ( idx < 0 )
    {
    idx = this->GetSourceEntryIndex(entry);
    }
  if ( idx < 0 )
    {
    return;
    }
  char buffer[1024];
  sprintf(buffer, "DeleteSourceItem %d", idx);
  if ( this->AnimationEntries->GetNumberOfItems() <= 1 )
    {
    this->DeleteItemButton->EnabledOff();
    }
  else
    {
    this->DeleteItemButton->SetCommand(this, buffer);
    this->DeleteItemButton->EnabledOn();
    }
  entry->CreateLabel(idx);
  this->AnimationEntriesMenu->SetButtonText(entry->GetLabel());
  this->UpdateEntries();
  if ( this->InShowEntryInFrame )
    {
    return;
    }
  this->InShowEntryInFrame = 1;
  this->UpdateSourceMenu(idx);
  entry->UpdateMethodMenu();
  this->InShowEntryInFrame = 0;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateEntries()
{
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  char* command = vtkString::Duplicate("ShowEntryInFrameCallback XXXXXXXXXXXXXXXXX");
  int idx = 0;
  this->AnimationEntriesMenu->GetMenu()->DeleteAllMenuItems();
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    entry->CreateLabel(idx);
    const char* label = entry->GetLabel();
    sprintf(command, "ShowEntryInFrameCallback %d", idx);
    this->AnimationEntriesMenu->AddCommand(label, this, command); 
    idx ++;
    }
  delete [] command;
  this->UpdateNewScript();
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetSourceEntryIndex(vtkPVAnimationInterfaceEntry* entry)
{
  this->AnimationEntries->InitTraversal();
  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    vtkObject* o = this->AnimationEntries->GetItemAsObject(cc);
    if ( o == entry )
      {
      return cc;
      }
    }
  return -1;
}

//-----------------------------------------------------------------------------
vtkPVAnimationInterfaceEntry* vtkPVAnimationInterface::GetSourceEntry(int idx)
{
  this->AnimationEntries->InitTraversal();
  if ( idx < 0 && idx >= this->AnimationEntries->GetNumberOfItems() )
    {
    vtkErrorMacro(<< "Item " << idx << " is not in the collection (" 
      << this->AnimationEntries->GetNumberOfItems() << ")");
    return 0;
    }

  vtkPVAnimationInterfaceEntry* entry
    = vtkPVAnimationInterfaceEntry::SafeDownCast(
      this->AnimationEntries->GetItemAsObject(idx));
  if ( entry )
    {
    entry->SetCurrentIndex(idx);
    }
  return entry;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::UpdateNewScript()
{
  if ( !this->AnimationEntriesIterator )
    {
    return;
    }
  if ( this->UpdatingScript )
    {
    return;
    }
  this->UpdatingScript = 1;
  ostrstream str;
  ostrstream cstr;
  //str << "puts \"------------- start --------------\"" << endl;
  str << "# globalPVTime is provided by the animation " << endl;
  str << "# interface for convenience. " << endl;
  str << "# It varies linearly between 0 and 1 (0 at the " << endl;
  str << "# first frame, 1 at the last frame).\n" << endl;
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  int cnt = 0;
  int script_available = 0;
  if ( this->AnimationEntries->GetNumberOfItems() > 0 )
    {
    typedef vtkstd::map<vtkTypeUInt32, int> smaptype;
    smaptype smap;


    for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
      {
      vtkPVAnimationInterfaceEntry* entry
        = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
      entry->Prepare();
      // TODO: Why is this referring to only 1 VTK source (0)?
      if ( entry->GetPVSource() && entry->GetPVSource()->GetVTKSourceID(0).ID != 0 )
        {
        smap[entry->GetPVSource()->GetVTKSourceID(0).ID] = 1;
        cnt ++;
        }
      if ( entry->GetDirty() )
        {
        this->Dirty = 1;
        //cout << "Entry changed" << endl;
        }
      }
    if ( cnt )
      {
      str << "# The available sources are:" << endl;
      str << "# ";

      smaptype::iterator sit;
      for ( sit = smap.begin(); sit != smap.end(); ++sit )
        {
        str << sit->first << " ";
        }
      str << endl;
      script_available = 1;
      }
    }
  if ( !cnt )
    {
    str << "# The available sources are: none." << endl;
    }
  str << "# Note: Only sources listed above can be used in the script." << endl
      << "# Other sources will not be updated during the animation. " << endl;
  if ( !this->Dirty)
    {
    //cout << " \\- No change" << endl;
    this->UpdatingScript = 0;
    return;
    }
  str << endl;
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem() )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    if ( entry->GetScript() )
      {
      str << entry->GetTimeEquation(this->NumberOfFrames) << endl;
      str << entry->GetScript() << endl;
      script_available = 1;
      }
    entry->SetDirty(0);
    }
  //str << "puts \"-------------- end ---------------\"" << endl;
  str << ends;
  cstr << ends;
  this->SetNewScriptString(str.str());
  str.rdbuf()->freeze(0);
  cstr.rdbuf()->freeze(0);
  this->ScriptEditor->SetValue(this->NewScriptString);
  this->Dirty = 0;

  this->ScriptAvailable = script_available;
  this->UpdatingScript = 0;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ScriptEditorCallback()
{
  const char* script = this->ScriptEditor->GetValue();
  unsigned int cc;
  ostrstream str;
  str << "SetScript {";
  for ( cc = 0; cc< strlen(script); cc ++ )
    {
    int ch = script[cc];
    switch ( ch )
      {
      case '\"': str << "\\\""; break;
      case '{': str << "\\{"; break;
      case '}': str << "\\}"; break;
      case '\n': str << "\\\n"; break;
      case '\\': str << "\\\\"; break;
    default: str << (char)ch; break;
      }
    }
  str << "}" << ends;
  //cout << "Script: " << str.str() << endl;
  str.rdbuf()->freeze(0);
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetGlobalStart()
{
  float range[2];
  this->TimeRange->GetRange(range);
  return static_cast<int>(range[0]);
}

//-----------------------------------------------------------------------------
int vtkPVAnimationInterface::GetGlobalEnd()
{
  float range[2];
  this->TimeRange->GetRange(range);
  return static_cast<int>(range[1]);
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrepareForDelete()
{
  this->Stop();
  this->AnimationEntriesIterator->Delete();
  this->AnimationEntriesIterator = 0;
  this->AnimationEntries->Delete();
  this->AnimationEntries = 0;
}

//----------------------------------------------------------------------------
void vtkPVAnimationInterface::DeleteSource(vtkPVSource* src)
{
  vtkCollectionIterator* it = this->AnimationEntriesIterator;
  int cc = 0;
  for ( it->InitTraversal(); !it->IsDoneWithTraversal(); it->GoToNextItem(), cc++ )
    {
    vtkPVAnimationInterfaceEntry* entry
      = vtkPVAnimationInterfaceEntry::SafeDownCast(it->GetObject());
    if ( entry->GetPVSource() == src )
      {
      this->DeleteSourceItem(cc);
      it->InitTraversal();
      cc = 0;
      }
    }
  if ( this->AnimationEntries->GetNumberOfItems() == 0 )
    {
    this->AddEmptySourceItem();
    }
}

//----------------------------------------------------------------------------
void vtkPVAnimationInterface::SaveState(ofstream* file)
{
  int numberFrames = this->NumberOfFramesEntry->GetEntry()->GetValueAsInt();
  int frame = static_cast<int>(this->TimeScale->GetValue());

  int cc;
  for ( cc = 0; cc < this->AnimationEntries->GetNumberOfItems(); cc ++ )
    {
    vtkPVAnimationInterfaceEntry* entry = this->GetSourceEntry(cc);
    if ( entry->IsActionValid(1) )
      {
      *file << "set kw(" << entry->GetTclName() << ") [$kw(" << this->GetTclName() 
        << ") AddEmptySourceItem]" << endl;
      entry->SaveState(file);
      }
    }

  *file << "$kw(" << this->GetTclName() << ") SetNumberOfFrames " << numberFrames << endl;
  *file << "$kw(" << this->GetTclName() << ") SetCurrentTime " << frame << endl;
  
  *file << "$kw(" << this->GetTclName() << ") SetCacheGeometry "
        << this->GetCacheGeometry() << endl;
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::ExecuteEvent(vtkObject *, unsigned long event, 
  void*)
{
  if ( event == vtkKWEvent::ErrorMessageEvent )
    {
    this->Stop();
    }
}

//-----------------------------------------------------------------------------
void vtkPVAnimationInterface::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "ControlledWidget: " << this->GetControlledWidget() << endl;
  os << indent << "NumberOfFrames: " << this->GetNumberOfFrames() << endl;
  os << indent << "Loop: " << this->GetLoop() << endl;
  os << indent << "View: " << this->GetView() << endl;
  os << indent << "Window: " << this->GetWindow() << endl;
  os << indent << "ScriptAvailable: " << this->ScriptAvailable << endl;
}





