/* -*- 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 <mia/3d/filter/reorient.hh>

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

struct ReorientMock {
	ReorientMock();
	void check_result(P3DImage result, const C3DUSImage& test_image,
			  const C3DFVector& test_voxel);

	C3DBounds size;
	C3DUSImage src;
};

ReorientMock::ReorientMock():
	size(2,3,5),
	src(size)
{
	C3DUSImage::iterator i = src.begin();
	for (size_t k = 0; k < src.size(); ++k, ++i)
		*i = k;

	src.set_voxel_size(C3DFVector(1.0, 2.0, 3.0));
}

void ReorientMock::check_result(P3DImage result, const C3DUSImage& test_image, const C3DFVector& test_voxel)
{
	const C3DUSImage *r = dynamic_cast<const C3DUSImage *>(result.get());
	BOOST_REQUIRE(r);
	BOOST_CHECK_EQUAL(r->get_size(), test_image.get_size());
	BOOST_REQUIRE(r->get_size() == test_image.get_size());
	for (C3DUSImage::const_iterator ir = r->begin(), it = test_image.begin();
	     ir != r->end(); ++ir, ++it){
		BOOST_CHECK_EQUAL(*ir, *it);
	}

	BOOST_CHECK_EQUAL(r->get_voxel_size(), test_voxel);
}


BOOST_FIXTURE_TEST_CASE( test_reorient_traversal_to_traversal, ReorientMock )
{
	C3DReorient f(C3DReorient::xyz);
	check_result(f.filter(src), src, src.get_voxel_size().xyz());
}

BOOST_FIXTURE_TEST_CASE( test_reorient_xzy, ReorientMock )
{
	C3DReorient f(C3DReorient::flip_yz);
	C3DBounds test_size(size.x, size.z, size.y);

	C3DUSImage  test_image(test_size, src);

	for (size_t z = 0; z < src.get_size().z; ++z)
		for (size_t y = 0; y < src.get_size().y; ++y)
			for (size_t x = 0; x < src.get_size().x; ++x) {
				test_image(x,z,y) = src(x,y,z);
			}

	check_result(f.filter(src), test_image, src.get_voxel_size().xzy());
}


BOOST_FIXTURE_TEST_CASE( test_reorient_yxz, ReorientMock )
{
	C3DReorient f(C3DReorient::flip_xy);
	C3DBounds test_size(size.y, size.x, size.z);

	C3DUSImage  test_image(test_size, src);

	for (size_t z = 0; z < src.get_size().z; ++z)
		for (size_t y = 0; y < src.get_size().y; ++y)
			for (size_t x = 0; x < src.get_size().x; ++x) {
				test_image(y,x,z) = src(x,y,z);
			}
	check_result(f.filter(src), test_image, test_image.get_voxel_size().yxz());
}


BOOST_FIXTURE_TEST_CASE( test_reorient_yzx, ReorientMock )
{
	C3DReorient f(C3DReorient::yzx);
	C3DBounds test_size(size.y, size.z, size.x);

	C3DUSImage  test_image(test_size, src);

	for (size_t z = 0; z < src.get_size().z; ++z)
		for (size_t y = 0; y < src.get_size().y; ++y)
			for (size_t x = 0; x < src.get_size().x; ++x) {
				test_image(y,z,x) = src(x,y,z);
			}
	check_result(f.filter(src), test_image, test_image.get_voxel_size().yzx());
}


BOOST_FIXTURE_TEST_CASE( test_reorient_zxy, ReorientMock )
{
	C3DReorient f(C3DReorient::zxy);
	C3DBounds test_size(size.z, size.x, size.y);

	C3DUSImage  test_image(test_size, src);

	for (size_t z = 0; z < src.get_size().z; ++z)
		for (size_t y = 0; y < src.get_size().y; ++y)
			for (size_t x = 0; x < src.get_size().x; ++x) {
				test_image(z,x,y) = src(x,y,z);
			}
	check_result(f.filter(src), test_image, test_image.get_voxel_size().zxy());
}

BOOST_FIXTURE_TEST_CASE( test_reorient_zyx, ReorientMock )
{
	C3DReorient f(C3DReorient::flip_xz);
	C3DBounds test_size(size.z, size.y, size.x);

	C3DUSImage  test_image(test_size, src);

	for (size_t z = 0; z < src.get_size().z; ++z)
		for (size_t y = 0; y < src.get_size().y; ++y)
			for (size_t x = 0; x < src.get_size().x; ++x) {
				test_image(z,y,x) = src(x,y,z);
			}
	check_result(f.filter(src), test_image, test_image.get_voxel_size().zyx());
}


struct ReorientFromAxialMock {
	ReorientFromAxialMock();
	void check_result(const C3DReorient& f, E3DImageOrientation new_orientation, const char *faces);

	C3DBounds size;
	C3DSBImage src;
};

ReorientFromAxialMock::ReorientFromAxialMock():
	size(3,3,3),
	src(size)
{
	fill(src.begin(), src.end(), '\0');
	src.set_orientation(ior_axial);
	src(0,1,1) = 'l';
	src(2,1,1) = 'r';

	src(1,0,1) = 'f';
	src(1,2,1) = 'b';

	src(1,1,0) = 'u';
	src(1,1,2) = 'd';

}

void ReorientFromAxialMock::check_result(const C3DReorient& f, E3DImageOrientation new_orientation, const char *faces)
{
	P3DImage result = f.filter(src);
	const C3DSBImage *r = dynamic_cast<const C3DSBImage *>(result.get());
	BOOST_REQUIRE(r);

	BOOST_CHECK_EQUAL(r->get_orientation(), new_orientation);

	BOOST_CHECK_EQUAL((*r)(0,1,1), faces[0]);
	BOOST_CHECK_EQUAL((*r)(2,1,1), faces[1]);
	BOOST_CHECK_EQUAL((*r)(1,0,1), faces[2]);
	BOOST_CHECK_EQUAL((*r)(1,2,1), faces[3]);
	BOOST_CHECK_EQUAL((*r)(1,1,0), faces[4]);
	BOOST_CHECK_EQUAL((*r)(1,1,2), faces[5]);

}



