/////////////////////////////////////////////////////////////////////////////
// File:        basictypesimpl.cpp
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Copyright:   (C) 2010 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 "commoncomponents.h"
#include "timecomponents.h"

#include "spcore/basictypes.h"
#include "spcore/pin.h"
#include "spcore/pinimpl.h"
#include "spcore/module.h"
#include "spcore/component.h"
#include "spcore/conversion.h"
#include <string>
#include <exception>
using namespace std;

namespace spcore {

/*
	Template class for unary operations

	TODO: use this for all unary operators
*/
template <typename CONTENTS, typename OPTYPE, typename RETYPE= OPTYPE>
class UnaryOperation : public CComponentAdapter, public CONTENTS {
  public:
	virtual const char* GetTypeName() const { return CONTENTS::getTypeName(); }
    UnaryOperation(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {

		// Input pins
  		if (RegisterInputPin(*SmartPtr<InputPin1>(new InputPin1("a", *this), false))!= 0)
			throw std::runtime_error("error creating input pin a");

		// Output pin
		m_oResult= RETYPE::CreateOutputPin("result");
		assert (m_oResult);
		if (RegisterOutputPin(*m_oResult)!= 0)
			throw std::runtime_error("error creating output pin");

		// Result
		m_result= RETYPE::CreateInstance(); assert (m_result);
	}

  private:
	virtual ~UnaryOperation() {}

	class InputPin1 : public CInputPinWriteOnly<OPTYPE, UnaryOperation > {
	public:
		InputPin1 (const char * name, UnaryOperation & component)
		: CInputPinWriteOnly<OPTYPE, UnaryOperation >(name, component) {}

		virtual int DoSend(const OPTYPE & message) {
			this->m_component->m_result->setValue(this->m_component->Compute (message.getValue()));
			this->m_component->m_oResult->Send (this->m_component->m_result);
			return 0;
		}
	};	

  private:
    // Atributes
	SmartPtr<IOutputPin> m_oResult;
    SmartPtr<RETYPE> m_result;
};


/*
	Template class for binary operations
*/
template <typename CONTENTS, typename OPTYPE, typename RETYPE= OPTYPE>
class BinaryOperation : public CComponentAdapter, public CONTENTS {
  public:
	virtual const char* GetTypeName() const { return CONTENTS::getTypeName(); }
    BinaryOperation(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {

		if (argc) {
			int i= 0;
			for (; i< argc; ++i) if (strcmp("-v", argv[i])== 0) break;

			if (i< argc) {
				++i;
				if (i>= argc) 
					throw std::runtime_error("No value found for parameter -v");

				// Found				
				this->ParseOperandB(argv[i]);
			}
		}

		// Input pins
  		if (RegisterInputPin(*SmartPtr<InputPin1>(new InputPin1("a", *this), false))!= 0)
			throw std::runtime_error("error creating input pin a");
   		if (RegisterInputPin(*SmartPtr<InputPin2>(new InputPin2("b", *this), false))!= 0)
			throw std::runtime_error("error creating input pin b");

		// Output pin
		m_oResult= RETYPE::CreateOutputPin("result");
		assert (m_oResult);
		if (RegisterOutputPin(*m_oResult)!= 0)
			throw std::runtime_error("error creating output pin");

		// Result
		m_result= RETYPE::CreateInstance(); assert (m_result);
	}

  private:
	virtual ~BinaryOperation() {}

	class InputPin1 : public CInputPinWriteOnly<OPTYPE, BinaryOperation > {
	public:
		InputPin1 (const char * name, BinaryOperation & component)
		: CInputPinWriteOnly<OPTYPE, BinaryOperation >(name, component) {}

		virtual int DoSend(const OPTYPE & message) {
			this->m_component->m_result->setValue(this->m_component->SetOperandA (message.getValue()));
			this->m_component->m_oResult->Send (this->m_component->m_result);
			return 0;
		}
	};

	class InputPin2 : public CInputPinReadWrite<OPTYPE, BinaryOperation> {
	public:
		InputPin2 (const char * name, BinaryOperation & component)
		: CInputPinReadWrite<OPTYPE, BinaryOperation>(name, component) {}

		virtual int DoSend(const OPTYPE & message) {
			this->m_component->SetOperandB(message.getValue());
			return 0;
		}

		virtual SmartPtr<OPTYPE> DoRead() const {
			SmartPtr<OPTYPE> result= OPTYPE::CreateInstance();
			result->setValue (this->m_component->GetOperandB());
			return result;
		}
	};

  private:
    // Atributes
	SmartPtr<IOutputPin> m_oResult;
    SmartPtr<RETYPE> m_result;
};


// Integer addition
class AddIntContents {
public:
	static const char* getTypeName() { return "iadd"; }
	AddIntContents() : m_b(0) { }
	int SetOperandA (int a) { return a + m_b; }
	void SetOperandB (int b) {	m_b= b; }
	int GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		int val= m_b;
		StrToInt(operand, &val);
		SetOperandB(val);
	}

private:
	int m_b;
};
typedef ComponentFactory<BinaryOperation<AddIntContents, CTypeInt> > AddIntFactory;

// Integer substraction
class SubIntContents {
public:
	static const char* getTypeName() { return "isub"; }
	SubIntContents() : m_b(0) { }
	int SetOperandA (int a) { return a - m_b; }
	void SetOperandB (int b) {	m_b= b; }
	int GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		int val= m_b;
		StrToInt (operand, &val);
		SetOperandB(val);
	}

private:
	int m_b;
};
typedef ComponentFactory<BinaryOperation<SubIntContents, CTypeInt> > SubIntFactory;

// Integer multiplication
class MulIntContents {
public:
	static const char* getTypeName() { return "imul"; }
	MulIntContents() : m_b(1) { }
	int SetOperandA (int a) { return a * m_b; }
	void SetOperandB (int b) {	m_b= b; }
	int GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		int val= m_b;
		StrToInt (operand, &val);
		SetOperandB(val);
	}

private:
	int m_b;
};
typedef ComponentFactory<BinaryOperation<MulIntContents, CTypeInt> > MulIntFactory;

