/*
 * SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of Synopsys,
 * Inc., and is fully protected under copyright and trade secret laws. You may
 * not view, use, disclose, copy, or distribute this file or any information
 * contained herein except pursuant to a valid written license from Synopsys.
 */

#include <fstream>
#include <iomanip>
#include "../getCurrentTime2.h"
#include <base/ssetypes.h>
#include <base/transform.h>
#include "transform2.h"

#ifdef WIN32
#include <process.h>
#endif

//
//	Forward declarations.
//
void print_result( double, double );

#define SCALE 100

////////////////////////////////////////////////////////////////////////////
//
//	The sample transformations.
//
struct tsmpl_s
{
double xloc;
double yloc;
double mag;
double rot;
bool flip;
}
tsmpl[] =
{
{0,0,1,0,0},
{0,0,1,90,0},
{0,0,1,180,0},
{0,0,1,270,0},
{0,0,1,0,1},
{0,0,1,90,1},
{0,0,1,180,1},
{0,0,1,270,1},

{1000,1000,1,0,0},
{1000,1000,1,90,0},
{1000,1000,1,180,0},
{1000,1000,1,270,0},
{1000,1000,1,0,1},
{1000,1000,1,90,1},
{1000,1000,1,180,1},
{1000,1000,1,270,1},

{1000,1000,10,0,0},
{1000,1000,10,90,0},
{1000,1000,10,180,0},
{1000,1000,10,270,0},
{1000,1000,10,0,1},
{1000,1000,10,90,1},
{1000,1000,10,180,1},
{1000,1000,10,270,1},

{1000,1000,10,0+45,0},
{1000,1000,10,90+45,0},
{1000,1000,10,180+45,0},
{1000,1000,10,270+45,0},
{1000,1000,10,0+45,1},
{1000,1000,10,90+45,1},
{1000,1000,10,180+45,1},
{1000,1000,10,270+45,1},

{1000,1000,10,0+30,0},
{1000,1000,10,90+30,1},

{1000,1000,10,0+60,0},
{1000,1000,10,90+60,1},

{1000,1000,10,123,1},
{1000,1000,10,321,1},
{1000,1000,10,17,1},
{1000,1000,10,71,1},

{1000,1000,1,360,0},
{0,0,1,0,0}
};
#define tsmpl_count (sizeof(tsmpl)/sizeof(tsmpl_s))

template <class T>
T mktrans( int i )
{
	assert( i < tsmpl_count );
	return T(
			tsmpl[i].xloc,
			tsmpl[i].yloc,
			tsmpl[i].flip != 0,
			tsmpl[i].rot,
			tsmpl[i].mag
	);
}

////////////////////////////////////////////////////////////////////////////
//
//	The sample rectangles.
//
struct rsmpl_s
{
double l;
double b;
double r;
double t;
}
rsmpl[] =
{
{10000,10000,100000,100000},
{1000,1000,1000,1000},
{0,0,1000,1000}
};
#define rsmpl_count (sizeof(rsmpl)/sizeof(rsmpl_s))

template <class C>
pod::rectangle<C> mkrect( int i )
{
	assert( i < rsmpl_count );
	return pod::rectangle<C>( 
			C(rsmpl[i].l),
			C(rsmpl[i].b),
			C(rsmpl[i].r),
			C(rsmpl[i].t)
	);
}

////////////////////////////////////////////////////////////////////////////
//
//	The sample points.
//
struct psmpl_s
{
double x;
double y;
}
psmpl[] =
{
{100000,100000},
{10000,10000},
{1000,1000},
{1,1},
{0,0}
};
#define psmpl_count (sizeof(psmpl)/sizeof(psmpl_s))

template <class C>
pod::point<C> mkpt( int i )
{
	assert( i < psmpl_count );
	return pod::point<C>( 
			C(psmpl[i].x),
			C(psmpl[i].y)
	);
}

////////////////////////////////////////////////////////////////////////////
//
//	log.
//
std::ofstream out;

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

