#ifndef _CSH_
#define _CSH_ 1

using namespace std;
#include <string>
#include <iostream>
#include <thread>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <libgen.h>
#include <math.h>
#include "Debug.h"

typedef struct ShareS {			// shared items between procs or threads
	int conns;						// overall connections# both in ring and mash
	int msgs;						// overall forwards#	   both in ring and mash
	int act;							//	active nodes#		   both in ring and mash
	sem_t counterSem;				// semaphore for counters
} ShareT, *ShareP;
#define ShareA(v) if((v = (ShareP) mmap(NULL, sizeof(ShareT), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0)) < 0) SYSERR("mmap")

typedef struct CSS {				// top level attributes
	string text;					// text to be sent in messages
	int ttl;							// TTL for circulating msgs
	int mp0;							// TCP port of first mash node
	int mn;							// intended # of nodes in mash
	int rp0;							// TCP port of first ring node
	int rn;							// intended # of nodes in ring
   struct timespec pace;		// pacing time quantum
   int pacing;						// pacing indicator
	int issl;						// ssl switch: 0=no_ssl, 1=ssl, 2=both
	int connThreshold;			// connection retry threshhold
	int connTO;						// connection timeout in usecs
	int selTO;						// selection timeout in secs
	string cePath;					// SSL certs path
	string caPath;					// CA  certs path
	ShareP shP;
	CSS(DebugP, char*);
} *CSP;

typedef struct HeaderS {		// container header
	int ttl;
	int ts;
	int remPort;

	HeaderS();
	HeaderS(int);
	int len();
} *HeaderP;

typedef struct PayloadS {		// payload structure
	time_t ts;
	char text;

	PayloadS();
	PayloadS(const char *);
	int check(PayloadS*);
	char *deliver();
	string digest();
	void sabotage();
	int len();
} *PayloadP;

typedef struct ContainerS {	// data container sent throug mash or ring
	HeaderS hdr;
	PayloadS payl;
	int len();
} ContainerT, *ContainerP;

typedef class DataC {			// data sent and received
public:
	DebugP deP;
	ContainerP contP;
	int dataLen;
//	int transferLen;

	DataC();
	DataC(DebugP);
	int dttl();
	int ttl();
	void load(int, const char*);
	string unld();
	string digest();
	bool dataOk();
	int ts();
	int remPort();
	int remPort(int);
} *DataP;

typedef struct SocketS {		// info about sockets allocated in node
	int remPort;
	int sc;
	SSL *sslP;
} *SocketP;

typedef enum{ring, mash} topology;
typedef enum{client, server} nodeside;
class ConstellationC {			// constellation of communication nodes (mash or ring)
	DebugP deP;
public:
	topology topo;
	int ssl, first, nodes, *forwP;

	ConstellationC();
	ConstellationC(topology, int);
	int run();
};
typedef ConstellationC *ConstellationP;

class NodeC : public ConstellationC {	// attributes and operations of one node of constellation (mash or ring)
public:
	DebugP deP;
	int locPort;
	int last;
	int kicker;
	int closing;
	thread closingThread;		// thread to close client side sockets
	DataC data;
	int len;
	int ssc;
	SocketP cliSides;
	SocketP srvSides;
	SSL_CTX *ctxP;

	NodeC(ConstellationP, int);
	int run();
	void mainLoop();
	void bindN();
	void conn(int, int);
	void acc(int);
	void closeSocket(int, nodeside);
	int getN(int);
	int readN(int);
	int putN(int);
	int writeN(int);
	int next_node();
	void forward(int);
	void closeClients();
};
typedef NodeC *NodeP;

extern char *gpa(struct sockaddr *);
extern void gai(int, struct addrinfo *ai, DebugP);
#define GAI(level, ai) gai(level, ai, deP)
extern void ssl_err(char*);
extern void abend();

#define SYSERR(e) LOG(0, "%s: %s (%d)", (char*)e, strerror(errno), errno), abend(deP)
#define SSLERR(e) ssl_err((char*)e, deP), abend(deP)
#define SOFTERR(e) LOG(0, e), fflush(stderr)
#define HARDERR(e) SOFTERR(e), abend(deP);

extern CSP csP;

#endif
