/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */


#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <string>
#include <stdexcept>
#include <algorithm>

#include <mia/core/cmdlineparser.hh>
#include <mia/internal/main.hh>
#include <mia/core/msgstream.hh>
#include <mia/2d/filter.hh>
#include <mia/2d/imageio.hh>

using namespace std;
NS_MIA_USE


const SProgramDescription g_general_help = {
       {pdi_group, "Analysis, filtering, combining, and segmentation of 2D images"},
       {pdi_short, "Evaluate the dice index between two binary 2D images."},
       {
              pdi_description, "This program evaluate the dice index of two binary masks given as binary images. "
              "The result is written to stdout."
       },
       {pdi_example_descr, "Evaluate the dice index of maks1.png and mask2.png"},
       {pdi_example_code, "-1 mask1.png -2 mask2.png"}
};

template <typename I1, typename I2, typename F>
void for_each_pair(I1 begin1, I1 end1, I2 begin2, F function)
{
       while ( begin1 != end1 ) {
              function(*begin1, *begin2);
              ++begin1;
              ++begin2;
       }
}

float get_dice_index(const C2DBitImage& mask1, const C2DBitImage& mask2)
{
       int n1 = 0;
       int n2 = 0;
       int s = 0;
       for_each_pair(mask1.begin(), mask1.end(), mask2.begin(),
       [&n1, &n2, &s](bool b1, bool b2) {
              if (b1)  ++n1;

              if (b2)  ++n2;

              if (b1 && b2) ++s;
       });
       int sum = n1 + n2;

       if (sum)
              return (2.0 * s) / sum;
       else
              return 1.0;
}

int do_main( int argc, char *argv[] )
{
       const auto& imageio = C2DImageIOPluginHandler::instance();
       string in_filename1;
       string in_filename2;
       CCmdOptionList options(g_general_help);
       options.add(make_opt( in_filename1, "in-file-1", '1', "input image 1",
                             CCmdOptionFlags::required_input, &imageio));
       options.add(make_opt( in_filename2, "in-file-2", '2', "input image 2",
                             CCmdOptionFlags::required_input, &imageio));
       options.set_stdout_is_result();

       if (options.parse(argc, argv) != CCmdOptionList::hr_no)
              return EXIT_SUCCESS;

       auto in_image1 = load_image2d(in_filename1);
       auto in_image2 = load_image2d(in_filename2);

       if (in_image1->get_pixel_type() != it_bit)
              throw invalid_argument("Image 1 is not of bit pixel type");

       if (in_image2->get_pixel_type() != it_bit)
              throw invalid_argument("Image 2 is not of bit pixel type");

       if (in_image1->get_size() != in_image2->get_size())
              throw invalid_argument("Images are of different size");

       auto mask1 = dynamic_cast<const C2DBitImage&>(*in_image1);
       auto mask2 = dynamic_cast<const C2DBitImage&>(*in_image2);
       cout << get_dice_index(mask1, mask2) << "\n";
       return EXIT_SUCCESS;
}

MIA_MAIN(do_main);


