

#ifndef _BASEPROTOCOL_H_
#define _BASEPROTOCOL_H_

#include "MFSPublic.h"
#include "3rd/uvw.hpp"
#include "BaseWriteBuffer.h"

namespace mfs
{



#define logstream(f,l,a,r) {                    \
    if (f > r) {                                \
        std::stringstream ss;                   \
        ss<<"all="<<a<<",data length="<<l;      \
        logv(ss.str());                         \
        f=0;                                    \
    } else {                                    \
        f++;                                    \
    }                                           \
}

// 基于tcp&libuv&uvw的应用层协议封装
class BaseProtocol: public std::enable_shared_from_this<BaseProtocol>
{
    protected:
    uint64_t _streamID = 0;

    bool _saveData = false;
    std::string _saveFilePathRecv = "";
    std::string _saveFilePathSend = "";
    std::ofstream _fileRecv;
    std::ofstream _fileSend;

    std::weak_ptr<uvw::Loop> _loop;
    std::weak_ptr<uvw::TCPHandle> _client;
    // std::vector<uint8_t> _writeBuffer;
    std::list<BaseWriteBuffer> _listWriteBuffer;
    std::list<BaseWriteBuffer> _listWritedBuffer;
    int _writeBufferSize = 0;
    int _writedBufferSize = 0;

    std::string _serviceName;
    std::string _clientIp = "0.0.0.0";
    int _clientPort = 0;
    std::string _thisIp = "0.0.0.0";
    int _thisPort = 0;

    // 连接最终write的缓存
    std::ofstream _cacheTestStream;
    // 连接处理好的data存储
    std::ofstream _cacheTestData;

    uint64_t    _writeBytesAll = 0;
    uint64_t    _readBytesAll = 0;
    
    bool _lastDataUpdate = false;                                       // 最后一次数据过来时，是否刷新了激活时间
    bool _lastDataUpdate2 = false;                                       // 最后一次数据过来时，是否刷新了激活时间
    uvw::Loop::Time _lastActiveTime;                                    // 记录最后一次有效操作的时间戳
    uvw::Loop::Time _lastDataTime;                                    // 记录最后一次数据的时间戳
    uint64_t _timeoutMilli;                                             // 超时时间

    StreamInfo _streamInfo;

    bool _hookfd = false;                                               // 是否拦截数据的读取,_hookfd为true且自定义alloc时，接收通知手动读取fd
    std::function<void(BaseProtocol*, uv_buf_t*)> _onBeforeData;                                  // 接收到数据
    // uv_handle_t *handle

    std::shared_ptr<uvw::TCPHandle> shareClient() 
    {
        auto result = _client.lock();
        if (!result)
        {
            LOG_ERROR << "TCPHandle is nullptr" << LOG_ENDL;
        }
        return result;
    }
    std::shared_ptr<uvw::Loop> shareLoop() 
    {
        auto result = _loop.lock();
        if (!result)
        {
            LOG_ERROR << "Loop is nullptr" << LOG_ENDL;
        }
        return result;
    }

    void writeOneBuffer();
    void removeBuffer(uint8_t* buffer, int& bufferLength,int removeLength){
        
        bufferLength -= removeLength;
        if (bufferLength<=0)
        {
            bufferLength = 0;
        }
        else if (bufferLength> 0)
        {
            memcpy(buffer, buffer+removeLength, bufferLength);
        }
    }
    public:
    BaseProtocol(std::shared_ptr<uvw::Loop> loop, std::shared_ptr<uvw::TCPHandle> client, const std::string& name);
    virtual ~BaseProtocol()
    {
        logv(_serviceName + " client free.");
        if (_fileRecv.is_open())
        {
            _fileRecv.close();
        }
        if (_fileSend.is_open())
        {
            _fileSend.close();
        }
        

    }
    void UpdateAddress(const uvw::Addr& addr, const uvw::Addr& addrlocal)
    {
        _clientIp = addr.ip;
        _clientPort = addr.port;
        _thisIp = addrlocal.ip;
        _thisPort = addrlocal.port;
        _streamInfo.ip = addr.ip;
        _streamInfo.port = std::to_string(addr.port);
    }
    