// Integer division
class DivIntContents {
public:
	static const char* getTypeName() { return "idiv"; }
	DivIntContents() : m_b(1) { }
	int SetOperandA (int a) { return a / m_b; }
	void SetOperandB (int b) {
		if (b== 0)
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, "intdiv: not stored 0 as divisor", "spcore");
		else
			m_b= b;
	}
	int GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		int val= m_b;
		StrToInt (operand, &val);
		SetOperandB(val);
	}

private:
	int m_b;
};
typedef ComponentFactory<BinaryOperation<DivIntContents, CTypeInt> > DivIntFactory;

// Float addition
class AddFloatContents {
public:
	static const char* getTypeName() { return "fadd"; }
	AddFloatContents() : m_b(0) { }
	float SetOperandA (float a) { return a + m_b; }
	void SetOperandB (float b) {	m_b= b; }
	float GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		float val= m_b;
		StrToFloat (operand, &val);
		SetOperandB(val);
	}

private:
	float m_b;
};
typedef ComponentFactory<BinaryOperation<AddFloatContents, CTypeFloat> > AddFloatFactory;

// Float substraction
class SubFloatContents {
public:
	static const char* getTypeName() { return "fsub"; }
	SubFloatContents() : m_b(0) { }
	float SetOperandA (float a) { return a - m_b; }
	void SetOperandB (float b) {	m_b= b; }
	float GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		float val= m_b;
		StrToFloat (operand, &val);
		SetOperandB(val);
	}

private:
	float m_b;
};
typedef ComponentFactory<BinaryOperation<SubFloatContents, CTypeFloat> > SubFloatFactory;

// Float multiplication
class MulFloatContents {
public:
	static const char* getTypeName() { return "fmul"; }
	MulFloatContents() : m_b(1.0f) { }
	float SetOperandA (float a) { return a * m_b; }
	void SetOperandB (float b) { m_b= b; }
	float GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		float val= m_b;
		StrToFloat (operand, &val);
		SetOperandB(val);
	}

private:
	float m_b;
};
typedef ComponentFactory<BinaryOperation<MulFloatContents, CTypeFloat> > MulFloatFactory;