template< class T, class P, int nProbs >
class modify
{
	T trns;
	P src;
	P dest;
	
public:
	modify( const T& t, const P& p )
	{
		trns = t;
		src = p;
	}
	
	__forceinline void operator() ()
	{
		for( int i = nProbs; i; --i )
			trns.modify( src, dest );
	}
};

template< class T, class P, int nProbs >
class modify2
{
	T trns;
	P src;
	
public:
	modify2( const T& t, const P& p )
	{
		trns = t;
		src = p;
	}
	
	__forceinline void operator() ()
	{
		for( int i = nProbs; i; --i )
		{
			volatile P p = trns.modify( src );
		}
	}
};

template<	class P,
			int nProbes >
void test( const base::transform& t1, const base2::transform& t2, const P& p )
{
	const int n = SCALE;

	typedef modify<base::transform,P,n> modify1_type;
	double dblMin1 = mesure<modify1_type>( modify1_type( t1, p ), nProbes );
	dblMin1 /= n;

	typedef modify<base2::transform,P,n> modify2_type;
	double dblMin2 = mesure<modify2_type>( modify2_type( t2, p ), nProbes );
	dblMin2 /= n;

	typedef modify2<base::transform,P,n> modify21_type;
	double dblMin21 = mesure<modify21_type>( modify21_type( t1, p ), nProbes );
	dblMin21 /= n;

	typedef modify2<base2::transform,P,n> modify22_type;
	double dblMin22 = mesure<modify22_type>( modify22_type( t2, p ), nProbes );
	dblMin22 /= n;

	print_result( dblMin1, dblMin2 );
	print_result( dblMin21, dblMin22 );
}

template< class P, int nProbes >
void testTrans( int i, const P& p )
{
	out << "<tr>";
#if 0
	out << "<td>rot:" << tsmpl[i].rot 
			<< " flip:" << tsmpl[i].flip
			<< " mag:" << tsmpl[i].mag
			<< " x:" << tsmpl[i].xloc
			<< " y:" << tsmpl[i].yloc
			  << "</td>";
#endif
	test<P,nProbes>(mktrans<base::transform>(i),
					mktrans<base2::transform>(i),
					p);
	out << "</tr>" << std::endl;
}

template<	class P,
			int nProbes >
void testAllTrans( const P& p )
{
	for ( int i = 0; i < tsmpl_count; ++i )
		testTrans<P,nProbes>(i,p);
}

template<	class C,
			int nProbes >
void testAllPt()
{
	for ( int i = 0; i < psmpl_count; ++i )
		testAllTrans<pod::point<C>,nProbes>(mkpt<C>(i));
}

template<	class C,
			int nProbes >
void testAllRect()
{
	for ( int i = 0; i < rsmpl_count; ++i )
		testAllTrans<pod::rectangle<C>,nProbes>(mkrect<C>(i));
}



////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

template< class T, int nProbs >
class mult
{
	T trns;
	T trns2;
	T trns3;
	
public:
	mult( const T& t, const T& t2 )
	{
		trns = t;
		trns2 = t2;
	}
	
	__forceinline void operator() ()
	{
		for( int i = nProbs; i; --i )
			trns.mult( trns2, trns3 );
	}
};

template< class T, int nProbs >
class mult2
{
	T trns;
	T trns2;
	
public:
	mult2( const T& t, const T& t2 )
	{
		trns = t;
		trns2 = t2;
	}
	
	__forceinline void operator() ()
	{
		for( int i = nProbs; i; --i )
		{
			volatile T t = trns * trns2;
		}
	}
};

