/**
* @file		pin.h
* @brief	Interface definition for component pins.
* @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/>.
*/
#ifndef SPCORE_PIN_H
#define SPCORE_PIN_H

#include "include/spcore/baseobj.h"
#include <assert.h>

namespace spcore {

class CTypeAny;

/**
	@brief Interface for input pins

	This interface declares operations that should be available to work 
	with pins but not to implement it. Use CInputPin to create your 
	specific (i.e. typed) pin implementation.
*/
class IInputPin : public IBaseObject {
protected:
	virtual ~IInputPin() {}

public:
	/**
		@return the internal type ID for the type name of this pin, 
		(which is execution) dependent or TYPE_ANY.
	*/
    virtual int GetTypeID() const = 0;

    /**
		@return the name of the pin.
	*/
    virtual const char* GetName() const = 0;

    enum EIPinProperties {
      ALLOW_WRITE = 1,
      ALLOW_READ = 2

    };

    /**
		@brief Get the properties of the pin.
		@return Combination of flags.
		@return ALLOW_WRITE: calls to Send method allowed.
		@return ALLOW_READ: calls to Read method allowed.
    */
    virtual unsigned int GetProperties() const = 0;

    /**
		@brief Send a message to the pin. 			
		@return  0 -> message successfully sent.
		@return -1 -> type mismatch.

		Intended only for calls outside the graph.
    */
    virtual int Send(SmartPtr<const CTypeAny> message) = 0;

	/**
		@brief Read the content of the pin.
		
		@return Copy of the content of a NULL pointer.
	*/
    virtual SmartPtr<const CTypeAny> Read() const = 0;

	/**
		@brief Rename the pin.
		@param name New name of the pin.
	*/
	virtual void Rename (const char * name) = 0;

	/**
		@brief Allow to change the type of the pin. 
		
		The only change allowed	is to turn an any pin into a typed one. 
		The change	might fail if the pin is already connected.

		@param type_name Name of the new type.
		@return  0 -> type changed correctly
		@return	-1 -> type cannot be changed
		@return	-2 -> type name does not exists
	*/
	virtual int ChangeType (const char * type_name) = 0;
};

/**
	@brief Interface for output pins.

	This interface declares operations that should be available to work 
	with pins but not to implement it. Use COutputPin to create your 
	specific (i.e. typed pin implementation)
*/
class IOutputPin : public IBaseObject {
protected:
	virtual ~IOutputPin() {}

public:
	/**
		@return the internal type ID for the type name of this pin, which 
		is execution dependent, or  TYPE_ANY if the type name doesn't exists.
	*/
    virtual int GetTypeID() const = 0;

	/**
		@brief Name of the pin.
		@return Pointer to a internal char array which might not be freed.
	*/
    virtual const char* GetName() const = 0;

    /**
		@brief Connect this with a consumer input pin.
		@param consumer Input pin to connect to.
		@return 0 if all correct 
		@return <0 when error
    */
    virtual int Connect(IInputPin & consumer) = 0;

    /**
		@brief Disconnects. 
		@param consumer Input pin at the other end.
		
		If the two pins where not connected does nothing.
    */
    virtual void Disconnect(const IInputPin & consumer) = 0;

    /**
		@brief Checks whether two pins can be connected.
		taking into account the type of each one.
		@param consumer Input pin at the other end.
		@return true or false
	*/
    virtual bool CanConnect(const IInputPin & consumer) const = 0;

    /**
		@brief Send a message to the connected pins. 
		@return 0 if correct or <0 when error.

		To be used by the component implementation.
    */
    virtual int Send(SmartPtr<const CTypeAny> message) = 0;

	/**
		@brief Return the number of consumers currently connected
		@return number of consumers 
	*/
	virtual unsigned int GetNumComsumers() const = 0;

	/**
		@brief Rename the pin.
		@param name New name for the pin.
	*/
	virtual void Rename (const char * name) = 0;

	/**
		Allow to change the type of the pin. The only change allowed
		is to turn an any pin into a typed one. The change
		might fail if the pin is already connected.

		@param type_name Name of the new type.
		@return  0 -> type changed correctly
		@return	-1 -> type cannot be changed
		@return	-2 -> type name does not exists
	*/
	virtual int ChangeType (const char * type_name) = 0;

};

} // namespace spcore
#endif
