/**************************** CPPHeaderFile ************************************

* FileName [Shaft.h]

* PackageName [shaft]

* Synopsis [Header file for ConnectInfo, PubInfo, SubInfo, UnsubInfo,
* NotInfo and Shaft classes.]

* Description [This file contains the declarations for the classes
* ConnectInfo, PubInfo, SubInfo, UnsubInfo, NotInfo and Shaft. The
* ConnectInfo class encapsulates all the information about a
* connection to a broker - both for submitting requests and receiving
* notifications. The PubInfo class encapsulates all the information
* about a publication. The SubInfo class encapsulates all the
* information about a subscription. The UnsubInfo class encapsulates
* all the information about an unsubscription. The NotInfo class
* encapsulates all the information about a notification. The Shaft
* class encapsulates a client which can submit pub/sub/unsub requests
* as well as receive notifications.]

* SeeAlso [ConnectInfo.cpp PubInfo.cpp SubInfo.cpp UnsubInfo.cpp
* NotInfo.cpp Shaft.cpp]

* Author [Sagar Chaki]

* Copyright [ Copyright (c) 2001 by Carnegie Mellon University.  All
* Rights Reserved. This software is for educational purposes only.
* Permission is given to academic institutions to use, copy, and
* modify this software and its documentation provided that this
* introductory message is not removed, that this software and its
* documentation is used for the institutions' internal research and
* educational purposes, and that no monies are exchanged. No guarantee
* is expressed or implied by the distribution of this code. Send
* bug-reports and/or questions to: chaki+@cs.cmu.edu. ]

******************************************************************************/

#ifndef __SHAFT_H__
#define __SHAFT_H__

#include <string>
using namespace std;

//other classes needed
class SpearSocket;

/**************************************************************/
//info about a connection - can be used either to open a client
//connection to a broker or a server socket for getting notifications
//or to request a broker to open a connection for sending
//notifications.
/**************************************************************/

class ConnectInfo
{
 private:
  //the IP address of the broker
  string ipAddress;

  //the port for the broker or the server socket to be opened
  unsigned short port;

  //the backlog of the server socket to be opened
  int backlog;

public:
  ConnectInfo(string i = "null",unsigned short p = 0,int b = 0);
  ConnectInfo(const ConnectInfo &rhs);
  ~ConnectInfo() {}

  ConnectInfo &operator = (const ConnectInfo &rhs);

  string GetIPAddress() const { return ipAddress; }
  unsigned short GetPort() const { return port; }
  int GetBacklog() const { return backlog; }

  void SetIPAddress(const string i) { ipAddress = i; }
  void SetPort(const unsigned short p) { port = p; }
  void SetBacklog(const int b) { backlog = b; }
};

/**************************************************************/
//info about a publication
/**************************************************************/

class PubInfo
{
 private:
  //the string representing the publication
  string pub;

  //the id to be assigned to the publication
  string id;

  //if an acknowledgment is needed
  bool ack;

 public:
  PubInfo(string p = "null",string i = "basic",bool a = false);
  PubInfo(const PubInfo &rhs);
  ~PubInfo() {}

  PubInfo &operator = (const PubInfo &rhs);

  string GetPub() const { return pub; }
  string GetId() const { return id; }
  bool GetAck() const { return ack; }
  
  void SetPub(const string p) { pub = p; }
  void SetId(const string i) { id = i; }
  void SetAck(const bool a) { ack = a; }
};

/**************************************************************/
//info about a subscription
/**************************************************************/

class SubInfo
{
 private:
  //the string representing the subscription
  string sub;

  //the id to be assigned to the subscription
  string id;

  //the ip address where the notification is to be sent
  string ipAddress;

  //the port where the notification is to be sent
  int port;

  //the validity duration of the subscription
  unsigned long validity;

  //if an acknowledgment is needed
  bool ack;
  
 public:
  SubInfo(string s = "null",string i = "null",string ip = "null",
	  int p = 0,unsigned long v = 0,bool a = false);
  SubInfo(const SubInfo &rhs);
  ~SubInfo() {}

  SubInfo &operator = (const SubInfo &rhs);