template< int nProbes >
void testMult( const base::transform& t11, const base::transform& t12,
				const base2::transform& t21, const base2::transform& t22 )
{
	const int n = SCALE;

	{
	typedef mult<base::transform,n> mult1_type;
	double dblMin1 = mesure<mult1_type>( mult1_type( t11, t12 ), nProbes );
	dblMin1 /= n;

	typedef mult<base2::transform,n> mult2_type;
	double dblMin2 = mesure<mult2_type>( mult2_type( t21, t22 ), nProbes );
	dblMin2 /= n;

	print_result( dblMin1, dblMin2 );
	}

	{
	typedef mult2<base::transform,n> mult1_type;
	double dblMin1 = mesure<mult1_type>( mult1_type( t11, t12 ), nProbes );
	dblMin1 /= n;

	typedef mult2<base2::transform,n> mult2_type;
	double dblMin2 = mesure<mult2_type>( mult2_type( t21, t22 ), nProbes );
	dblMin2 /= n;

	print_result( dblMin1, dblMin2 );
	}
}

template< int nProbes >
void testTrans1x1( int i, int j )
{
	out << "<tr>";
#if 0
	out << "<td>rot:" << tsmpl[i].rot 
			<< " flip:" << tsmpl[i].flip
			<< " mag:" << tsmpl[i].mag
			<< " x:" << tsmpl[i].xloc
			<< " y:" << tsmpl[i].yloc
			  << "</td>";
	out << "<td>rot:" << tsmpl[j].rot 
			<< " flip:" << tsmpl[j].flip
			<< " mag:" << tsmpl[j].mag
			<< " x:" << tsmpl[j].xloc
			<< " y:" << tsmpl[j].yloc
			  << "</td>";
#endif
	testMult<nProbes>(mktrans<base::transform>(i), mktrans<base::transform>(j),
					mktrans<base2::transform>(i), mktrans<base2::transform>(j) );
	out << "</tr>" << std::endl;
}

template< int nProbes >
void testAllTrans1x1()
{
	for ( int i = 0; i < tsmpl_count; ++i )
	for ( int j = 0; j < tsmpl_count; ++j )
		testTrans1x1<nProbes>(i,j);
}

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

template< class T, int nProbs >
class inverse
{
	T trns;
	T trns2;
	
public:
	inverse( const T& t )
	{
		trns = t;
	}
	
	__forceinline void operator() ()
	{
		for( int i = nProbs; i; --i )
			trns2 = trns.getInverse();
	}
};

template< int nProbes >
void testInverse( const base::transform& t1, const base2::transform& t2 )
{
	const int n = SCALE;

	typedef inverse<base::transform,n> inverse1_type;
	double dblMin1 = mesure<inverse1_type>( inverse1_type( t1 ), nProbes );
	dblMin1 /= n;

	typedef inverse<base2::transform,n> inverse2_type;
	double dblMin2 = mesure<inverse2_type>( inverse2_type( t2 ), nProbes );
	dblMin2 /= n;
	
	print_result( dblMin1, dblMin2 );
}

template< int nProbes >
void testTransInverse( int i )
{
	out << "<tr>";
#if 0
	out << "<td>rot:" << tsmpl[i].rot 
			<< " flip:" << tsmpl[i].flip
			<< " mag:" << tsmpl[i].mag
			<< " x:" << tsmpl[i].xloc
			<< " y:" << tsmpl[i].yloc
			  << "</td>";
	out << "<td>rot:" << tsmpl[j].rot 
			<< " flip:" << tsmpl[j].flip
			<< " mag:" << tsmpl[j].mag
			<< " x:" << tsmpl[j].xloc
			<< " y:" << tsmpl[j].yloc
			  << "</td>";
#endif
	testInverse<nProbes>(mktrans<base::transform>(i),
					mktrans<base2::transform>(i) );
	out << "</tr>" << std::endl;
}

template< int nProbes >
void testAllTransInverse()
{
	for ( int i = 0; i < tsmpl_count; ++i )
		testTransInverse<nProbes>(i);
}

////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////


