/* -*- 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/>.
 *
 */

#include <mia/internal/autotest.hh>
#include <dicom/dcm2d.hh>
#include <dicom/dicom4mia.hh>

NS_MIA_USE
using namespace std;
using namespace ::boost;
using namespace ::boost::unit_test;
using namespace IMAGEIO_2D_DICOM;

struct DicomLoaderFixture {

       DicomLoaderFixture();

       template <typename T>
       void check_attribute(const char *name, const T& value)
       {
              TRACE_FUNCTION;
              cvdebug() << "check if attribute '" << name << "' has value '"
                        << value << "' of type '"
                        << typeid(T).name() << "'\n";
              PAttribute attr = pimage->get_attribute(name);
              BOOST_REQUIRE(attr);
              cvdebug() << "Got attribute of type '" << attr->typedescr() << "'\n";
              cvdebug() << "will cast from'" << typeid(attr.get()).name()
                        << "' to '" << typeid(TAttribute<T> *).name() << "'\n";
              const TAttribute<T>& pattr = dynamic_cast<const TAttribute<T>&>(*attr);
              T attr_val = pattr;
              BOOST_CHECK_EQUAL(attr_val, value);
       }

       void check_attribute(const char *name, const char *value);
       CDicom2DImageIOPlugin plugin;
       P2DImage pimage;
};

DicomLoaderFixture::DicomLoaderFixture()
{
       string filename(MIA_SOURCE_ROOT"/testdata/test.dcm");
       cvdebug() << "open: " << filename << "\n";
       CDicom2DImageIOPlugin::PData images = plugin.load(filename.c_str());
       BOOST_REQUIRE(images);
       BOOST_REQUIRE(images->size() == 1);
       pimage = *images->begin();
       BOOST_REQUIRE(pimage);
}


void DicomLoaderFixture::check_attribute(const char *name, const char *value)
{
       TRACE_FUNCTION;
       cvdebug() << "check if attribute '" << name << "' has value '"
                 << value << "' of type 'string'\n";
       string svalue(value);
       PAttribute attr = pimage->get_attribute(name);
       BOOST_REQUIRE(attr);
       const TAttribute<string> *pattr = dynamic_cast<TAttribute<string> *>(attr.get());
       BOOST_REQUIRE(pattr);
       string attr_val = *pattr;
       BOOST_CHECK_EQUAL(attr_val, svalue);
}



BOOST_FIXTURE_TEST_CASE( test_dicom_load, DicomLoaderFixture )
{
       check_attribute("StudyDescription", "Cardiovascular^Heart-Cardiac Function");
       check_attribute("SeriesDescription", "cine_retro_aortic arch");
       check_attribute("Modality", "MR");
       check_attribute("SeriesNumber", 24);
       check_attribute("PatientPosition", ipp_hfs);
       check_attribute("AcquisitionDate", "20041116");
       check_attribute("AcquisitionNumber", 1);
       check_attribute("InstanceNumber", 6);
       check_attribute("StudyID", "4273329");
       check_attribute("ImageType", "ORIGINAL\\PRIMARY\\M\\ND\\RETRO");
       check_attribute("SliceLocation", 15.088232007086f);
       check_attribute("MediaStorageSOPClassUID", "1.2.840.10008.5.1.4.1.1.4");
       C2DFVector pixel_size = pimage->get_pixel_size();
       BOOST_CHECK_EQUAL(pixel_size, C2DFVector(1.484375, 1.484375));
       // test
       const C2DUSImage& image = dynamic_cast<const C2DUSImage&>(*pimage);
       BOOST_CHECK_EQUAL(image.get_size(), C2DBounds(224, 256));
       BOOST_CHECK_EQUAL(image(0, 0), 0);
       // the next test is not necessarily right
       BOOST_CHECK_EQUAL(image(128, 114), 135);
}


template  <typename T>
struct DicomSaveLoadFixture {
       DicomSaveLoadFixture();
       CDicom2DImageIOPlugin plugin;
protected:
       void fill_attributes();
       C2DBounds size;
       T2DImage<T> *org_image;
       P2DImage porg_image;
};

