/////////////////////////////////////////////////////////////////////////////
// Name:        test_mod_camera_rois.cpp
// Author:      Cesar Mauri Loba
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
// 
//  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////


#include "spcore/coreruntime.h"
#include "testcommon/testcommon.h"
#include "3rdparty/nvwa/debug_new.h"

#include "mod_camera/roitype.h"

#include <ostream>
#include <sstream>
#include <iostream>
#include <math.h>

using namespace spcore;
using namespace mod_camera;
using namespace std;

void dump_roi ( const CTypeROI& roi,  std::ostream& stream= std::cout, char const * tab = "")
{
	stream << tab << "X:" << roi.GetX() << std::endl;
	stream << tab << "Y:" << roi.GetY() << std::endl;
	stream << tab << "Width:" << roi.GetWidth() << std::endl;
	stream << tab << "Height:" << roi.GetHeight() << std::endl;
	stream << tab << "UseDirection:" << roi.GetUseDirection() << std::endl;
	stream << tab << "Direction:" << roi.GetDirection() << std::endl;
	stream << tab << "IsVisible:" << roi.GetIsVisible() << std::endl;
	stream << tab << "IsEditable:" << roi.GetIsEditable() << std::endl;
	stream << tab << "RegistrationId:" << roi.GetRegistrationId() << std::endl;

	SmartPtr<spcore::IIterator<spcore::CTypeAny*> > it= roi.QueryChildren();
	if (it.get()== NULL) ExitErr("CTypeROI cannot returna a NULL iterator");

	string new_tab(tab);
	new_tab.append("\t");
	for (; !it->IsDone(); it->Next()) {
		CTypeROI* child= sptype_dynamic_cast<CTypeROI>( it->CurrentItem());
		if (!child) ExitErr("non CTypeROI type children found!");
		dump_roi(*child, stream, new_tab.c_str());
	}
}

bool areSimilar (float a, float b)
{
	if (a== b) return true;

	if (fabs(a-b)< 0.0000001f) return true;

	return false;
}

void test_rois()
{
	ICoreRuntime* cr= getSpCoreRuntime();

	int retval= cr->LoadModule("mod_camera");
	DumpCoreRuntime(cr);
	if (retval!= 0) 
		ExitErr("error loading mod_camera");

	//
	// perform some foo tests
	//

	SmartPtr<CTypeROI> roi1= CTypeROI::CreateInstance();
	roi1->SetUseDirection(true);	
	roi1->SetDirection(10.0f);
	roi1->SetIsVisible(true);	
	roi1->SetIsEditable(true);
	roi1->SetRegistrationId(10000);
	dump_roi (*roi1);

	if (!areSimilar(roi1->GetX(), 0.0f) || 
		!areSimilar(roi1->GetY(), 0.0f) || 
		!areSimilar(roi1->GetWidth(), 1.0f) || 
		!areSimilar(roi1->GetHeight(), 1.0f)) ExitErr("ROI calculation error");
	
	// Without changing size, ROI shouldn't change
	roi1->SetCenter(0.8f, 0.8f);
	if (!areSimilar(roi1->GetX(), 0.0f) || 
		!areSimilar(roi1->GetY(), 0.0f) || 
		!areSimilar(roi1->GetWidth(), 1.0f) || 
		!areSimilar(roi1->GetHeight(), 1.0f)) ExitErr("ROI calculation error");
	
	// Changing size only affects size
	roi1->SetSize (0.5f, 0.5f);
	if (!areSimilar(roi1->GetX(), 0.0f) || 
		!areSimilar(roi1->GetY(), 0.0f) || 
		!areSimilar(roi1->GetWidth(), 0.5f) || 
		!areSimilar(roi1->GetHeight(), 0.5f)) ExitErr("ROI calculation error");
	
	roi1->SetCenter(0.9f, 0.9f);
	if (!areSimilar(roi1->GetX(), 0.5f) || 
		!areSimilar(roi1->GetY(), 0.5f) || 
		!areSimilar(roi1->GetWidth(), 0.5f) || 
		!areSimilar(roi1->GetHeight(), 0.5f)) ExitErr("ROI calculation error");
	
	roi1->SetCenter(-0.9f, -0.9f);
	if (!areSimilar(roi1->GetX(), 0.0f) || 
		!areSimilar(roi1->GetY(), 0.0f) || 
		!areSimilar(roi1->GetWidth(), 0.5f) || 
		!areSimilar(roi1->GetHeight(), 0.5f)) ExitErr("ROI calculation error");
	dump_roi (*roi1);

	//
	// Composite
	//
	roi1->SetCenter(0.6f, 0.6f);
	SmartPtr<CTypeInt> int1= CTypeInt::CreateInstance();
	SmartPtr<CTypeROI> roi2= CTypeROI::CreateInstance();
	SmartPtr<CTypeROI> roi3= CTypeROI::CreateInstance();
	SmartPtr<CTypeROI> roi4= CTypeROI::CreateInstance();

	if (roi1->AddChild(int1)== 0) ExitErr("non CTypeROI non allowed");
	if (roi1->AddChild(roi2)== -1) ExitErr("AddChild failed");
	if (roi1->AddChild(roi3)== -1) ExitErr("AddChild failed");
	if (roi1->AddChild(roi3)== 0) ExitErr("adding the same child again not allowed");
	if (roi2->AddChild(roi4)== -1) ExitErr("AddChild failed");

	// check copy
	SmartPtr<CTypeROI> roi5= CTypeROI::CreateInstance();

	{
		SmartPtr<CTypeAny> tmp= roi1->Clone(roi5.get(), true);
		assert (tmp.get()== roi5.get());
	}

	std::stringstream result1;
	std::stringstream result5;

	dump_roi(*roi1, result1);
	dump_roi(*roi5, result5);

	if (result1.str().compare(result5.str())!= 0) ExitErr("composite copy error. results differ");
	
	SmartPtr<CTypeROI> roi6= CTypeROI::CreateInstance();
	SmartPtr<CTypeROI> roi7= CTypeROI::CreateInstance();

	if (roi5->AddChild(roi6)== -1) ExitErr("AddChild failed");
	if (roi5->AddChild(roi7)== -1) ExitErr("AddChild failed");

	{
		SmartPtr<CTypeAny> tmp= roi1->Clone(roi5.get(), true);
		assert (tmp.get()== roi5.get());
	}

	dump_roi(*roi1, result1);
	dump_roi(*roi5, result5);

	if (result1.str().compare(result5.str())!= 0) ExitErr("composite copy error. results differ");
}


// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------

int main(int, char *[]) {
	
	// Initialize spcore
	ICoreRuntime* cr= getSpCoreRuntime();
	if (!cr) return false;

	test_rois();
	
	// Free spcore
	freeSpCoreRuntime();

	// If execution reaches this => all tests ok
	return 0;
}