// Float division
class DivFloatContents {
public:
	static const char* getTypeName() { return "fdiv"; }
	DivFloatContents() : m_b(1.0f) { }
	float SetOperandA (float a) { return a / m_b; }
	void SetOperandB (float b) {
		if (b== 0.0f)
			getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, "fdiv: not stored 0.0 as divisor", "spcore");
		else
			m_b= b;
	}
	float GetOperandB () const {	return m_b; }
	void ParseOperandB(const char* operand) {
		float val= m_b;
		StrToFloat (operand, &val);
		SetOperandB(val);
	}

private:
	float m_b;
};
typedef ComponentFactory<BinaryOperation<DivFloatContents, CTypeFloat> > DivFloatFactory;

///////////////////////////////////////////////////////////////////////////////
/**
	fsqrt - Computes the square root

	Input pins:
		a (float)

	Output pins:
		result (float)
*/
class FSqrtComponent : public CComponentAdapter {
public:
	static const char* getTypeName() { return "fsqrt"; }
	virtual const char* GetTypeName() const { return FSqrtComponent::getTypeName(); }
    FSqrtComponent(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {
		
		m_opin= CTypeFloat::CreateOutputPin("result");
		if (RegisterOutputPin(*m_opin)!= 0)
			throw std::runtime_error("error registering output pin");

  		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinIn("a", *m_opin), false))!= 0)
			throw std::runtime_error("error creating input pin");
	}

private:
	virtual ~FSqrtComponent() {}

	class InputPinIn : public CInputPinWriteOnly<CTypeFloat, IOutputPin> {
	public:
		InputPinIn (const char * name, IOutputPin & component)
		: CInputPinWriteOnly<CTypeFloat, IOutputPin>(name, component) {
			m_result= CTypeFloat::CreateInstance();
		}

		virtual int DoSend(const CTypeFloat & msg) {
			float v= msg.getValue();
			if (v>= 0.0f) {
				m_result->setValue(sqrtf(v));
				m_component->Send(m_result);
				return 0;
			}
			else
				return -1;
		}

	private:		
		SmartPtr<CTypeFloat> m_result;
	};
	
	SmartPtr<IOutputPin> m_opin;	
};

typedef ComponentFactory<FSqrtComponent> FSqrtComponentFactory;

///////////////////////////////////////////////////////////////////////////////
//	Comparison operators
///////////////////////////////////////////////////////////////////////////////

template <typename T>
class CmpOpCommonOps
{
public:
	CmpOpCommonOps() : m_b(0) {}
	void SetOperandB (T b) { m_b= b; }
	T GetOperandB () const { return m_b; }
	void ParseOperandB(const char* operand);

protected:
	T m_b;
};

template<> void CmpOpCommonOps<int>::ParseOperandB(const char *operand) {
	int val= m_b;
	StrToInt (operand, &val);
	SetOperandB(val);
}

template<> void CmpOpCommonOps<float>::ParseOperandB(const char *operand) {
	float val= m_b;
	StrToFloat (operand, &val);
	SetOperandB(val);
}

// Integer
struct IntEqContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "ieq"; }
	bool SetOperandA (int a) { return (a== m_b); }
};
typedef ComponentFactory<BinaryOperation<IntEqContents, CTypeInt, CTypeBool> > IntEqFactory;

struct IntNeqContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "ineq"; }
	bool SetOperandA (int a) { return (a!= m_b); }
};
typedef ComponentFactory<BinaryOperation<IntNeqContents, CTypeInt, CTypeBool> > IntNeqFactory;

struct IntGtContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "igt"; }
	bool SetOperandA (int a) { return (a> m_b); }
};
typedef ComponentFactory<BinaryOperation<IntGtContents, CTypeInt, CTypeBool> > IntGtFactory;

struct IntEgtContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "iegt"; }
	bool SetOperandA (int a) { return (a>= m_b); }
};
typedef ComponentFactory<BinaryOperation<IntEgtContents, CTypeInt, CTypeBool> > IntEgtFactory;

struct IntLtContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "ilt"; }
	bool SetOperandA (int a) { return (a< m_b); }
};
typedef ComponentFactory<BinaryOperation<IntLtContents, CTypeInt, CTypeBool> > IntLtFactory;