  string GetSub() const { return sub; }
  string GetId() const { return id; }
  string GetIPAddress() const { return ipAddress; }
  int GetPort() const { return port; }
  unsigned long GetValidity() const { return validity; }
  bool GetAck() const { return ack; }
  
  void SetSub(const string s) { sub = s; }
  void SetId(const string i) { id = i; }
  void SetIPAddress(const string i) { ipAddress = i; }
  void SetPort(const int p) { port = p; }
  void SetValidity(const unsigned int v) { validity = v; }
  void SetAck(const bool a) { ack = a; }
};

/**************************************************************/
//info about an unsubscription
/**************************************************************/

class UnsubInfo
{
 private:
  //the id of the subscription to be removed
  string subId;
  
  //if an acknowledgment is needed
  bool ack;

 public:
  UnsubInfo(string s = "null",bool a = false);
  UnsubInfo(const UnsubInfo &rhs);
  ~UnsubInfo() {}

  UnsubInfo &operator = (const UnsubInfo &rhs);

  void SetSubId(const string s) { subId = s; }
  void SetAck(const bool a) { ack = a; }

  string GetSubId() const { return subId; }
  bool GetAck() const { return ack; }
};

/**************************************************************/
//info about a notification
/**************************************************************/

class NotInfo
{
 private:
  //the id of the subscription being notified
  string subId;

  //the string for the publication that matched the subscription
  string pub;

 public:
  NotInfo(string s = "null",string p = "null");
  NotInfo(const NotInfo &rhs);
  ~NotInfo() {}

  NotInfo &operator = (const NotInfo &rhs);

  void SetSubId(const string s) { subId = s; }
  void SetPub(const string p) { pub = p; }

  string GetPub() const { return pub; }
  string GetSubId() const { return subId; }
};

/**************************************************************/
//the client
/**************************************************************/

//some pre-defined constants
//delay requested before a broker tries to initiate a notification connection
const int NOT_CONNECT_DELAY = 2;

//timeout for waiting for the broker to initiate a notification connection
const int NOT_CONNECT_TIMEOUT = 5;

//the connection status of any client
enum ShaftConnectStatus 
{
  SHAFT_CONNECT_NONE = 15000,    //not connected
  SHAFT_CONNECT_SRV,             //socket is opened as a server socket
  SHAFT_CONNECT_REQ,             //connected in request mode - can publish, subscribe etc
  SHAFT_CONNECT_NOT              //connected in notification mode - can receive notifications
};

//Note: Shaft does not do any implicit connection management. The user
//will have to explicitly open and close all connections through the
//various methods supplied.

class Shaft
{
 private:
  SpearSocket *sock;  //the socket
  int status;         //the connection status

 public:
  Shaft();
  Shaft(const Shaft &rhs);
  ~Shaft();

  Shaft &operator = (const Shaft &rhs);

  int GetStatus() const { return status; }

  //terminate any existing connection
  void Disconnect();

  //these functions are used in the client mode - for publishing
  //subscribing and unsubscribing
  int Connect(const ConnectInfo &connectInfo);
  bool Publish(PubInfo &pubInfo);
  bool Subscribe(SubInfo &subInfo);
  bool Unsubscribe(UnsubInfo &unsubInfo);

  //these functions are used in the server mode
  //open a server socket
  bool Open(const ConnectInfo &connectInfo);
  //start a notification connection from a broker on the Shaft objects
  //provided
  int StartNotConnect(Shaft &srvShaft,Shaft &newShaft,const ConnectInfo &connectInfo);
  //start a notification connection on some IP address and port
  int StartNotConnect(const ConnectInfo &connectInfo);
  //accept a notification connection from a broker and do the
  //handshake
  bool AcceptNotConnect(Shaft &srvShaft);
  //query the status of a notification connection on some IP
  //address and port
  int QueryNotConnect(const ConnectInfo &connectInfo);
  //close a notification connection on some IP address and port
  int CloseNotConnect(const ConnectInfo &connectInfo);
  //receive a notification
  bool GetNotification(NotInfo &notInfo);
};

#endif