    virtual void OnData(char* data, int dataLen);
    virtual void OnAlloc(uv_buf_t *buf, int suggested);
    virtual void OnClose();
    virtual void OnConnection();
    virtual void OnWrite(const uvw::WriteEvent &event);
    virtual void OnError(const uvw::ErrorEvent &event);
    virtual void OnEnd();

    virtual void PreAlloc(uv_buf_t *buf, int suggested) final;
    
    virtual int Write(char* data, int dataLen, bool forced = false);
    virtual int Write2(char* data, int dataLen, bool forced = false);
    
    virtual void OnReady();
    
    virtual int WriteV(iovec* dataList, int size, bool forced=false);
    virtual int WriteV2(iovec* dataList, int size, bool forced=false);

    virtual void Close()
    {
        if (auto ptrClient = shareClient())
        {
            ptrClient->close();
        }
    }

    virtual void SetTimeoutValue(int timeoutMilli)
    {
        _timeoutMilli = timeoutMilli;
    }
    virtual int GetTimeoutValue()
    {
        return _timeoutMilli;
    }
    virtual void UpdateActiveTime()
    {
        if (auto ptrLoop = shareLoop())
        {
            _lastActiveTime = ptrLoop->now();
        }
    }
    void UpdateConnectionFlag(int v){
        _lastDataUpdate2 = v;
        if (_lastDataUpdate2 == 1)
        {
            this->UpdateActiveTime();
        }
    }
    bool ClearWriteBuffer()
    {
        _writeBufferSize = 0;
        _listWriteBuffer.clear();
        return false;
    }
    virtual bool CheckTimeout(int timeoutMilli = -1);

    void OnRecvData(int len){_readBytesAll+=len;}

    virtual void alogd(const std::string& message, const std::string& fileName, const int line, const std::string& functionName) 
    {
        LOG_DEBUG2 <<"["<< _thisPort <<"] "<<"["<<_clientIp <<":"<< _clientPort <<"] " <<"["<<mfs::logErrConsole.filtersFileName(fileName)<<":"<<line<<"] "<<functionName<<"(): >>>> " << message <<LOG_ENDL;
    }
    virtual void aloge(const std::string& message, const std::string& fileName, const int line, const std::string& functionName) 
    {
        LOG_ERROR2 <<"["<< _thisPort <<"] "<<"["<<_clientIp <<":"<< _clientPort <<"] " <<"["<<mfs::logErrConsole.filtersFileName(fileName)<<":"<<line<<"] "<<functionName<<"(): >>>> " << message <<LOG_ENDL;
    }
    virtual void alogv(const std::string& message, const std::string& fileName, const int line, const std::string& functionName) 
    {
        LOG_VERBOSE2 <<"["<< _thisPort <<"] "<<"["<<_clientIp <<":"<< _clientPort <<"] " <<"["<<mfs::logErrConsole.filtersFileName(fileName)<<":"<<line<<"] "<<functionName<<"(): >>>> " << message <<LOG_ENDL;
    }
    
    void SetOnBeforeDataCallback(std::function<void(BaseProtocol*, uv_buf_t*)> callback)
    {
        _onBeforeData = callback;
    } 

    std::shared_ptr<uvw::TCPHandle> Handle(){return _client.lock();}
    uint64_t ID (){return _streamID;}
    void SaveData(bool v);
    const StreamInfo& GetStreamInfo(){return _streamInfo;}
    uv_os_fd_t getfd() 
    {
        auto pclient = Handle();
        // if (uvwfd == UV_EINVAL || uvwfd == UV_EBADF)
        return pclient?pclient->fileno():UV_EINVAL;
    }
    bool hookfd() {return _hookfd;}
    void hookfd(bool v){_hookfd=v;}
};

typedef std::function<BaseProtocol*(std::shared_ptr<uvw::Loop> loop, std::shared_ptr<uvw::TCPHandle> client, const std::string& name)> BaseClientCreator;

}

#endif // _BASECLIENT_H_