/* -*- 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/downscale.hh>
#include <mia/core/spacial_kernel.hh>

NS_MIA_USE
using namespace std;
using namespace ::boost::unit_test;
namespace bfs=boost::filesystem;
using namespace downscale_3dimage_filter;


BOOST_AUTO_TEST_CASE( test_downscale )
{
	const short init[64] = {
		0, 0, 1, 1, /**/ 0, 0, 1, 1, /**/ 2, 2, 3, 3, /**/ 2, 2, 3, 3,
		0, 0, 1, 1, /**/ 0, 0, 1, 1, /**/ 2, 2, 3, 3, /**/ 2, 2, 3, 3,
		4, 4, 5, 5, /**/ 4, 4, 5, 5, /**/ 6, 6, 7, 7, /**/ 6, 6, 7, 7,
		4, 4, 5, 5, /**/ 4, 4, 5, 5, /**/ 6, 6, 7, 7, /**/ 6, 6, 7, 7
	};

	// todo should test with a do-nothing filter
	const short test[8] = {
		1, 2, 3, 4, 4, 5, 6, 7
	};


	C3DSSImage fimage(C3DBounds(4, 4, 4), init );

	fimage.set_voxel_size(C3DFVector(2.0, 3.0, 1.0));

	CDownscale scaler(C3DBounds(2, 2, 2), "gauss");

	P3DImage scaled =scaler.filter(fimage);

	BOOST_CHECK_EQUAL(scaled->get_size(), C3DBounds(2, 2, 2));

	const C3DSSImage& fscaled = dynamic_cast<const C3DSSImage&>(*scaled);
	BOOST_CHECK_EQUAL(fscaled.get_voxel_size(), C3DFVector(4.0f, 6.0f, 2.0f));
	const short *t = test;
	for( C3DSSImage::const_iterator k = fscaled.begin(); k != fscaled.end(); ++k, ++t ) {
		BOOST_CHECK_EQUAL(*k, *t);
	}

}

BOOST_AUTO_TEST_CASE( test_downscale_nonskew_x )
{
	for (unsigned int dx = 1; dx < 4; ++dx)  {
		unique_ptr<C3DSSImage> fimage(new C3DSSImage(C3DBounds(10+dx, 20, 20)));
		auto i = fimage->begin(); 
		for (size_t z= 0; z < 20; ++z)
			for (size_t y = 0; y < 20; ++y)
				for (size_t x = 0; x < 10+dx; ++x, ++i) {
					*i = x; 
				}
		

		fimage->set_voxel_size(C3DFVector(2.0, 3.0, 1.0));

		CDownscale scaler(C3DBounds(2, 2, 2), "gauss");

		P3DImage scaled =scaler.filter(*fimage);

		size_t tsize = (10+dx+1)/2; 
		BOOST_CHECK_EQUAL(scaled->get_size(), C3DBounds(tsize, 10, 10));
		
		const C3DSSImage& fscaled = dynamic_cast<const C3DSSImage&>(*scaled);
		BOOST_CHECK_EQUAL(fscaled.get_voxel_size(), C3DFVector(4.0f, 6.0f, 2.0f));


		for (size_t z= 3; z < 8; ++z)
			for (size_t y = 3; y < 8; ++y)
				for (size_t x = 0; x < tsize; ++x) {
					BOOST_CHECK_EQUAL(fscaled(x,y,z), fscaled(x,2,2)); 
				}
		

	}
}

BOOST_AUTO_TEST_CASE( test_downscale_nonskew_y )
{
	for (unsigned int dx = 1; dx < 4; ++dx)  {
		unique_ptr<C3DSSImage> fimage(new C3DSSImage(C3DBounds(20, 10+dx, 20)));
		
		auto i = fimage->begin(); 
		for (size_t z= 0; z < 20; ++z)
			for (size_t y = 0; y < 10+dx; ++y)
				for (size_t x = 0; x < 20; ++x, ++i) {
					*i = y; 
				}
		

		fimage->set_voxel_size(C3DFVector(2.0, 3.0, 1.0));

		CDownscale scaler(C3DBounds(2, 2, 2), "gauss");

		P3DImage scaled =scaler.filter(*fimage);

		size_t tsize = (10+dx+1)/2; 
		BOOST_CHECK_EQUAL(scaled->get_size(), C3DBounds(10, tsize, 10));
		
		const C3DSSImage& fscaled = dynamic_cast<const C3DSSImage&>(*scaled);
		BOOST_CHECK_EQUAL(fscaled.get_voxel_size(), C3DFVector(4.0f, 6.0f, 2.0f));


		for (size_t z= 3; z < 8; ++z)
			for (size_t y = 3; y < tsize; ++y)
				for (size_t x = 0; x < 8; ++x) {
					BOOST_CHECK_EQUAL(fscaled(x,y,z), fscaled(2,y,2)); 
				}
		

	}
}
