@LICENCE@
#include "@ACTIONCLASSNAME@.h"

// CamiTK includes
#include <Property.h>
#include <Log.h> 

// Additional includes
@ADDITIONAL_INCLUDES@

@IF_ITKFILTER@
// Itk includes
#include <itkVTKImageToImageFilter.h>
#include <itkImageToVTKImageFilter.h>
#include <ItkProgressObserver.h>
// Do not forget to include your own ITK filter here and to remove this one:
#include <itkOtsuThresholdImageFilter.h>
@ENDIF_ITKFILTER@

using namespace camitk;


// ------------------- Constructor -------------------
@ACTIONCLASSNAME@::@ACTIONCLASSNAME@(ActionExtension * extension) : Action(extension) {
    // Setting name, description and input component
    setName("@ACTION_NAME@");
    setDescription("@ACTION_DESCRIPTION@");
    setComponentClassName("@COMPONENTNAME@");

    // Setting classification family and tags
    setFamily("@FAMILY@");
    @BEGIN_ADDTAGS@
    addTag("@TAG@");
    @ELSE_ADDTAG@
    // Tags allow the user to search the actions trhough themes
    // You can add tags here with the method addTag("tagName");

    @END_ADDTAG@

    // Setting the action's parameters
    @BEGIN_ADDPROPERTIES@
    addParameter(new Property(tr("@PROPERTY_NAME@"), @PROPERTY_VALUE@, tr("@PROPERTY_DESCRIPTION@"), "@PROPERTY_UNIT@"));
    @ELSE_ADDPROPERTIES@
    // If you want to add parameters to your action, you can add them
    // using properties
    // addParameter(new Property(tr("Property name"), "Property value", tr("Property description"), "Property unit"));
    @END_ADDPROPERTIES@

}

// ------------------- apply -------------------
Action::ApplyStatus @ACTIONCLASSNAME@::apply() {
    @IF_NOCOMP@
    @IF_ADDPROPERTIES@
    // Get the parameters
    @ENDIF_ADDPROPERTIES@
    @BEGIN_ADDPROPERTIES@
    @PROPERTY_TYPE@ @PROPERTY_CPP_NAME@ = property("@PROPERTY_NAME@").@PROPERTY_TOTYPE@;
    @END_ADDPROPERTIES@

    // For demo reason, create a warning log message.
    // Although it is recommanded, in a classic CEP development process,
    // to use CAMITK_TRACE of CAMITK_INFO instead to show information.
    QString logMessage;
    logMessage = tr("Action \"@ACTION_NAME@\" called");
    @IF_ADDPROPERTIES@
    logMessage += tr(" with parameters:");
    @ENDIF_ADDPROPERTIES@
    logMessage += "\n";
    @BEGIN_ADDPROPERTIES@
    logMessage += QString(" - \"@PROPERTY_NAME@\": ") + @PROPERTY_VALUE_AS_QSTRING@ + "\n";
    @END_ADDPROPERTIES@
    CAMITK_WARNING(logMessage);

    @ELSEIF_NOCOMP@

    for(Component *comp: getTargets()) {
        @IF_DEFCOMPONENT@
        @COMPONENTNAME@ * input = dynamic_cast<@COMPONENTNAME@ *> ( comp );
        process(input);
        @ELSEIF_DEFCOMPONENT@
        @IF_ADDPROPERTIES@
        // Get the parameters
        @ENDIF_ADDPROPERTIES@
        @BEGIN_ADDPROPERTIES@
        @PROPERTY_TYPE@ @PROPERTY_CPP_NAME@ = property("@PROPERTY_NAME@").@PROPERTY_TOTYPE@;
        @END_ADDPROPERTIES@

        // For demo reason, create a warning log message.
        // Although it is recommanded, in a classic CEP development process,
        // to use CAMITK_TRACE of CAMITK_INFO instead to show information.        
        logMessage = tr("Action \"@ACTION_NAME@\" called on component \"") + comp->getName() + "\"\n";
        @IF_ADDPROPERTIES@
        logMessage += tr("With parameters:\n");
        @ENDIF_ADDPROPERTIES@
        @BEGIN_ADDPROPERTIES@
        logMessage += QString(" - \"@PROPERTY_NAME@\": ") + @PROPERTY_VALUE_AS_QSTRING@ + "\n";
        @END_ADDPROPERTIES@
        CAMITK_WARNING(logMessage);
        @ENDIF_DEFCOMPONENT@
    }

    @END_NOCOMP@
    return SUCCESS;
}