void print_result( double time1, double time2 )
{
	out << "<td width=300 align=right>" << std::setiosflags( std::ios::fixed ) << std::setprecision( 12 ) << time1 
		<< "</td><td width=300 align=right>" << time2 
		<< "</td><td width=300 align=right>" << std::setprecision( 6 ) << (1. - time2/time1 )*100 
		<< "%</td>";
//	printf( "t1 %f   t2 %f   fast %.3f%%\n", dblDiff1/nProbes, dblDiff2/nProbes, (dblDiff1/dblDiff2-1.)*100, nProbes );
}

template< int nProbes >
void testTransform()
{
	out << "<a href=\"#_1\">pod::point&ltint32&gt</a><br>"
		<< "<a href=\"#_2\">pod::point&ltint64&gt</a><br>"
		<< "<a href=\"#_3\">pod::point&ltdouble&gt</a><br>"
		<< "<a href=\"#_4\">pod::rectangle&ltint32&gt</a><br>"
		<< "<a href=\"#_5\">pod::rectangle&ltint64&gt</a><br>"
		<< "<a href=\"#_6\">pod::rectangle&ltdouble&gt</a><br>"
		<< "<a href=\"#_7\">trans*trans</a><br>"
		<< "<a href=\"#_8\">trans<sup>-1</sup></a><br><br><br>";
	
	std::cout << "pod::point<int32>" << std::endl;
	out << "<a name=\"#_1\"></a><table border=1><thead><H3>pod::point&ltint32&gt</h3></thead>" << std::endl;
	testAllPt<int32,nProbes>();
	out << "</table><P>";

	std::cout << "pod::point<int64>" << std::endl;
	out << "<a name=\"#_2\"></a><table border=1><thead><H3>pod::point&ltint64&gt</H3></thead>" << std::endl;
	testAllPt<int64,nProbes>();
	out << "</table><P>";

	std::cout << "pod::point<double>" << std::endl;
	out << "<a name=\"#_3\"></a><table border=1><thead><H3>pod::point&ltdouble&gt</H3></thead>" << std::endl;
	testAllPt<double,nProbes>();
	out << "</table><P>";

	std::cout << "pod::rectangle<int32>" << std::endl;
	out << "<a name=\"#_4\"></a><table border=1><thead><H3>pod::rectangle&ltint32&gt</H3></thead>" << std::endl;
	testAllRect<int32,nProbes>();
	out << "</table><P>";

	std::cout << "pod::rectangle<int64>" << std::endl;
	out << "<a name=\"#_5\"></a><table border=1><thead><H3>pod::rectangle&ltint64&gt</H3></thead>" << std::endl;
	testAllRect<int64,nProbes>();
	out << "</table><P>";

	std::cout << "pod::rectangle<double>" << std::endl;
	out << "<a name=\"#_6\"></a><table border=1><thead><H3>pod::rectangle&ltdouble&gt</H3></thead>" << std::endl;
	testAllRect<double,nProbes>();
	out << "</table><P>";

	std::cout << "trans*trans" << std::endl;
	out << "<a name=\"#_7\"></a><table border=1><thead><H3>trans*trans</H3></thead>" << std::endl;
	testAllTrans1x1<nProbes>();
	out << "</table><P>";

	std::cout << "inverse trans" << std::endl;
	out << "<a name=\"#_8\"></a><table border=1><thead><H3>trans<sup>-1</sup></H3></thead>" << std::endl;
	testAllTransInverse<nProbes>();
	out << "</table><P>";
}

void main ( )
{
	out.open( "result.html" );
	out << "<html><head><title></title></head><body><font face=\"courier\">" << std::endl;
	
	//	Init
	perf_init();
	base::transform::initFnTables();
	base2::transform::initFnTables();

	testTransform<100>();

	out << "</body></html>";
	out.close();
	
#ifdef WIN32
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	memset( &pi, 0, sizeof( pi ) );
	memset( &si, 0, sizeof( si ) );
	BOOL b = CreateProcess( L"C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE", L"IEXPLORE.EXE file:///D:/work/prj/test/testTransform/result.html", 0, 0, false, 0, 0, 0, &si, &pi );
#endif
}