/* -*- 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 <climits>
#include <mia/internal/autotest.hh>
#include <mia/core/cmdlineparser.hh>
#include <mia/3d/nfg.hh>


NS_MIA_USE
using namespace std;

const float check_noise_level = sqrt((499.0 - 131.0 * 131.0 / 54.0) / 53.0 );

const float grad_sum_norm = 2+ 5+ 2 + sqrt(6.5)+ sqrt(9.25)+  2.5 + 3+ 4 + sqrt(21.25) + 2; 

const float check_jump_level = check_noise_level * grad_sum_norm / 27.0f;

P3DImage create_test_image()
{
	const float init_data[27] = { 0, 1, 0,
				      6, 4, 0,
				      4, 9, 4,

				      1, 2, 1,
				      5, 5, 5,
				      6, 8, 6,

				      0, 1, 0,
				      7, 3, 0,
				      2, 7, 6
	};


	/* the gradient: 
	   (0,0,0), (0,0,0),(0,0,0); 
	   (0,2,0),(-3,4,0),(0,2,0);     2, 5, 2 
	   (0,0,0), (0,0,0), (0,0,0);
	   
	   (0,   0, 0),( 0,  0,  0), (0,  0, 0); 
	   (0,2.5, .5),( 0,  3,-.5), (0,2.5, 0); sqrt(6.5), sqrt(9,25), 2.5
	   (0,  0, -1),( 0,  0, -1), (0,  0, 1); 1, 1, 1

	   (0,0,0), (0,0,0),  (0,0,0); 
	   (0,1,0), (-3.5,3,0),(0,3,0); 1, sqrt(21.25), 3, 
	   (0,0,0), (2,0,0),  (0,0,0); 2   

	 */

	/*
	  0:  5 :   0 :   0
	  1: 19 :  19 :  19
	  2:  9 :  18 :  36
	  3:  4 :  12 :  36
	  4:  7 :  28 : 112
	  5:  7 :  35 : 175
	  6:  2 :  12 :  72
	  7:  1 :   7 :  49
	Sum: 54 : 131 : 499
	 */

	C3DBounds size(3,3,3);
	return P3DImage(new C3DFImage(size, init_data));
}


BOOST_AUTO_TEST_CASE( check_nfg_n )
{
	P3DImage image = create_test_image();

	const float noise_level = 27.0 / grad_sum_norm;
	C3DFVectorfield ngf = get_nfg_n(*image,  noise_level);


	C3DFVector center = ngf(1,1,1);

	BOOST_CHECK_CLOSE(center.x , 0.0f, 0.1);
	BOOST_CHECK_CLOSE(center.y , 3.0f / sqrtf(10.25f), 0.1);
	BOOST_CHECK_CLOSE(center.z , -0.5f / sqrtf(10.25f), 0.1);

	C3DFVectorfield ngf2 = get_nfg_n(*image,  0.0);
	center = ngf2(1,1,1);


	BOOST_CHECK_CLOSE(center.x ,  0.0f, 0.1);
	BOOST_CHECK_CLOSE(center.y ,  3.0f / sqrt(9.25f), 0.1);
	BOOST_CHECK_CLOSE(center.z ,  -0.5f / sqrt(9.25f), 0.1);
}


BOOST_AUTO_TEST_CASE( check_nfg_j )
{
	P3DImage image = create_test_image();

	const float jump_level = get_jump_level(*image, 27.0 / grad_sum_norm);
	C3DFVectorfield ngf = get_nfg_j(*image,  jump_level*jump_level);

	C3DFVector center = ngf(1,1,1);

	BOOST_CHECK_CLOSE(center.x , 0.0f, 0.1);
	BOOST_CHECK_CLOSE(center.y , 3.0f / sqrtf(10.25f), 0.1);
	BOOST_CHECK_CLOSE(center.z , -0.5f / sqrtf(10.25f), 0.1);


	C3DFVectorfield ngf2 = get_nfg_j(*image,  0.0);
	center = ngf2(1,1,1);

	BOOST_CHECK_CLOSE(center.x ,  0.0f, 0.1);
	BOOST_CHECK_CLOSE(center.y ,  3.0f / sqrt(9.25f), 0.1);
	BOOST_CHECK_CLOSE(center.z ,  -0.5f / sqrt(9.25f), 0.1);
}



BOOST_AUTO_TEST_CASE( check_get_noise_level )
{

	P3DImage image = create_test_image();
	BOOST_CHECK_CLOSE(get_noise_level(*image),check_noise_level, 0.1);
}


BOOST_AUTO_TEST_CASE( check_intensity_jump_level )
{
	P3DImage image = create_test_image();
	const float noise_level = 27.0 / grad_sum_norm;

	BOOST_CHECK_CLOSE(get_jump_level(*image, noise_level), 1.0f, 0.1);

}

BOOST_AUTO_TEST_CASE(  test_get_jump_level2 )
{
	P3DImage image = create_test_image();
	BOOST_CHECK_CLOSE(get_jump_level(*image), check_jump_level , 0.1);
}

