#include "testcommon/testcommon.h"
#include "spcore/basetypesimpl.h"

using namespace spcore;
using namespace std;

class Container : public spcore::CComponentAdapter
{
public:
	Container(const char *name) : CComponentAdapter(name)
	{	
		m_data= 0;
		m_lis1= new MyListener1 (*this);
		assert (m_lis1);
		m_iPin1= getSpCoreRuntime()->CreateInputPin("my_in_pin", "int", *m_lis1);
		assert (m_iPin1);
		m_oPin1= getSpCoreRuntime()->CreateOutputPin("my_out_pin_1", "int");
		assert (m_oPin1);
		int retval= RegisterInputPin (*m_iPin1);
		assert (retval== 0);
		retval= RegisterOutputPin (*m_oPin1);
		assert (retval== 0);
	}
	~Container()
	{
	}
	string GetTypeName(void) const
	{
		return "Container";
	}
private:
	// Listener
	class MyListener1 : public CIntListener<Container> {
	public:
		MyListener1 (Container& c) : CIntListener<Container>(c) {}
		virtual void Update(const CTypeInt & message) {
			//this->m_component->m_data++;
			cout << "MyListener1: " << message.getValue() << endl;
		}
	};	

	int m_data;
	MyListener1* m_lis1;
	IInputPin* m_iPin1;
	IOutputPin* m_oPin1;
			
public:		
	void DoTest()
	{
		m_oPin1->Attach (*m_iPin1);
		CTypeInt* i= CTypeInt::CreateInstance();
		assert (i);
		i->setValue(12);
		m_oPin1->Send (*i);
		i->Release();
	}	
};

void TestContainer()
{
	Container* cont= new Container("my_cont");
	cont->DoTest();

	IIterator<IInputPin*>* ii= cont->GetInputPins();
	for (ii->First(); !ii->IsDone(); ii->Next()) {
		IInputPin* ip= ii->CurrentItem();
		cout << "Input pin: " << ip->GetName() << " TypeID: " << ip->GetTypeID() << " Type name: " << ip->GetTypeName() << endl;
	}
	ii->Release();


	IIterator<IOutputPin*>* io= cont->GetOutputPins();
	for (io->First(); !io->IsDone(); io->Next()) {
		IOutputPin* op= io->CurrentItem();
		cout << "Input pin: " << op->GetName() << " TypeID: " << op->GetTypeID() << " Type name: " << op->GetTypeName() << endl;
	}
	io->Release();

	delete cont;
}

void TestGraph()
{
	ICoreRuntime* core= getSpCoreRuntime();
	IGraphManager* mgr= core->CreateGraphManager();	assert (mgr);

	// Trying to register a new component should work
	IComponent* cont= new Container("my_cont");
	int retval= mgr->RegisterComponent(*cont); assert (retval== 0);
	
	// Trying to register again the same component should fail
	retval= mgr->RegisterComponent(*cont); assert (retval!= 0);

	// Trying to register a new component with the same name should fail
	IComponent* tmpCont= new Container("my_cont");
	retval= mgr->RegisterComponent(*tmpCont); assert (retval!= 0);
	tmpCont->Release();

	// Trying to register a new component should work
	IComponent* adder= core->CreateComponent(COMPONENT_ADD_INT_NAME, "firstAdder"); assert (adder);
	retval= mgr->RegisterComponent(*adder); assert (retval== 0);

	// Dump graph manager status
	DumpGraphManager(*mgr);

	// Attach pins by number
	//retval= mgr->Attach (adder, (unsigned int) 0, cont, (unsigned int) 0); assert (retval== 0);
	retval= mgr->Attach (adder, "result", cont, "my_in_pin"); assert (retval== 0);

	// Obtain adder input pins for testing
	IteratorPtr<IInputPin*> it(adder->GetInputPins());
	it->First();
	CInputPin* iPinA= static_cast<CInputPin*>(it->CurrentItem());
	it->Next(); assert (!it->IsDone());
	CInputPin* iPinB= static_cast<CInputPin*>(it->CurrentItem());
	CTypeInt *myInt= CTypeInt::CreateInstance(); assert (myInt);

	// Perform addition
	myInt->setValue(5);
	//iPinB->GetListener()->Update(*myInt);
	iPinB->Update(*myInt);
	myInt->setValue(3);
	//iPinA->GetListener()->Update(*myInt);
	iPinA->Update(*myInt);


	myInt->Release();
}


int main (int, char**)
{
	//RegisterModules();

	DumpCoreRuntime();

	//TestContainer();
	
	TestGraph();


	// Cleanup
	freeSpCoreRuntime();
	
	DUMP_LEAKS

//	getchar();
	return 0;
}