#include "itkCommand.h"
#include "itkImage.h"
#include "itkGaussianImageSource.h"
#include "itkGridImageSource.h"

// This callback function aborts the process it observes when the progress reaches 10%.
static const double ExecutionFractionForAbort = 0.1;
void AbortProgressCallback(itk::Object* caller, const itk::EventObject& itkNotUsed(event), void* itkNotUsed(clientData))
  {
  itk::ProcessObject* processObject = (itk::ProcessObject*)caller;
  std::cout << "Progress is " << 100.0 * processObject->GetProgress() << " %." << std::endl;
  if (processObject->GetAbortGenerateData() == false) {
    if (processObject->GetProgress() >= ExecutionFractionForAbort) {
      std::cout << "Filter " << caller->GetNameOfClass() << " is being aborted by AbortProgressCallback." << std::endl;
      processObject->AbortGenerateDataOn();
      }
    }
  }

// To define the image type..
typedef itk::Image<double, 3> ImageType;

int main()
  {
  // This command will observe the ProgressEvent of the filter.
  // The callback function will abort the process when its progress reaches 10%.
  typedef itk::CStyleCommand         CommandType;
  CommandType::Pointer processAborter = CommandType::New();
  processAborter->SetCallback(AbortProgressCallback);

  // Test with itk::GaussianImageSource.
  std::cout << std::endl << "Executing itk::GaussianImageSource filter." << std::endl;
    {
    // To set the filter.
    itk::GaussianImageSource<ImageType>::Pointer imageSource = itk::GaussianImageSource<ImageType>::New();
    ImageType::SizeType size;
    size.Fill(100);
    imageSource->SetSize(size);
    // To add the observer.
    imageSource->AddObserver(itk::ProgressEvent(), processAborter);
    // To execute the filter.
    try {
      imageSource->Update();
      std::cout << "Execution terminated successfully." << std::endl;
      }
    catch(itk::ProcessAborted& exc) {
      std::cout << "Filter execution has BEEN ABORTED." << std::endl;
      }
    catch(itk::ExceptionObject& exc) {
      std::cout << "Filter execution has GENERATED AN EXCEPTION." << std::endl;
      std::cout << "   Location: " << exc.GetLocation() << std::endl; 
      std::cout << "   Line " << exc.GetLine() << std::endl;
      std::cout << "   File " << exc.GetFile() << std::endl;
      std::cout << "   Description: ***" << exc.GetDescription() << "***" << std::endl;
      }
    }

  // Test with itk::GridImageSource.
  std::cout << std::endl << "Executing itk::GridImageSource filter." << std::endl;
    {
    // To set the filter.
    itk::GridImageSource<ImageType>::Pointer imageSource = itk::GridImageSource<ImageType>::New();
    ImageType::SizeType size;
    size.Fill(100);
    imageSource->SetSize(size);
    // To add the observer.
    imageSource->AddObserver(itk::ProgressEvent(), processAborter);
    // To execute the filter.
    try {
      imageSource->Update();
      std::cout << "Execution terminated successfully." << std::endl;
      }
    catch(itk::ProcessAborted& exc) {
      std::cout << "Filter execution has BEEN ABORTED." << std::endl;
      }
    catch(itk::ExceptionObject& exc) {
      std::cout << "Filter execution has GENERATED AN EXCEPTION." << std::endl;
      std::cout << "   Location: " << exc.GetLocation() << std::endl; 
      std::cout << "   Line " << exc.GetLine() << std::endl;
      std::cout << "   File " << exc.GetFile() << std::endl;
      std::cout << "   Description: ***" << exc.GetDescription() << "***" << std::endl;
      }
    }
  }