//============================================================================
/// Summary  : Simple Socket
/// Filename : simpleSocket.h
/// Author   : reed@bluefinrobotics.com
/// Project  : Simple Socket Library
/// Revision : 0.0
/// Created  : 2002.02.26
/// Modified : 2002.02.26
//============================================================================

#ifndef _SIMPLESOCKET_H
#define _SIMPLESOCKET_H

//#define DEBUG_SS 1

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <stdio.h>

#include "../utils/Syslog.h"
#include "System.h"

// Some limits.
static const int maxIpAddressStringSize = 16;

// Address parameters from netinit/in.h.
static const u_long ANY_ADDRESS = INADDR_ANY;
static const u_long BROADCAST_ADDRESS = INADDR_BROADCAST;

// Other address parameters.
static const char BROADCAST_STRING[] = "255.255.255.255\0";

class SimpleSocket
{
 public:
    // Constructors / Destructors
    SimpleSocket();
    virtual ~SimpleSocket();

    // ---------- Create Socket Items ----------
    // Socket Type enumerations taken from sys/socket.h
    enum Type{ STREAM = SOCK_STREAM,          // stream socket
	       DGRAM = SOCK_DGRAM,            // datagram socket
	       RAW = SOCK_RAW,                // raw-protocol interface
	       RDM = SOCK_RDM,                // reliably-delivered message
	       SEQPACKET = SOCK_SEQPACKET };  // sequenced packet stream
    // Socket Domain (address families) enumerations taken from sys/socket.h (minimal listing here)
    enum Domain{ UNSPEC = AF_UNSPEC, // ( 0) unspecified 
		 // ...
	         INET = AF_INET,     // ( 2) internetwork: UDP, TCP, etc.
		 // ...
		 MAX = AF_MAX };     // (20) maximum number of domains
    // Socket Protocol (from sys/socket.h ... same as address families for now).
    typedef Domain Protocol;

    /// create socket
    int create( Type type,
		Domain domain = INET,
		Protocol proctocol = UNSPEC);
    /// create datagram socket
    int createInetDgram();

    /// destroy socket
    int destroy();

    /// set socket options
    int setOptions(int level,
		   int options,
		   const void *optionValue,
		   int optionLength);
    /// set socket options broadcast
    int setOptionsDgramBroadcast();

    /// set socket address long value
    int setAddress(unsigned short port,                         // Port
		   unsigned long ipAddress = BROADCAST_ADDRESS, // BROADCAST_ADDRESS = 255.255.255.255
		   unsigned short family = INET);               // INET = Internet
    /// set socket address IP address string
    int setAddress(unsigned short port,                       // Port
		   char *ipAddressString = &BROADCAST_STRING, // IP address = 192.168.0.86
		   unsigned short family = INET);             // INET = Internet

    // +++++++ Converters go here +++++++

    /// Convert string IP address to a hex address, i.e. "255.255.255.255" --> 0xFFFFFFFF.
    unsigned long string2hexIpAddress(char *ipAddressString);


    // +++++++ Heavy duty functions that do it all +++++++

    /// create broadcast datagram socket
    /// @param socket port
    /// @param network address structure
    /// @return returns : -1 on failure
    /// @return returns :  0 on success
    virtual int createBroadcastDatagramSend(unsigned short port, 
					    unsigned long ipAddress = BROADCAST_ADDRESS);
    virtual int createBroadcastDatagramSend(unsigned short port, 
					    char *ipAddressString = &BROADCAST_STRING);

    // ---------- Transfer Over Socket Commands ----------

    /// send to socket explicit
    int sendTo(const void *message,
	       int messageLength,
	       int flags = 0);
    /// send to socket simple
    int sendDatagram(const void *message,
		     int messageLength);

    bool exists() { return(networkAddress.descriptor > 0 ? true : false); }
    bool ready() { return(networkAddress.ready); } 
 protected:

 private:
    /// Network address.
    struct NetworkAddress 
    {
	Boolean ready;
	int descriptor;
	char ipAddressString[maxIpAddressStringSize];
	unsigned long ipAddress;
	unsigned short port;
	struct sockaddr_in address;
	int addressLength;
	int optionValue;
	int optionValueLength;
    } networkAddress;
};
#endif
