/**
 * @file TestHisto.cpp
 * @date Aug 6, 2008
 * @author Ronald Kluth
 *
 * @brief Tests for ODEMx class Histo
 */

#include "TestStatistics.h"
#include "../TestBase/TestBase.h"
#include "../TestData/TestData.h"

#include <cmath>

/// @cond DOXYGEN_SKIP
SUITE( Statistics )
{
/// @endcond

	/**
	 * @struct HistoFixture
	 * @brief Helper struct providing set-up/tear-down of Histo tests
	 * @note Base class Tally-specific properties are not tested with Histo.
	 * @copydetails EventFixture
	 */
	struct HistoFixture
	{
		SuiteBase::SimulationTest sim;
		SuiteData::ReportTest reporter;
		double lower;
		double upper;
		int cells;
		Histogram histogram;

		HistoFixture()
		:	sim( "HistoTestSim" ),
			reporter(),
			lower( 0 ),
			upper( 5 ),
			cells( 5 ),
			histogram( sim, "HistoTest", lower, upper, cells )
			{}
	};

	/**
	 * @test odemx::Histo construction
	 *
	 * Expected effects:
	 * @li label is set correctly
	 * @li statistics manager (Simulation) is set correctly
	 * @li equal borders produce a warning
	 * @li lower border greater than upper border produces a warning
	 * @li number of cells less than 1 produces a warning
	 */
	TEST_FIXTURE( HistoFixture, ConstructionDestruction )
	{
		data::Label label = "TestHistoConstructionUserSim";
		std::auto_ptr< Histogram > histogram( new Histogram( sim, label, 0, 1, 1 ) );
		CHECK_EQUAL( label, histogram->getLabel() );
	}

	/**
	 * @test odemx::Histo::reset()
	 *
	 * Expected function call effects:
	 * @li all data cell counters are reset to \c 0
	 */
	TEST_FIXTURE( HistoFixture, Reset )
	{
		base::SimTime simTime = 0;
		histogram.update( 1 );
		histogram.update( 3 );
		histogram.update( 5 );

		const Histogram::CellVec& data = histogram.getData();
		histogram.reset( simTime );

		Histogram::CellVec::const_iterator i;
		for( i = data.begin(); i!= data.end(); ++i )
		{
			CHECK_EQUAL( (std::size_t) 0, i->count );
		}
	}

	/**
	 * @test odemx::Histo::update(double)
	 *
	 * Expected function call effects:
	 * @li the cell counter corresponding to the update-value is incremented
	 */
	TEST_FIXTURE( HistoFixture, Update )
	{
		histogram.update( -0.1 ); // less than lower limit
		histogram.update( 0.5 );
		histogram.update( 1.5 );
		histogram.update( 2.5 );
		histogram.update( 3.5 );
		histogram.update( 4.5 );
		histogram.update( 5.5 ); // greater than upper limit

		const Histogram::CellVec& data = histogram.getData();

		CHECK_EQUAL( (std::size_t) 1, data[0].count );
		CHECK_EQUAL( (std::size_t) 1, data[1].count );
		CHECK_EQUAL( (std::size_t) 1, data[2].count );
		CHECK_EQUAL( (std::size_t) 1, data[3].count );
		CHECK_EQUAL( (std::size_t) 1, data[4].count );
		CHECK_EQUAL( (std::size_t) 1, data[5].count );
		CHECK_EQUAL( (std::size_t) 1, data[6].count );
	}

	/**
	 * @test odemx::Histo::report(Report*)
	 *
	 * Expected function call effects:
	 * @li the report table contains correct values
	 */
	TEST_FIXTURE( HistoFixture, Report )
	{
		base::SimTime simTime = 25;

		histogram.reset( simTime ); // non-0 reset time
		double min = 1.2;
		double max = 3.4;
		histogram.update( min );
		histogram.update( max );

		double mean = histogram.getMean();
		double deviation = std::sqrt(
				( ( min - mean ) * ( min - mean )
				+ ( max - mean ) * ( max - mean ) ) / 2 );

		CHECK_EQUAL( (std::size_t) 2, histogram.getUpdateCount() );
		CHECK_EQUAL( min, histogram.getMin() );
		CHECK_EQUAL( max, histogram.getMax() );
		CHECK_EQUAL( ( min + max ) / 2, mean );
		CHECK_CLOSE( deviation, histogram.getStandardDeviation(), 0.000000000000001 );

		reporter.addReportProducer( histogram );
		reporter.generateReport();
		CHECK( reporter.processedTables );

		// check the first table
		CHECK_EQUAL( histogram.getLabel(), reporter.allTableContent[0][0] );
		CHECK_EQUAL( toString( histogram.getResetTime() ), reporter.allTableContent[0][1] );
		CHECK_EQUAL( toString( histogram.getUpdateCount() ), reporter.allTableContent[0][2] );
		CHECK_EQUAL( toString( lower ), reporter.allTableContent[0][3] );
		CHECK_EQUAL( toString( upper ), reporter.allTableContent[0][4] );
		CHECK_EQUAL( toString( cells + 2 ), reporter.allTableContent[0][5] );
		CHECK_EQUAL( toString( histogram.getMin() ), reporter.allTableContent[0][6] );
		CHECK_EQUAL( toString( histogram.getMax() ), reporter.allTableContent[0][7] );
		CHECK_EQUAL( toString( histogram.getMean() ), reporter.allTableContent[0][8] );
		CHECK_EQUAL( toString( histogram.getStandardDeviation() ), reporter.allTableContent[0][9] );

		// check second table, line 1
		CHECK_EQUAL( toString( lower - 1 ), reporter.allTableContent[1][0] ); // lower cell limit
		CHECK_EQUAL( toString( lower ), reporter.allTableContent[1][1] ); // upper cell limit
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][2] ); // cell hit counter
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][3] ); // hit percentage
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][4] ); // bar display value
		// line 2
		CHECK_EQUAL( toString( lower ), reporter.allTableContent[1][5] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 1 ), reporter.allTableContent[1][6] ); // upper cell limit
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][7] ); // cell hit counter
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][8] ); // hit percentage
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][9] ); // bar display value
		// line 3
		CHECK_EQUAL( toString( lower + 1 ), reporter.allTableContent[1][10] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 2 ), reporter.allTableContent[1][11] ); // upper cell limit
		CHECK_EQUAL( toString( 1 ), reporter.allTableContent[1][12] ); // cell hit counter
		CHECK_EQUAL( toString( 50 ), reporter.allTableContent[1][13] ); // hit percentage
		CHECK_EQUAL( toString( 100 ), reporter.allTableContent[1][14] ); // bar display value
		// line 4
		CHECK_EQUAL( toString( lower + 2 ), reporter.allTableContent[1][15] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 3 ), reporter.allTableContent[1][16] ); // upper cell limit
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][17] ); // cell hit counter
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][18] ); // hit percentage
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][19] ); // bar display value
		// line 5
		CHECK_EQUAL( toString( lower + 3 ), reporter.allTableContent[1][20] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 4 ), reporter.allTableContent[1][21] ); // upper cell limit
		CHECK_EQUAL( toString( 1 ), reporter.allTableContent[1][22] ); // cell hit counter
		CHECK_EQUAL( toString( 50 ), reporter.allTableContent[1][23] ); // hit percentage
		CHECK_EQUAL( toString( 100 ), reporter.allTableContent[1][24] ); // bar display value
		// line 6
		CHECK_EQUAL( toString( lower + 4 ), reporter.allTableContent[1][25] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 5 ), reporter.allTableContent[1][26] ); // upper cell limit
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][27] ); // cell hit counter
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][28] ); // hit percentage
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][29] ); // bar display value
		// line 7
		CHECK_EQUAL( toString( lower + 5 ), reporter.allTableContent[1][30] ); // lower cell limit
		CHECK_EQUAL( toString( lower + 6 ), reporter.allTableContent[1][31] ); // upper cell limit
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][32] ); // cell hit counter
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][33] ); // hit percentage
		CHECK_EQUAL( toString( 0 ), reporter.allTableContent[1][34] ); // bar display value

	}

/// @cond DOXYGEN_SKIP
}
/// @endcond