struct IntEltContents : public CmpOpCommonOps<int> {
	static const char* getTypeName() { return "ielt"; }
	bool SetOperandA (int a) { return (a<= m_b); }
};
typedef ComponentFactory<BinaryOperation<IntEltContents, CTypeInt, CTypeBool> > IntEltFactory;


// Float
struct FloatEqContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "feq"; }
	bool SetOperandA (float a) { return (a== m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatEqContents, CTypeFloat, CTypeBool> > FloatEqFactory;

struct FloatNeqContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "fneq"; }
	bool SetOperandA (float a) { return (a!= m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatNeqContents, CTypeFloat, CTypeBool> > FloatNeqFactory;

struct FloatGtContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "fgt"; }
	bool SetOperandA (float a) { return (a> m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatGtContents, CTypeFloat, CTypeBool> > FloatGtFactory;

struct FloatEgtContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "fegt"; }
	bool SetOperandA (float a) { return (a>= m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatEgtContents, CTypeFloat, CTypeBool> > FloatEgtFactory;

struct FloatLtContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "flt"; }
	bool SetOperandA (float a) { return (a< m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatLtContents, CTypeFloat, CTypeBool> > FloatLtFactory;

struct FloatEltContents : public CmpOpCommonOps<float> {
	static const char* getTypeName() { return "felt"; }
	bool SetOperandA (float a) { return (a<= m_b); }
};
typedef ComponentFactory<BinaryOperation<FloatEltContents, CTypeFloat, CTypeBool> > FloatEltFactory;

///////////////////////////////////////////////////////////////////////////////
//	Boolean operators
///////////////////////////////////////////////////////////////////////////////
class NotContents {
public:
	static const char* getTypeName() { return "not"; }
	bool Compute(bool v) { return !v; }	
};
typedef ComponentFactory<UnaryOperation<NotContents, CTypeBool> > NotFactory;

///////////////////////////////////////////////////////////////////////////////
//	Casting operators
///////////////////////////////////////////////////////////////////////////////
/**
	fcast - Convert an input value into float

	Input pins:
		in (any)

		Input could be bool, int or float

	Output pins:
		out (float)
*/
class FCastComponent : public CComponentAdapter {
public:
	static const char* getTypeName() { return "fcast"; }
	virtual const char* GetTypeName() const { return FCastComponent::getTypeName(); }
    FCastComponent(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {
		
		m_opin= CTypeFloat::CreateOutputPin("out");
		if (RegisterOutputPin(*m_opin)!= 0)
			throw std::runtime_error("error registering output pin");

  		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinIn("in", *m_opin), false))!= 0)
			throw std::runtime_error("error creating input pin");
	}

private:
	virtual ~FCastComponent() {}

	class InputPinIn : public CInputPinWriteOnly<CTypeAny, IOutputPin> {
	public:
		InputPinIn (const char * name, IOutputPin & component)
		: CInputPinWriteOnly<CTypeAny, IOutputPin>(name, component) {
			m_intTypeId= CTypeInt::getTypeID();
			m_boolTypeId= CTypeBool::getTypeID();
			m_floatTypeId= CTypeFloat::getTypeID();
			m_result= CTypeFloat::CreateInstance();
		}

		virtual int DoSend(const CTypeAny & msg) {
			int msgId= msg.GetTypeID();

			if (msgId== m_intTypeId) {
				m_result->setValue((float) sptype_static_cast<const CTypeInt>(&msg)->getValue());
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_boolTypeId) {
				if (sptype_static_cast<const CTypeBool>(&msg)->getValue())
					m_result->setValue(1.0f);
				else
					m_result->setValue(0.0f);
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_floatTypeId) {
				m_result->setValue(sptype_static_cast<const CTypeFloat>(&msg)->getValue());
				return this->m_component->Send (m_result);
			}

			return -1;
		}

	private:
		int m_intTypeId, m_boolTypeId, m_floatTypeId;
		SmartPtr<CTypeFloat> m_result;
	};
	
	SmartPtr<IOutputPin> m_opin;	
};

typedef ComponentFactory<FCastComponent> FCastComponentFactory;

/**
	icast - Convert an input value into integer

	Input pins:
		in (any)

		Input could be bool, int or float

	Output pins:
		out (int)
*/
class IntCastComponent : public CComponentAdapter {
public:
	static const char* getTypeName() { return "icast"; }
	virtual const char* GetTypeName() const { return IntCastComponent::getTypeName(); }
    IntCastComponent(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {
		
		m_opin= CTypeInt::CreateOutputPin("out");
		if (RegisterOutputPin(*m_opin)!= 0)
			throw std::runtime_error("error registering output pin");

  		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinIn("in", *m_opin), false))!= 0)
			throw std::runtime_error("error creating input pin");
	}

private:
	virtual ~IntCastComponent() {}

	class InputPinIn : public CInputPinWriteOnly<CTypeAny, IOutputPin> {
	public:
		InputPinIn (const char * name, IOutputPin & component)
		: CInputPinWriteOnly<CTypeAny, IOutputPin>(name, component) {
			m_floatTypeId= CTypeFloat::getTypeID();
			m_boolTypeId= CTypeBool::getTypeID();
			m_intTypeId= CTypeInt::getTypeID();
			m_result= CTypeInt::CreateInstance();
		}

		virtual int DoSend(const CTypeAny & msg) {
			int msgId= msg.GetTypeID();

			if (msgId== m_floatTypeId) {
				m_result->setValue((int) sptype_static_cast<const CTypeFloat>(&msg)->getValue());
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_boolTypeId) {
				if (sptype_static_cast<const CTypeBool>(&msg)->getValue())
					m_result->setValue(1);
				else
					m_result->setValue(0);
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_intTypeId) {
				m_result->setValue(sptype_static_cast<const CTypeInt>(&msg)->getValue());
				return this->m_component->Send (m_result);
			}

			return -1;
		}

	private:
		int m_floatTypeId, m_boolTypeId, m_intTypeId;
		SmartPtr<CTypeInt> m_result;
	};
	
	SmartPtr<IOutputPin> m_opin;	
};

typedef ComponentFactory<IntCastComponent> IntCastComponentFactory;

/**
	bcast - Convert an input value into boolean

	Input pins:
		in (any)

		Input could be bool, int or float

	Output pins:
		out (bool)
*/
class BCastComponent : public CComponentAdapter {
public:
	static const char* getTypeName() { return "bcast"; }
	virtual const char* GetTypeName() const { return BCastComponent::getTypeName(); }
    BCastComponent(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {
		
		m_opin= CTypeBool::CreateOutputPin("out");
		if (RegisterOutputPin(*m_opin)!= 0)
			throw std::runtime_error("error registering output pin");

  		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinIn("in", *m_opin), false))!= 0)
			throw std::runtime_error("error creating input pin");
	}

private:
	virtual ~BCastComponent() {}

	class InputPinIn : public CInputPinWriteOnly<CTypeAny, IOutputPin> {
	public:
		InputPinIn (const char * name, IOutputPin & component)
		: CInputPinWriteOnly<CTypeAny, IOutputPin>(name, component) {
			m_intTypeId= CTypeInt::getTypeID();
			m_floatTypeId= CTypeFloat::getTypeID();
			m_boolTypeId= CTypeBool::getTypeID();			
			m_result= CTypeBool::CreateInstance();
		}

		virtual int DoSend(const CTypeAny & msg) {
			int msgId= msg.GetTypeID();

			if (msgId== m_intTypeId) {
				m_result->setValue(sptype_static_cast<const CTypeInt>(&msg)->getValue()!= 0);
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_floatTypeId) {
				// TODO: check wheter is better to allow for "almost zero" comparison 
				m_result->setValue(sptype_static_cast<const CTypeFloat>(&msg)->getValue()!= 0.0f);
				return this->m_component->Send (m_result);
			}
			else if (msgId== m_boolTypeId) {
				m_result->setValue(sptype_static_cast<const CTypeBool>(&msg)->getValue());
				return this->m_component->Send (m_result);
			}

			return -1;
		}

	private:
		int m_intTypeId, m_floatTypeId, m_boolTypeId;
		SmartPtr<CTypeBool> m_result;
	};
	
	SmartPtr<IOutputPin> m_opin;	
};

