///
//     @file    mcastRelay.hxx
//     @date    Mon Aug 20 09:38:20 2018
// 
//     Copyright © 2018 by ZeeVee, Inc
//
#ifndef MCASTRELAY_HXX
#define MCASTRELAY_HXX

using namespace std;
using namespace std::chrono;

#ifdef _WIN32

struct ip {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
	u_char	ip_hl:4,		/* header length */
		     ip_v:4;		/* version */
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
	u_char	ip_v:4,			/* version */
  		    ip_hl:4;		/* header length */
#endif
	u_char	ip_verlen;
	u_char	ip_tos;			/* type of service */
	short	ip_len;			/* total length */
	u_short	ip_id;			/* identification */
	short	ip_off;			/* fragment offset field */
	u_char	ip_ttl;			/* time to live */
	u_char	ip_p;			/* protocol */
	u_short	ip_sum;			/* checksum */
	struct	in_addr ip_src,ip_dst;	/* source and dest address */
};

#endif

using namespace std;

enum Constants {
    MaxFrameSize = (1000000 / 8),
    MaxBitRateMbps = 8,
    MaxTsDurationSecs = 2,  // don't go below 2
    MaxTsFiles = 8,
    MaxTsFileSize = (MaxBitRateMbps * 1000000 / 8 * MaxTsDurationSecs + MaxFrameSize),
};

extern "C" {
    int readyHandler(struct mg_connection *conn, void *cbdata);
    int hlsHandler(struct mg_connection *conn, void *cbdata);
    int tsHandler(struct mg_connection *conn, void *cbdata);
    int log_message(const struct mg_connection *conn, const char *message);
    int webSocketConnectHandler(const struct mg_connection *conn, void *userData);
    void webSocketReadyHandler(struct mg_connection *conn, void *userData);
    int websocketDataHandler(struct mg_connection *conn, int bits, char *data, size_t len, void *userDdata);
    void websocketSend(struct mg_context *ctx);
    void webSocketCloseHandler(const struct mg_connection *conn, void *userData);
}

#define IP4_HDRLEN 20       // IPv4 header length

enum IgmpTypes {
    Report = 0x12
};

typedef struct IgmpPkt
{
    char type;
    char maxRespTime;
    short chksum;
    int mcastAddr;
} IgmpPkt;

typedef struct Pkt
{
    struct ip iphdr;
    IgmpPkt igmp;
} Pkt;


class MemFile
{
public:
    char *buf;
    double durationMs;
    int bytes;
    char name[64];
};

class McastRelay
{
public:
    mutex mtx;

    int firstMcastPkt;
    int firstTsRead;

    int vidFrames;
    int totBytes;
    int ringFull;
    stringstream content;
    string hostAddrStr;
    int hostAddr;
    int ourIp;
    int ourMask;
    int mcastAddr;
    int mcastPort;
    int vidPid;
    int igmpSock;
    int firstSequenceNum;
    int lastSequenceNum;
    int fileWriteIndex;
    MemFile memTsFiles[MaxTsFiles];

    thread threadIgmpReportsHandle;
    thread threadRcvHandle;
    
    struct mg_websocket_subprotocols subprots;
    const struct mg_connection *webSockConn;

    int contCountTs;
    int goodContTs;
    int stopUdpRcvs;
    high_resolution_clock::time_point prevTime;

    int Main();
    
    int InitWebServer();
    int StartMcastReceive();
    void ThreadMcastRcv(int sock);
    void ThreadIgmpReports();

    int ReadyHandler(struct mg_connection *conn, void *cbdata);
    int HlsHandler(struct mg_connection *conn, void *cbdata);
    int TsHandler(struct mg_connection *conn, void *cbdata);
    void WriteFile(char *buf, int nbytes, int newFrame);

    int WebSocketConnectHandler(const struct mg_connection *conn, void *userData);
    void WebSocketReadyHandler(struct mg_connection *conn, void *userData);
    int WebsocketDataHandler(struct mg_connection *conn, int bits, char *data, size_t len, void *userDdata);
    void WebsocketSend(struct mg_context *ctx);
    void WebSocketCloseHandler(const struct mg_connection *conn, void *userData);

    int GetMcastSock();
    int SendIgmpReport();
    int InitIpPkt(Pkt &pkt);
    int InetCksum(uint16_t *addr, u_int len);
    int GetOurIp(int remoteIp);
    
};


void LOG(const char* fmt, ...) ;

#endif