@IF_DEFCOMPONENT@
void @ACTIONCLASSNAME@::process(@COMPONENTNAME@ * comp) {
    @IF_ADDPROPERTIES@
    // Get the parameters
    @ENDIF_ADDPROPERTIES@
    @BEGIN_ADDPROPERTIES@
    @PROPERTY_TYPE@ @PROPERTY_CPP_NAME@ = property("@PROPERTY_NAME@").@PROPERTY_TOTYPE@;
    @END_ADDPROPERTIES@

    // For demo reason, create a warning log message.
    // Although it is recommanded, in a classic CEP development process,
    // to use CAMITK_TRACE of CAMITK_INFO instead to show information.
    QString logMessage;
    logMessage = tr("Action \"@ACTION_NAME@\" called on component \"") + comp->getName() + "\"\n";
    @IF_ADDPROPERTIES@
    logMessage += tr("With parameters:\n");
    @ENDIF_ADDPROPERTIES@
    @BEGIN_ADDPROPERTIES@
    logMessage += QString(" - \"@PROPERTY_NAME@\": ") + @PROPERTY_VALUE_AS_QSTRING@ + "\n";
    @END_ADDPROPERTIES@
    CAMITK_WARNING(logMessage);

    @IF_IMAGECOMPONENT@
    // Getting the input image
    vtkSmartPointer<vtkImageData> inputImage  = comp->getImageData();
    int dims[3];
    int numberOfScalarComponents = inputImage->GetNumberOfScalarComponents();
    inputImage->GetDimensions(dims);

    // Creating the output image
    vtkSmartPointer<vtkImageData> outputImage = vtkSmartPointer<vtkImageData>::New();
    outputImage->SetDimensions(dims);
	outputImage->AllocateScalars(inputImage->GetScalarType(), numberOfScalarComponents);

    // Here, we arbitrarily fill the output image with the exact same data as the input image.
    // Thus this action just copy the input image (an example of stupid action...).
    for (int z = 0; z < dims[2]; z++) {
        for (int y=0; y<dims[1]; y++) {
            for (int x=0; x<dims[0]; x++) {
                for (int color = 0; color < numberOfScalarComponents; color++) {
                    double val = inputImage->GetScalarComponentAsDouble(x, y, z, color);
                    outputImage->SetScalarComponentFromDouble(x,y,z,color,val);
                }
            }
        }
    }

    // Create The output Component
    new ImageComponent(outputImage, comp->getName() + "@CAMEL_CASE_ACTION_NAME@");
    refreshApplication();
    @ENDIF_IMAGECOMPONENT@
    @IF_ITKFILTER@
    // ITK filter implementation using templates
    vtkSmartPointer<vtkImageData> inputImage = comp->getImageData();
    vtkSmartPointer<vtkImageData> outputImage = implementProcess (inputImage);
    // Create The output Component
    new ImageComponent(outputImage, comp->getName() + "@CAMEL_CASE_ACTION_NAME@");

    refreshApplication();
    @ENDIF_ITKFILTER@

}

@IF_ITKFILTER@
#include "@ACTIONCLASSNAME@.impl"

// ITK filter implementation
template <class InputPixelType, class OutputPixelType, const int dim>
vtkSmartPointer<vtkImageData> @ACTIONCLASSNAME@::itkProcess(vtkSmartPointer<vtkImageData> img) {
    vtkSmartPointer<vtkImageData> resultImage = nullptr;
    vtkSmartPointer<vtkImageData> result = vtkSmartPointer<vtkImageData>::New();

    // --------------------- Filters declaration and creation ----------------------
    // Define ITK input and output image types with respect to the instantiation
    //    types of the tamplate.
    typedef itk::Image< InputPixelType,  dim > InputImageType;
    typedef itk::Image< OutputPixelType, dim > OutputImageType;

    // Convert the image from CamiTK in VTK format to ITK format to use ITK filters.
    typedef itk::VTKImageToImageFilter<InputImageType> vtkToItkFilterType;
    typename vtkToItkFilterType::Pointer vtkToItkFilter = vtkToItkFilterType::New();

    // Declare and create your own private ITK filter here...
    // For example: we use here the Otsu filter
    typedef itk::OtsuThresholdImageFilter<InputImageType, OutputImageType> FilterType;
    typename FilterType::Pointer filter = FilterType::New();

    // In the same way, once the image is filtered, we need to convert it again to
    // VTK format to give it to CamiTK.
    typedef itk::ImageToVTKImageFilter<OutputImageType> itkToVtkFilterType;
    typename itkToVtkFilterType::Pointer itkToVtkFilter = itkToVtkFilterType::New();
    
    // ------------------------- WRITE YOUR CODE HERE ----------------------------------

    
    // To update CamiTK progress bar while filtering, add an ITK observer to the filters.
    ItkProgressObserver::Pointer observer = ItkProgressObserver::New();
    // ITK observers generally give values between 0 and 1, and CamiTK progress bar
    //    wants values between 0 and 100...
    observer->SetCoef(100.0);

    // --------------------- Plug filters and parameters ---------------------------
    // From VTK to ITK
    vtkToItkFilter->SetInput(img);
    // For the filter itself
    // For example, replace these lines by your own code: 
    filter->SetInput(vtkToItkFilter->GetOutput());
    filter->AddObserver ( itk::ProgressEvent(), observer );
    // Use your parameters if they are well defined
    //filter->SetOutsideValue((OutputPixelType) parameters->getOutsideValue());
    //filter->SetInsideValue( (OutputPixelType) parameters->getInsideValue() );

    // ------------------------- WRITE YOUR CODE HERE ----------------------------------


    // From ITK to VTK
    // Change the following line to put your filter instead of filter
    // For example: 
    itkToVtkFilter->SetInput(filter->GetOutput());

    // --------------------- Actually execute all filters parts --------------------
    itkToVtkFilter->Update();

    // --------------------- Create and return a copy (the filters will be deleted)--
    resultImage = itkToVtkFilter->GetOutput();
    int extent[6];
    resultImage->GetExtent(extent);
    result->SetExtent(extent);
    result->DeepCopy(resultImage);

    // Set CamiTK progress bar back to zero (the processing filter is over)
    observer->Reset();
    resultImage = itkToVtkFilter->GetOutput();

    return result;
}
@ENDIF_ITKFILTER@
@ENDIF_DEFCOMPONENT@