typedef ComponentFactory<BCastComponent> BCastComponentFactory;

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

/**
	fabs - Absolute value component (float)

	Input pins:
		in (CTypeFloat)

	Output pins:
		out (CTypeFloat)
*/
class FAbsComponent : public CComponentAdapter {
public:
	static const char* getTypeName() { return "fabs"; }
	virtual const char* GetTypeName() const { return FAbsComponent::getTypeName(); }
    FAbsComponent(const char * name, int argc, const char * argv[]) 
	: CComponentAdapter(name, argc, argv) {
		
		m_opin= CTypeFloat::CreateOutputPin("out");
		if (RegisterOutputPin(*m_opin)!= 0)
			throw std::runtime_error("error registering output pin");

  		if (RegisterInputPin(*SmartPtr<IInputPin>(new InputPinIn("in", *m_opin), false))!= 0)
			throw std::runtime_error("error creating input pin");
	}

private:
	virtual ~FAbsComponent() {}

	class InputPinIn : public CInputPinWriteOnly<CTypeFloat, IOutputPin> {
	public:
		InputPinIn (const char * name, IOutputPin & component)
		: CInputPinWriteOnly<CTypeFloat, IOutputPin>(name, component) {	
			m_result= CTypeFloat::CreateInstance();
		}

		virtual int DoSend(const CTypeFloat & message) {
			m_result->setValue (fabsf(message.getValue()));
			return this->m_component->Send (m_result);
		}
	private:
		SmartPtr<CTypeFloat> m_result;
	};
	SmartPtr<IOutputPin> m_opin;
};

