/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM 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; only version 2 of the License.      
 * 
 * NMM 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 NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#ifndef NMM_INTERFACE_HPP
#define NMM_INTERFACE_HPP NMM_INTERFACE_HPP

#include "nmm/nmm_prefix.hpp"

#include "NMMReference.hpp"
#include "UserInfo.hpp"
#include "BindingException.hpp"

#include "nmm/comm/serialize/SerializedValue.hpp"
#include "nmm/comm/serialize/SequenceValue.hpp"
#include "nmm/comm/messaging/IEventSender.hpp"

// for MS Visual C++, include these because of earlier template instantiation
#ifdef _MSC_VER
#include "nmm/comm/serialize/StdValue.hpp"
#include "TSAddress.hpp"
#else
#endif

#include <list>

#include "visibility.hpp"

namespace NMM {
  
  class NMMObject;
  class Event;
  class TSAddress;
  class TSDescription;
  class ProxyObject;
  
  /** \class Interface
   * This class is base class for all interfaces. It strores all addresses to its ParentObject
   * wich provides the implementation of an interface. The communication between
   * an Interface and its object is done through a ProxyObject, wich is connected through
   * a communication channel with the ParentObject.
   */
  class DLLEXPORT Interface
    : public SerializedValue,
      public IEventSender
  {
    friend class ProxyObject;
    friend class ReferenceManager;
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Constructor, that uses the given NMMObject as parent.
     *
     * @param receiver NMMObject that receives methods from the interface
     * @param interface_type the typename of the interface
     * @param name_space the namespace of the interface
     */
    Interface(NMMObject& receiver, const string& interface_type = "Interface", const string& name_space = "NMM");

    /** Constructor. 
     *
     * @param interface_type the typename of the interface
     * @param name_space the namespace of the interface
     */
    Interface(const string& interface_type = "Interface", const string& name_space = "NMM");

    /** Copy Constructor.
     *
     * @param iface Interface to copy
     */
    Interface(const Interface& iface);

    /** Destructor.
     */
    virtual ~Interface();

    /** Virtual Copy Constructor.
     *
     * @return a copy of the interface
     */
    virtual Interface* copy() const {return new Interface(*this);}
    //@}

    /** @name Event Sending
     */
    //@{
    /** This method sends an Event to the current event receiver.
     * 
     * @param e event that is sent to the event receiver which is in general an NMMObject
     * @return Result of the Event
     */
    virtual Result sendEvent(Event& e);
    //@}

    /** @name Access Interface information
     */
    //@{
    /** This method returns a list of all subtypes of an instance of this class.
     * @return list of all subtypes subtypes of an instance this class
     */
    inline const list<string>& getSubTypes() const {return __interfaces;}


    /** This method returns true if given type is a subtype of this interface.
     *
     *  @return true iff given type is a subtype of this interface
     */
    bool isSubType(const string& type);

    /** This method returns the typename of this interface.
     *
     * @return typename of the interface
     */
    virtual       string getInterfaceType() const { return getTypeName(); }

    /** This method returns the used ProxyObject to send events.
     *
     * @return pointer to the ProxyObject that receives Events from this interface
     */
    virtual       ProxyObject* getParentObject()          ;

    /** This method returns the used ProxyObject to send events.
     *
     * @return const pointer to the ProxyObject that receives Events from this interface
     */
    virtual const ProxyObject* getParentObject() const    ;

    /** This method returns the used ProxyObject to send events. 
     *
     * @deprecated This method is obsolete, use getParentObject().
     * @return pointer to the ProxyObject that receives Events from this interface
     */
    virtual       ProxyObject* getEventReceiver()         ;

    /** This method returns the used ProxyObject to send events. 
     *
     * @deprecated This method is obsolete, use getParentObject()
     * @return const pointer to the ProxyObject that receives Events from this interface .
     */
    virtual const ProxyObject* getEventReceiver() const   ;

    /** This method returns the NMMReference of the NMMObject that offers this interface.
     *
     * @return NMMReference of the NMMObject that offers this interface
     */
    virtual const NMMReference& getParentReference() const ;

    /** This method returns the UserInfo of the NMMObject.
     *
     * @return UserInfo of the NMMObject that implements and executes incoming events from an interface
     */
    inline const UserInfo& getParentInfo()           const { return __parent_user_info.getRValue(); }

    /** This method returns a list of all addresses to connect to the node.
     *
      * @return list of all addresses to connect to the node.
     */
    const SequenceValue<TSAddress>& getAddressList() const;

    /** This method returns a list of supported TransportStrategies of the ParentObject.
     *
     * @return list of supported TransportStrategies to connecte to the ParentObject
     */
    const list<TSDescription>& getSupportedStrategies() const  { return __supported_strategies.getRValue(); }

    /** This method returns the TSAddress for a specific Transport Strategy.
     *
     * @param transport_strategy TransportStrategy to return TSAddress for
     * @return TSAddress for give TransportStrategy
     */
    TSAddress* getDefaultAddress(const string& transport_strategy); 
    
    /** This method can be used to enforce the estabelishment of a conntection to the Node.
     */
    void establishBinding() throw (const BindingException&);
    //@}
    
    /** @name Methods to specify the position of interfaces
     */
    //@{
    /** Tests if the object of this interface and the object of the given interface run on the same system and in the same process.
     *
     * @param _interface interface to compare this one with
     * @return true if both objects represented by their interfacex run on same system and in same process, false otherwise
     */
    virtual bool isLocalTo(const Interface& _interface) const;

    /** Tests if the object of this interface and the object of the given interface run on the same system but in a different processes.
     *
     * @param _interface interface to compare this one with
     * @return true if both objects represented by their interfaces run on the same system but in a different processes
     */
    virtual bool isSystemTo(const Interface& _interface) const;

    /** Tests if the object of this interface and the object of the given interface run on different systems.
     *
     * @param _interface interface to compare this one with
     * @return true if both objects represented by their interfaces run on different systems
     */
    virtual bool isNetworkTo(const Interface& _interface) const;
    //@}

    /** @name Operator
     */
    //@{
    /** Assignment operator.
     *
     * @param _interface Interface to assign values from
     * @return reference to given Interface
     */
    Interface& operator=(const Interface& _interface);
    //@}
	
    /** This interface is used.
     *
     * This is an empty method which must be overloaded in all subclasses and implemented
     * in the .cpp file (it must not be inlined!). Its purpose is to force the linker to
     * link against the library containing he interface class definition.
     *
     * This method is generated automatically by the IDL compiler.
     */
    static void used() {}

    /** This method sets the EventReceiver.
     *
     * @param receiver event receiver to set
     */
    void setEventReceiver(NMMObject& receiver);

  protected:
    /** This method sets the ParentObject.
     *
     * @param receiver parent object
     */
    void setParentObject(ProxyObject* receiver) { __receiver = receiver; }

    /** This method adds an interface subtype.
     *
     * @param iface interface subtype to add
     */
    void addInterfaceType(const string& iface);

    /** Prepares the attributes for serialization.
     * Creates list of TSAddresses of usable TransportStrategies.
     */
    void prepareAttributes();

    /** Updates the attributes after deserialization.
     */
    void updateAttributes();

  private:
    /** Registers all attributes for serialization/deserialization.
     */
    void registerAttributes();

    /** Requests the ProxyObject.
     */
    void requestParentObject() const;

  private:
    list<string>                    __interfaces;             ///< List with subtypes
    mutable NMMObject*              __parent_object;          ///< Pointer to the NMMObject
    mutable ProxyObject*            __receiver;               ///< Pointer to the ProxyObject, that receives the events
    mutable TValue<NMMReference>    __parent_reference;       ///< NMMReference of the NMMObject
    TValue<UserInfo>                __parent_user_info;       ///< UserInfo of the NMMObject
    SequenceValue<TSAddress>        __address_list;           ///< List with all TSAddresses
    TValue< list<TSDescription> >   __supported_strategies;   ///< Stores the supported TransportStrategies
    bool                            __is_local;               ///< Is false if the Interface was serialized.
  };

  typedef auto_ptr<Interface> Interface_var;

  /** OValueStream insertion operator.
     * This operator writes list of Interfaces to an OValueStream.
     *
     * @param ov OValueStream to write to
     * @param interfaceptr_list list of Interfaces
     * @return given OValueStream
     */
  DLLEXPORT OValueStream& operator<<(OValueStream& ov, const list<Interface*>& interfaceptr_list);

  /** IValueStream extraction operator.
    * This operator reads list of Interfaces from an IValueStream.
    *
    * @param iv IValueStream to read from
    * @param interfaceptr_list list of Interfaces
    * @return given IValueStream
    */DLLEXPORT IValueStream& operator>>(IValueStream& iv, list<Interface*>& interfaceptr_list);
}

#include "nmm/nmm_suffix.hpp"

#endif