template  <typename T>
void DicomSaveLoadFixture<T>::fill_attributes()
{
       org_image->set_attribute(IDMediaStorageSOPClassUID,  "othervalue");
       org_image->set_attribute(IDSOPClassUID,  "othervalue");
       org_image->set_pixel_size(C2DFVector(1.45, 2.34));
       org_image->set_attribute("Modality", "MR");
       org_image->set_attribute("SeriesNumber", "12");
       org_image->set_attribute("AcquisitionNumber", "23");
       org_image->set_attribute("InstanceNumber", "7");
       org_image->set_attribute("SeriesDescription", "T2-pla");
       org_image->set_attribute("StudyDescription", "PROST");
       org_image->set_attribute("AcquisitionDate", "20090909");
       org_image->set_attribute("PatientPosition", "HFP");
       org_image->set_attribute("StudyID", "786755");
       org_image->set_attribute("SliceLocation", "12.6755");
       org_image->set_attribute("ImageType", "ORIGINAL\\PRIMARY\\M\\ND\\RETRO");
       org_image->set_attribute(IDRescaleIntercept, -1.0f);
       org_image->set_attribute(IDRescaleSlope, 2.0f);
       org_image->set_attribute(IDSmallestImagePixelValue, "0");
       org_image->set_attribute(IDLargestImagePixelValue, "119");
}

template  <typename T>
DicomSaveLoadFixture<T>::DicomSaveLoadFixture():
       size(10, 12)
{
       org_image = new T2DImage<T>(size);
       short k = 0;

       for (auto i = org_image->begin(); i != org_image->end(); ++i, ++k)
              *i = k;

       porg_image.reset(org_image);
}


BOOST_FIXTURE_TEST_CASE( test_dicom_ss_save_load, DicomSaveLoadFixture<signed short> )
{
       fill_attributes();
       CDicom2DImageIOPlugin::Data imagelist;
       imagelist.push_back(porg_image);
       BOOST_REQUIRE(plugin.save("testsave-ss.dcm", imagelist));
       CDicom2DImageIOPlugin::PData images = plugin.load("testsave-ss.dcm");
       BOOST_REQUIRE(images);
       BOOST_REQUIRE(images->size() == 1);
       P2DImage pimage = *images->begin();
       BOOST_REQUIRE(pimage);
       BOOST_CHECK(*pimage ==  *org_image);
       const C2DSSImage& load_image = dynamic_cast<const C2DSSImage&>(*pimage);
       BOOST_CHECK_EQUAL(load_image.get_size(), size);
       BOOST_CHECK(equal(load_image.begin(), load_image.end(), org_image->begin()));
}

BOOST_FIXTURE_TEST_CASE( test_dicom_us_save_load, DicomSaveLoadFixture<unsigned short> )
{
       fill_attributes();
       CDicom2DImageIOPlugin::Data imagelist;
       imagelist.push_back(porg_image);
       BOOST_REQUIRE(plugin.save("testsave-us.dcm", imagelist));
       CDicom2DImageIOPlugin::PData images = plugin.load("testsave-us.dcm");
       BOOST_REQUIRE(images);
       BOOST_REQUIRE(images->size() == 1);
       P2DImage pimage = *images->begin();
       BOOST_REQUIRE(pimage);
       BOOST_CHECK(*pimage ==  *org_image);
       const C2DUSImage& load_image = dynamic_cast<const C2DUSImage&>(*pimage);
       BOOST_CHECK_EQUAL(load_image.get_size(), size);
       BOOST_CHECK(equal(load_image.begin(), load_image.end(), org_image->begin()));
}

BOOST_FIXTURE_TEST_CASE( test_dicom_load_nothing, DicomSaveLoadFixture<signed short> )
{
       CDicom2DImageIOPlugin plugin;
       CDicom2DImageIOPlugin::PData images = plugin.load("nonexistence.dcm");
       BOOST_CHECK(!images.get());
}