typedef ComponentFactory<FAbsComponent> FAbsComponentFactory;

// Factories for basic types
typedef SimpleTypeFactory<CTypeInt> CTypeIntFactory;
typedef SimpleTypeFactory<CTypeBool> CTypeBoolFactory;
typedef SimpleTypeFactory<CTypeFloat> CTypeFloatFactory;
typedef SimpleTypeFactory<CTypeString> CTypeStringFactory;

// Factories for other components
typedef SimpleTypeFactory<CTypeComposite> CTypeCompositeFactory;


CBasicTypesModule::CBasicTypesModule() {
	//
	// Types
	RegisterTypeFactory(SmartPtr<CTypeIntFactory>(new CTypeIntFactory(), false));
	RegisterTypeFactory(SmartPtr<CTypeFloatFactory>(new CTypeFloatFactory(), false));
	RegisterTypeFactory(SmartPtr<CTypeBoolFactory>(new CTypeBoolFactory(), false));
	RegisterTypeFactory(SmartPtr<CTypeStringFactory>(new CTypeStringFactory(), false));
	RegisterTypeFactory(SmartPtr<CTypeCompositeFactory>(new CTypeCompositeFactory(), false));

	//
	// Components
	//
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new AddIntFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new SubIntFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new MulIntFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new DivIntFactory(), false));

	RegisterComponentFactory(SmartPtr<IComponentFactory>(new AddFloatFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new SubFloatFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new MulFloatFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new DivFloatFactory(), false));

	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FSqrtComponentFactory(), false));

	// Comparison operators
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntEqFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntNeqFactory(), false));	
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntGtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntEgtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntLtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntEltFactory(), false));

	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatEqFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatNeqFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatGtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatEgtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatLtFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FloatEltFactory(), false));
	
	// Boolean operators
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new NotFactory(), false));

	// Casting operators
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FCastComponentFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new IntCastComponentFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new BCastComponentFactory(), false));
	
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FAbsComponentFactory(), false));

	// Common components
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new SplitFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FAccumulatorFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FThresholdFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FLimitFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new ForwardComponentFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new FReductorFactory(), false));
//	RegisterComponentFactory(SmartPtr<IComponentFactory>(new SendMainSyncFactory(), false));
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new SendMainAsyncFactory(), false));

	RegisterComponentFactory(SmartPtr<IComponentFactory>(new PrintComponentFactory(), false));

	// Time components
	RegisterComponentFactory(SmartPtr<IComponentFactory>(new ChronoFactory(), false));
}

const char * CBasicTypesModule::GetName() const {
  	return "basictypes";
}

} // namespace spcore
