#include <ImageDev/ImageDev.h>
#include <ioformat/IOFormat.h>
#include <iolink/view/ImageViewProvider.h>
#include <string.h>

using namespace imagedev;
using namespace ioformat;
using namespace iolink;

int
main( int argc, char* argv[] )
{
    int status = 0;

    try
    {
        // ImageDev library initialization
        if ( imagedev::isInitialized() == false )
            imagedev::init();

        // Open a standard tif file and display the image properties
        auto imageInput = readImage( std::string( IMAGEDEVDATA_IMAGES_FOLDER ) + "polystyrene.tif" );

        // Threshold the grayscale image
        auto imageThr =
            thresholdingByCriterion( imageInput, ThresholdingByCriterion::ComparisonCriterion::GREATER_THAN, 128 );

        // Separate connected particles
        auto imageSep = separateObjects( imageThr,
                                         2,
                                         SeparateObjects::OutputType::SEPARATED_OBJECTS,
                                         SeparateObjects::AlgorithmMode::REPEATABLE,
                                         SeparateObjects::Neighborhood::CONNECTIVITY_26 );
        imageThr.reset();

        // Remove particles touching image borders
        auto imageBdk = killBorder2d( imageSep, KillBorder2d::Neighborhood::CONNECTIVITY_8 );
        imageSep.reset();

        // Connected component labeling of a binary image
        auto imageLab =
            labeling2d( imageBdk, Labeling2d::LabelType::LABEL_8_BIT, Labeling2d::Neighborhood::CONNECTIVITY_8 );

        // The number of particles is the maximum label
        auto extrema = intensityExtrema( imageLab, 0 );
        int particleCount = ( int )extrema->maximum( 0, 0, 0 );

        // Define the analysis features to be computed
        AnalysisMsr::Ptr analysis = std::make_shared< AnalysisMsr >();
        auto centerX = analysis->select( NativeMeasurements::barycenterX );
        auto centerY = analysis->select( NativeMeasurements::barycenterY );
        auto diameter = analysis->select( NativeMeasurements::equivalentDiameter );
        auto intensity = analysis->select( NativeMeasurements::intensityMean );

        // Launch the feature extraction on the segmented image
        labelAnalysis( imageLab, imageInput, analysis );
        std::cout << "Number of particles = " << particleCount << std::endl;
        std::cout << "Particle\t" << centerX->name() << "\t" << centerY->name() << "\t"
                  << diameter->name() + "\t" + intensity->name() << std::endl;
        // Print the analysis results for 10% of the particles
        for ( int i = 0; i < ( int )( particleCount / 10 ); i++ )
        {
            std::cout << ( i + 1 ) << "\t\t" << centerX->value( i ) << "\t\t" << centerY->value( i ) << "\t\t"
                      << diameter->value( i ) << "\t\t\t" << intensity->value( i ) << std::endl;
        }

        // Save the created image with IOFormat
        writeView( imageLab, "T06_01_output.png" );

        std::cout << "This example ran successfully." << std::endl;
    }
    catch ( const imagedev::Exception& error )
    {
        // Print potential exception in the standard output
        std::cerr << "ImageDev exception: " << error.what() << std::endl;
        status = -1;
    }

    // ImageDev library finalization
    imagedev::finish();

    // Check if we must ask for an enter key to close the program
    if ( !( ( argc == 2 ) && strcmp( argv[1], "--no-stop-at-end" ) == 0 ) )
        std::cout << "Press Enter key to close this window." << std::endl, getchar();

    return status;
}
