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

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

#include "vtkKWWindowBase.h"
#include "vtkKWRenderWidget.h"
#include "vtkAlgorithm.h"
#include "vtkKWProgressGauge.h"
#include "vtkKWEvent.h"
#include "vtkKWInternationalization.h"

#include <time.h>

//----------------------------------------------------------------------------
vtkKWProgressCommand::vtkKWProgressCommand()
{ 
  this->Window        = NULL;

  this->StartMessage  = NULL;
  this->EndMessage    = NULL;

  this->StartEvent    = vtkCommand::StartEvent;
  this->EndEvent      = vtkCommand::EndEvent;
  this->ProgressEvent = vtkCommand::ProgressEvent;

  this->RetrieveProgressMethod = vtkKWProgressCommand::GET_PROGRESS;

  this->RetrieveStartMessageFromCallData = 0;
  this->RetrieveEndMessageFromCallData   = 0;

  this->StartClock = 0;
}

//----------------------------------------------------------------------------
vtkKWProgressCommand::~vtkKWProgressCommand()
{
  this->SetWindow(NULL);

  this->SetStartMessage(NULL);
  this->SetEndMessage(NULL);
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetWindow(vtkKWWindowBase *window)
{
  if (this->Window != window)
    {
    if (this->Window)
      {
      this->Window->UnRegister(NULL);
      }
    this->Window = window;
    if (window)
      {
      window->Register(NULL);
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetStartMessage(const char *message)
{
  if (this->StartMessage)
    {
    delete [] this->StartMessage;
    this->StartMessage = NULL;
    }
  
  if (message)
    {
    this->StartMessage = new char [strlen(message) + 1];
    strcpy(this->StartMessage, message);
    if (!this->EndMessage)
      {
      ostrstream end_msg;
      end_msg << this->StartMessage << " -- " << ks_("Progress|Done") << ends;
      this->SetEndMessage(end_msg.str());
      end_msg.rdbuf()->freeze(0);
      }
    }
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetEndMessage(const char *message)
{
  if (this->EndMessage)
    {
    delete [] this->EndMessage;
    this->EndMessage = NULL;
    }
  
  if (message)
    {
    this->EndMessage = new char [strlen(message) + 1];
    strcpy(this->EndMessage, message);
    }
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetStartEvent(unsigned long event)
{
  this->StartEvent = event;
}

//----------------------------------------------------------------------------
unsigned long vtkKWProgressCommand::GetStartEvent()
{
  return this->StartEvent;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetEndEvent(unsigned long event)
{
  this->EndEvent = event;
}

//----------------------------------------------------------------------------
unsigned long vtkKWProgressCommand::GetEndEvent()
{
  return this->EndEvent;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetProgressEvent(unsigned long event)
{
  this->ProgressEvent = event;
}

//----------------------------------------------------------------------------
unsigned long vtkKWProgressCommand::GetProgressEvent()
{
  return this->ProgressEvent;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetRetrieveProgressMethod(int arg)
{
  this->RetrieveProgressMethod = arg;
}

//----------------------------------------------------------------------------
int vtkKWProgressCommand::GetRetrieveProgressMethod()
{
  return this->RetrieveProgressMethod;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetRetrieveStartMessageFromCallData(int arg)
{
  this->RetrieveStartMessageFromCallData = arg;
}

//----------------------------------------------------------------------------
int vtkKWProgressCommand::GetRetrieveStartMessageFromCallData()
{
  return this->RetrieveStartMessageFromCallData;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::SetRetrieveEndMessageFromCallData(int arg)
{
  this->RetrieveEndMessageFromCallData = arg;
}

//----------------------------------------------------------------------------
int vtkKWProgressCommand::GetRetrieveEndMessageFromCallData()
{
  return this->RetrieveEndMessageFromCallData;
}

//----------------------------------------------------------------------------
void vtkKWProgressCommand::Execute(vtkObject *caller, 
                                    unsigned long event, 
                                    void* callData)
{  
  if (!this->Window)
    {
    return;
    }

  // If we are getting progress during interactive rendering, skip them
  // since this is going to be way too fast anyway, and will just make
  // the progress gauge or status flicker in an annoying way.

  vtkKWRenderWidget *rw = vtkKWRenderWidget::SafeDownCast(caller);
  if (rw && rw->GetRenderMode() == vtkKWRenderWidget::InteractiveRender)
    {
    return;
    }

  vtkKWProgressGauge *gauge = this->Window->GetProgressGauge();

  vtkAlgorithm *po;
  double *dargs;


  // Start

  if (event == this->StartEvent)
    {
    if (this->RetrieveStartMessageFromCallData)
      {
      if (callData)
        {
        this->Window->SetStatusText(static_cast<char *>(callData));
        }
      }
    else
      {
      this->Window->SetStatusText(this->StartMessage);
      }
    gauge->SetValue(0);
    this->StartClock = (unsigned long)clock();
    }

  // End

  else if (event == this->EndEvent)
    {
    clock_t end_clock = clock();

    char *msg = NULL;
    if (this->RetrieveEndMessageFromCallData)
      {
      if (callData)
        {
        msg = static_cast<char *>(callData);
        }
      }
    else
      {
      msg = this->EndMessage;
      }

    if (msg)
      {
      if (this->StartClock)
        {
        clock_t delta = end_clock - (clock_t)this->StartClock;
        char *buffer = new char [strlen(msg) + 100];
        sprintf(buffer, ks_("Progress|Timing|%s (in %0.2f s.)"), 
                msg, (double)(delta) / (double)CLOCKS_PER_SEC);
        this->Window->SetStatusText(buffer);
        delete [] buffer;
        }
      else
        {
        this->Window->SetStatusText(msg);
        }
      }

    gauge->SetValue(0);
    this->StartClock = 0;
    }

  // Progress

  else if (event == this->ProgressEvent)
    {
    switch (this->RetrieveProgressMethod)
      {
      case vtkKWProgressCommand::GET_PROGRESS:
        po = vtkAlgorithm::SafeDownCast(caller);
        if (po)
          {
          gauge->SetValue(static_cast<int>(po->GetProgress() * 100.0));
          }
        break;
        
      case vtkKWProgressCommand::CALLDATA:
        dargs = static_cast<double *>(callData);
        gauge->SetValue(static_cast<int>(dargs[0] * 100.0));
        break;
      }
    }
}
