/* 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_INET_ADDR_HPP
#define NMM_INET_ADDR_HPP NMM_INET_ADDR_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm_sockaddr_in.hpp"

#include <string>
#include <ostream>

#include "visibility.hpp"

namespace NMM {

  /** A C++ Wrapper for an internet address.
   *
   * This class avoids some standard errors with network addresses. So
   * the IP-address and the port are automatically converted from host
   * byte-order to network byte-order.
   */
  class DLLEXPORT INetAddr {
  public:
    /** @name Constructor & Destructor
     */
    //@{
    /** Default Constructors & Destructor.
     * Initialize the IP-Address and port to 0
     */
    INetAddr();

    /** Constructor.
     * @param addr set the IP-Address as long to addr. The IP-Address is automatically converted from byte-odrder to host-order if need.
     * @param port set the address-port to port. The port is automatically converted from byte-odrder to host-order if need.
     */
    INetAddr(unsigned long addr, unsigned int port);

    /** Constructor.
     * @param addr set the IP-Address from a valid hostname to addr(the char* can be a valid IP-Address too). The IP-Address is automatically converted from byte-odrder to host-order if need.
     * @param port set the address-port to port. The port is automatically converted from byte-odrder to host-order if need.
     */
    INetAddr(const char* addr, unsigned int port);
    
    /** Copy-Constructor.
     * @param addr Creates a copy from a given INetAddr.
     */
    INetAddr(const INetAddr& addr);
    
    /** Virtual destructor.
     */
    virtual ~INetAddr();
    //@}
    
    /** @name Get Methods
     */
    //@{
    /** virtual Copy-Constructor
     * @return a copy from the INetAddr
     */
    virtual INetAddr*    copy()         const { return new INetAddr(*this); }

    /** This method returns the current port.
     * @return Returns the port in host-order. You must not convert it again!
     */
    inline unsigned int  getPort()      const { return ntohs(_address.sin_port); }

    /** This method returns the internal stored sockaddr. This method is for compatibility reason to use this class with C-Code
     * that uses the C-structs.
     * @return Returns internal C-Struct sockaddr.
     */
    inline sockaddr*     getAddress()   const { return reinterpret_cast<sockaddr*> (&_address); }

    /** This method returns the size of the internal sock_address.
     * This method is for compatibility reason to use this class with C-Code that uses the C-structs.
     * @return Returns the size of the sock_address
     */
    inline size_t        getSize()      const { return sizeof (_address); }

    /** This method returns the current IP-Address in host byte-order.
     * @return Returns the current IP-Address in host byte-order
     */
    inline unsigned long getIpAddress() const { return ntohl(_address.sin_addr.s_addr); }

    /** This method returns the transport protocol which can be eithe "TCP" or "UDP"
     * @return Returns the current transport protocol
     */
    inline const std::string& getTransportProtocol() const { return _trans_prot; }
    
    /** Convert address to human readable std::string of the form ip_address:port
     * @return string of the address in human readable form. 
     */
    std::string toString() const;
    //@}

    /** @name Set Methods
     */
    //@{
    /** Sets the port for the INetAddr. This method converts the port from host byte-order to network byte-order.
     * @param port Expects the port in host byte-order
     */
    inline void          setPort(unsigned int port)   { _address.sin_port = htons(port); _port = port; }

    /** Sets the transport protocol which can be either "tcp" or "udp"
     * @param protocol The Prototcol for the INetAddr.
     */
    inline void          setTransportProtocol(const std::string& protocol) { _trans_prot = protocol; }

    /** Sets a hostname to INetAddr. The hostname automatically converted to an IP-Address.
     * @param addr The new hostname for this INetAddr.
     */
    void          setAddress(const char* addr)  ;

    /** Sets the IP-Address for the INetAddr. This method converts the IP-Address from host byte-order to network byte-order.
     * @param addr The given IP-Address from host byte-order to network byte-order.
     */
    void          setAddress(unsigned long addr);

    /** Sets the an C-struct addr. All internal parameters are copied from the addr-struct.
     * @param addr The valid C-struct sockaddr_in.
     */
    void          setAddress(struct sockaddr_in* addr);
    //@}
    
    /** Output operator for INetAddr
     *
     * @param ostr output stream that should be used
     * @param addr that should be written to ostr.
     */
    friend std::ostream& operator<<(std::ostream& ostr, INetAddr& addr) {
      return ostr << addr.toString();
    }
    
    /** Update all members after deserialization
     */
    void updateAttributes();

    /** Returns the receiving broadcast address 
     *
     * @return the receiving broadcast address 
     */
    static unsigned long getReceivingBroadcastAddress();

    /** Returns the sending broadcast address 
     *
     * @return the sending broadcast address 
     */
    static unsigned long getSendingBroadcastAddress();
  private:
    mutable sockaddr_in     _address;           ///< The internal C-Struct soccaddr_in.
    std::string             _trans_prot;        ///< Stores the Transport-protocol, which can be "TCP" or "UDP"
    unsigned int            _port;              ///< Stores the port of the INetAddr
    unsigned long           _ip_address;        ///< Stores the IP-Address of the INetAddr
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
