// Facilitate automatic particle finding in micrographs
class ParticleFinder {

  public:
    ParticleFinder( );
    ~ParticleFinder( );

    ArrayOfParticlePositionAssets ReturnArrayOfParticlePositionAssets( );
    void                          DoItAll( );
    void                          RedoWithNewMaximumRadius( );
    void                          RedoWithNewTypicalRadius( );
    void                          RedoWithNewMinimumPeakHeight( );
    void                          RedoWithNewHighestResolution( );
    void                          RedoWithNewMinimumDistanceFromEdges( );
    void                          RedoWithNewAvoidLowVarianceAreas( );
    void                          RedoWithNewAvoidHighVarianceAreas( );
    void                          RedoWithNewLowVarianceThreshold( );
    void                          RedoWithNewHighVarianceThreshold( );
    void                          RedoWithNewAvoidAbnormalLocalMeanAreas( );
    void                          RedoWithNewNumberOfBackgroundBoxes( );
    void                          RedoWithNewAlgorithmToFindBackground( );

    wxString ReturnMicrographFilename( ) { return micrograph_filename; };

    CTF ReturnMicrographCTFWithPickingPixelSize( ) { return micrograph_ctf; };

    CTF ReturnMicrographCTFWithOriginalPixelSize( );

    float ReturnOriginalMicrographPixelSize( ) { return original_micrograph_pixel_size; };

    void SetAllUserParameters(wxString wanted_micrograph_filename,
                              float    wanted_original_micrograph_pixel_size,
                              float    wanted_acceleration_voltage_in_keV,
                              float    wanted_spherical_aberration_in_mm,
                              float    wanted_amplitude_contrast,
                              float    wanted_additional_phase_shift_in_radians,
                              float    wanted_defocus_1_in_angstroms,
                              float    wanted_defocus_2_in_angstroms,
                              float    wanted_astigmatism_angle_in_degrees,
                              bool     wanted_already_have_templates,
                              wxString wanted_templates_filename,
                              bool     wanted_average_templates_radially,
                              int      wanted_number_of_template_rotations,
                              float    wanted_typical_radius_in_angstroms,
                              float    wanted_maximum_radius_in_angstroms,
                              float    wanted_highest_resolution_to_use,
                              wxString wanted_output_stack_filename,
                              int      wanted_output_stack_box_size,
                              int      wanted_minimum_distance_from_edges_in_pixels,
                              float    wanted_minimum_peak_height_for_candidate_particles,
                              bool     wanted_avoid_low_variance_areas,
                              bool     wanted_avoid_high_variance_areas,
                              float    wanted_low_variance_threshold_in_fwhm,
                              float    wanted_high_variance_threshold_in_fwhm,
                              bool     wanted_avoid_high_low_mean_areas,
                              int      wanted_algorithm_to_find_background,
                              int      wanted_number_of_background_boxes,
                              bool     wanted_particles_are_white);

    // Todo: To be made private
    // Todo: use more appropriate objects to do this. Maybe ParticlePositionAssets, or wxArrays of floats
    // Use will (mis)use Curve objects to keep track of our results
    Curve results_x_y;
    Curve results_height_template;
    Curve results_rotation;

    bool write_out_plt;

  private:
    // Parameters from the user
    wxString micrograph_filename;
    wxString templates_filename;
    bool     already_have_templates;
    float    original_micrograph_pixel_size;
    float    highest_resolution_to_use;
    float    maximum_radius_in_angstroms;
    float    typical_radius_in_angstroms;
    bool     average_templates_radially;
    int      algorithm_to_find_background;
    int      number_of_background_boxes;
    int      number_of_template_rotations;
    float    minimum_peak_height_for_candidate_particles;
    int      output_stack_box_size;
    bool     avoid_low_variance_areas;
    bool     avoid_high_variance_areas;
    float    low_variance_threshold_in_fwhm;
    float    high_variance_threshold_in_fwhm;
    bool     avoid_high_low_mean_areas;
    int      minimum_distance_from_edges_in_pixels;
    wxString output_stack_filename;
    bool     particles_are_white;

    // CTF parameters from the user
    float acceleration_voltage_in_keV;
    float spherical_aberration_in_mm;
    float amplitude_contrast;
    float additional_phase_shift_in_radians;
    float defocus_1_in_angstroms;
    float defocus_2_in_angstroms;
    float astigmatism_angle_in_degrees;

    // Internal
    int   new_micrograph_dimension_x;
    int   new_micrograph_dimension_y;
    int   new_template_dimension;
    float pixel_size;
    float maximum_radius_in_pixels;
    float typical_radius_in_pixels;
    int   number_of_background_boxes_to_skip;
    //float 		minimum_distance_between_picks_in_angstroms;
    //float		minimum_distance_between_picks_in_pixels;
    int          minimum_box_size_for_object_with_psf;
    int          minimum_box_size_for_picking;
    int          number_of_templates;
    MRCFile      micrograph_file;
    MRCFile      template_file;
    CTF          micrograph_ctf;
    Image*       template_image;
    ProgressBar* my_progress_bar;
    Curve        template_power_spectrum;
    Curve        background_power_spectrum;
    Curve        current_power_spectrum;
    Curve        current_number_of_fourier_elements;
    Curve        temp_curve;
    Image        micrograph;
    Image        micrograph_bp;
    Image        micrograph_whitened;
    float        micrograph_mean;
    Image        local_mean;
    Image        local_sigma;
    //Image 		local_sigma_modified;
    float local_sigma_mode;
    float local_sigma_fwhm;
    float local_mean_mode;
    float local_mean_fwhm;
    Curve background_whitening_filter;
    Image maximum_score;
    Image maximum_score_modified;
    Image template_rotation_giving_maximum_score;
    Image template_giving_maximum_score;

    // Private methods
    void UpdateMaximumRadiusInPixels( );
    void UpdateTypicalRadiusInPixels( );
    void CloseImageFiles( );
    void FindPeaksAndExtractParticles( );
    void RemoveHighLowMeanAreasFromTargetFunction( );
    void RemoveHighLowVarianceAreasFromTargetFunction( );
    void DoTemplateMatching( );
    void WhitenMicrographBackground( );
    void UpdateLocalMeanAndSigma( );
    void BandPassMicrograph( );
    void ReadAndResampleMicrograph( );
    void GenerateATemplate( );
    void SetupCurveObjects( );
    void ReadTemplatesFromDisk( );
    void AllocateTemplateImages( );
    void DeallocateTemplateImages( );
    void UpdateMinimumBoxSize( );
    void OpenMicrographAndUpdateDimensions( );
    void UpdatePixelSizeFromMicrographDimensions( );
    void OpenTemplatesAndUpdateDimensions( );
    void UpdateCTF( );
    void ComputeLocalMeanAndStandardDeviation(Image* micrograph, Image* mask_image, float mask_radius_in_pixels, long number_of_pixels_within_mask, Image* micrograph_local_mean, Image* micrograph_local_stdev);
    void SetAreaToIgnore(Image& my_image, int central_pixel_address_x, int central_pixel_address_y, Image* box_image, float wanted_value);
    void SetCircularAreaToIgnore(Image& my_image, const int central_pixel_address_x, const int central_pixel_address_y, const float wanted_radius, const float wanted_value);
    void PrepareTemplateForMatching(Image* template_image, Image& prepared_image, float in_plane_rotation, CTF* micrograph_ctf, Curve* whitening_filter);
};
