//
//  MFSPublic.h
//
//  Created by 杨净 on 2018/3/20.
//  Copyright © 2018年 杨净. All rights reserved.
//
//  email: 1026397500@qq.com
//

#ifndef _WSPUBLIC_H_
#define _WSPUBLIC_H_

#include <uuid/uuid.h> 
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/uio.h>
#include <signal.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <netinet/tcp.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <unwind.h>
#include <dlfcn.h>
#include <time.h>
#include <math.h>
#include <dirent.h>
#include <sys/statvfs.h>

#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <thread>
#include <mutex>
#include <functional>
#include <memory>
#include <algorithm>
#include <chrono>
#include <ctime>
#include <fstream>
#include <experimental/filesystem>

#include "3rd/http_parser.h"
#include "3rd/base64encode.h"
#include "3rd/sha1.h"

#include "CommonLog.h"
#include "3rd/cJSON.h"

namespace fs = std::experimental::filesystem;

namespace mfs
{

inline uint8_t swapBigEndian(uint8_t value) noexcept
{
    return value;
}
    
inline char swapBigEndian(char value) noexcept
{
    return value;
}

inline uint16_t swapBigEndian(uint16_t value) noexcept
{
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
    return __builtin_bswap16(value);
#else
    return value;
#endif
}

inline uint32_t swapBigEndian(uint32_t value) noexcept
{
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
    return __builtin_bswap32(value);
#else
    return value;
#endif
}

inline uint64_t swapBigEndian(uint64_t value) noexcept
{
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
    return __builtin_bswap64(value);
#else
    return value;
#endif
}
    
inline int16_t swapBigEndian(int16_t value) noexcept
{
    return swapBigEndian(static_cast<uint16_t>(value));
}

inline int32_t swapBigEndian(int32_t value) noexcept
{
    return swapBigEndian(static_cast<uint32_t>(value));
}

inline int64_t swapBigEndian(int64_t value) noexcept
{
    return swapBigEndian(static_cast<uint64_t>(value));
}

struct NoCopy
{
    NoCopy() = default;
    NoCopy(const NoCopy &) = delete;
    NoCopy& operator=(const NoCopy&) = delete;
};

#define ERROR_FLAG (EPOLLHUP | EPOLLERR | EPOLLRDHUP)

enum SocketType
{
    WebsocketServiceType = 0,
    RtpServiceType,
    VideoInfoServiceType,

    StoreInfoServiceType,

    ServiceTypeEnd,                     // 分割线

    WebsocketClientType,
    RtpClientType,
    VideoInfoClientType,

    StoreInfoClientType,
};

inline int CreateDir(const char *sPathName) 
{
    char DirName[256];
    strcpy(DirName, sPathName);
    int i, len = strlen(DirName);
    if (DirName[len - 1] != '/')
    strcat(DirName, "/");
    len = strlen(DirName);
    for (i = 1; i < len; i++) 
    {
        if (DirName[i] == '/') 
        {
            DirName[i] = 0;
            if (access(DirName, 0) != 0)
            {
                if (mkdir(DirName, 0777) == -1) 
                {
                    perror("mkdir error");
                    return -1;
                }
            }
            DirName[i] = '/';
        }
    }
    return 0;
}


inline void WriteUint32LE(char* p, uint32_t value)
{
	p[0] = value & 0xff;
	p[1] = value >> 8;
	p[2] = value >> 16;
	p[3] = value >> 24;
}
inline void WriteUint32BE(char* p, uint32_t value)
{
	p[0] = value >> 24;
	p[1] = value >> 16;
	p[2] = value >> 8;
	p[3] = value & 0xff;
}

inline void WriteUint24BE(char* p, uint32_t value)
{
	p[0] = value >> 16;
	p[1] = value >> 8;
	p[2] = value & 0xff;
}


inline void WriteUint16BE(char* p, uint16_t value)
{
	p[0] = value >> 8;
	p[1] = value & 0xff;
}

inline uint16_t ReadUint16BE(char* data)
{
	uint8_t* p = (uint8_t*)data;
	uint16_t value = (p[0] << 8) | p[1];
	return value; 
}
inline uint64_t ReadUint64BE(char* data)
{
    uint8_t* p = (uint8_t*)data;
    uint64_t value = ((uint64_t)p[0] << 56) | ((uint64_t)p[1] << 48) | ((uint64_t)p[2] << 40) |( (uint64_t)p[3]<<32)|( (uint64_t)p[4]<<24)|( (uint64_t)p[5]<<16)|( (uint64_t)p[6]<<8)|((uint64_t) p[7]);
    return value;
}
inline uint32_t ReadUint32BE(char* data)
{
    uint8_t* p = (uint8_t*)data;
    uint32_t value = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
    return value;
}
inline uint32_t ReadUint24BE(char* data)
{
    uint8_t* p = (uint8_t*)data;
    uint32_t value = (p[0] << 16) | (p[1] << 8) | p[2];
    return value;
}

inline uint32_t ReadUint24LE(char* data)
{
    uint8_t* p = (uint8_t*)data;
    uint32_t value = (p[2] << 16) | (p[1] << 8) | p[0];
    return value;
}

inline std::string getNowStr()
{
    auto t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    char timeStr[256] = {0};
    strftime(timeStr, 256, "%y%m%d%H%M%S", std::localtime(&t));
    return timeStr;
}
inline struct tm getNowTm(){
        std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
        auto t = std::chrono::system_clock::to_time_t(now);
        auto lt = std::localtime(&t);
        return *lt;
}

inline std::chrono::system_clock::time_point str2time1078(const std::string& str){
    struct tm tm_ptr;
    strptime(str.c_str(), "%y%m%d%H%M%S", &tm_ptr);
    tm_ptr.tm_isdst = -1;
    auto timet2 = mktime(&tm_ptr);
    auto ftime = std::chrono::system_clock::from_time_t(timet2);
    return ftime;
}
inline std::string time2str1078(std::chrono::system_clock::time_point time){
    auto t = std::chrono::system_clock::to_time_t(time);
    char timeStr[256] = {0};
    strftime(timeStr, 256, "%y%m%d%H%M%S", std::localtime(&t));
    return timeStr;
}

inline bool isDigitStr(const char* str, int len)
{
    return strspn(str, "0123456789") == len;
}

template<typename T>
inline void VectorRemoveObject(std::vector<T>& vec, const T& obj) 
{
    auto iter = find(vec.begin(),vec.end(), obj);
    if (iter != vec.end())
    {
        vec.erase(iter);
    }
}
//判断字符串是否包含某字符串
//@params:str:大的字符串
//@params:contains_str:所包含的字符串
//@return: false:未包含 true：包含
inline bool IsContainsStr(const std::string& str, const std::string& contains_str)
{
	std::string::size_type idx = str.find(contains_str);
	if (idx!=std::string::npos)
	{
		return true;
	}
	else
	{
		return false;
	}
}


inline void PrintBuffer(void* pBuff, unsigned int nLen)
{
    printf("------------------BUFFER(%p)-------------------\n", pBuff);
    if (NULL == pBuff || 0 == nLen)
    {
        return;
    }

    const int nBytePerLine = 16;
    unsigned char* p = (unsigned char*)pBuff;
    char szHex[3*nBytePerLine+1] = {0};
    for (unsigned int i=0; i<nLen; ++i)
    {
        int idx = 3 * (i % nBytePerLine);
        if (0 == idx)
        {
            memset(szHex, 0, sizeof(szHex));
        }
#ifdef WIN32
        sprintf_s(&szHex[idx], 4, "%02x ", p[i]);// buff长度要多传入1个字节
#else
        snprintf(&szHex[idx], 4, "%02x ", p[i]); // buff长度要多传入1个字节
#endif
        
        // 以16个字节为一行，进行打印
        if (0 == ((i+1) % nBytePerLine))
        {
            printf("%s\n", szHex);
        }
    }

    // 打印最后一行未满16个字节的内容
    if (0 != (nLen % nBytePerLine))
    {
        printf("%s\n", szHex);
    }
    printf("------------------end-------------------\n");
}

template< typename T >
struct array_deleter
{
    void operator ()(T const * p)
    {
        delete[] p;
    }
};
}

#define SAMPLE_RATE         8000
#define CHANNELS            1
#define BIT_DEPTH_BYTES     2

#define LOG_FILE_NAME "/tmp/MediaForwardService"

#define SSL_FILE_KEY "ssl/ssl.key"
#define SSL_FILE_CERT "ssl/ssl.crt"

#define WRITE_BUFFER_MAX 1024000
#define WRITE_BUFFER_STEP 8192
#define READ_BUFFER_STEP 8192
// #define READ_BUUFER_MAX 1024000

#define SOCKET_TIMEOUT_SECONDS 10

#define STREAM_LOG_RATE 150


#define AUDIOFORMAT_ADPCMA  "ADPCMA"
#define AUDIOFORMAT_G72616  "G726-16K"
#define AUDIOFORMAT_G72624  "G726-24K"
#define AUDIOFORMAT_G72632  "G726-32K"
#define AUDIOFORMAT_G72640  "G726-40K"
#define AUDIOFORMAT_G711A   "G711a"
#define AUDIOFORMAT_G711U   "G711u"

enum PLAY_TYPE {
    REALTIME = 0, TALKBACK = 1, PLAYBACK = 2
};

enum WEBSOCKET_STATUS {
    WEBSOCKET_INIT,                 // 初始化
    PARSE_HEAD_COMPLETED,           // 接收到头信息(仅websocket)
    SEND_HANDSHAKE                  // 发送完头信息(仅websocket)
};


enum WebSocketOpcodeType {
    CONTINUATION = 0x0,
    TEXT_FRAME = 0x1,
    BINARY_FRAME = 0x2,
    CLOSE = 8,
    PING = 9,
    PONG = 0xa,
};
struct WebSocketHead
{
    uint8_t opCode: 4;
    uint8_t rsv3: 1;
    uint8_t rsv2: 1;
    uint8_t rsv1: 1;
    uint8_t fin: 1;
    uint8_t payloadLength: 7;
    uint8_t mask: 1;
    uint8_t dataLen[8];
} __attribute__ ((packed));

// //目标类型 目标ip 目标端口 消息类型  连接开始时间  连接断开时间  连接断开原因  连接接收流量  连接发送流量  SIM卡号  通道号 会话UUID
struct StreamInfo
{
    std::string targetID="0";           // 流id
    std::string targetType="0";         // 0:终端；1:web; 2:app
    std::string ip="0";                 
    std::string port="0";               
    std::string state="-1";             // -1:默认; 0:建立连接; 1:信息解析完成; 2:关闭连接; 
    std::string timestampStart="0";     // 建立连接时间戳
    std::string timestampEnd="0";       // 连接断开时间戳
    std::string message="";             // 连接断开信息
    std::string sendBytes="0";          // 服务器发送给该连接的数据
    std::string recvBytes="0";          // 服务器从该连接接收到的数据
    std::string simNumber="0";          // sim卡号
    std::string channel="0";            // 通道号
    std::string timestampStartData="0";     // 建立连接时间戳
    std::string uuid="0";               // 房间id
    std::string playType="0";			// 播放类型(0:实时、1:回放、2:对讲)
    std::string userID="0";				// 用户ID
    std::string vehicleId="0";			// 车辆id
};

#endif
