
#ifndef _BASECLIENT_H_
#define _BASECLIENT_H_

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

namespace mfs
{

// 基于tcp&libuv&uvw的传输层封装
class ClientManager
{
protected:
    std::shared_ptr<uvw::Loop> _loop = nullptr;

    std::vector<std::shared_ptr<BaseProtocol>> _clients;

    static ClientManager* _instance;
    
    ClientManager(std::shared_ptr<uvw::Loop> loop):_loop(loop){}
public:
    
    std::shared_ptr<BaseProtocol> ConnectServer(const std::string& ip, int port, const std::string& name, BaseClientCreator creator)
    {

        std::shared_ptr<uvw::TCPHandle> client = _loop->resource<uvw::TCPHandle>();
        client->on<uvw::CloseEvent>([this](const uvw::CloseEvent &, uvw::TCPHandle &client) 
        {
            auto ptrClient = client.data<BaseProtocol>();
            VectorRemoveObject(_clients, ptrClient);
            ptrClient->OnClose();
        });
        client->on<uvw::WriteEvent>([this](const uvw::WriteEvent &event, uvw::TCPHandle &client) 
        {
                client.data<BaseProtocol>()->OnWrite(event);
        });
        client->on<uvw::EndEvent>([](const uvw::EndEvent &, uvw::TCPHandle &client) { 
            client.data<BaseProtocol>()->OnEnd();
            client.close(); 
        });
        client->on<uvw::ErrorEvent>([this](const uvw::ErrorEvent &event, uvw::TCPHandle &client) {
            client.data<BaseProtocol>()->OnError(event);
            client.close();
        });
        client->on<uvw::DataEvent>([this](uvw::DataEvent &event, uvw::TCPHandle &client) 
        {
            // LOG_DEBUG << "DataEvent" <<LOG_ENDL;
            client.data<BaseProtocol>()->OnRecvData((int)event.length);
            if (client.userAlloc())
            {
                client.data<BaseProtocol>()->OnData(event.data.release(), (int)event.length);
            }
            else
            {
                client.data<BaseProtocol>()->OnData(event.data.get(), (int)event.length);
            }
            
        });
        client->on<uvw::AllocEvent>([this](const uvw::AllocEvent &event, uvw::TCPHandle &client) 
        {
            // LOG_DEBUG << "AllocEvent" <<LOG_ENDL;
            client.data<BaseProtocol>()->OnAlloc(event.buf, (int)event.suggested);
        });
        client->once<uvw::ConnectEvent>([](const uvw::ConnectEvent &, uvw::TCPHandle &client) {
            // ASSERT_TRUE(handle.writable());
            // ASSERT_TRUE(handle.readable());
            // LOG_DEBUG << "ConnectEvent:"<<client.readable() <<LOG_ENDL;
            auto ptrClient = client.data<BaseProtocol>();
            uvw::Addr remote = client.peer();
            uvw::Addr local = client.sock();
            ptrClient->UpdateAddress(remote,local);
            ptrClient->OnConnection();
            client.read();
        });
        client->connect(ip, port);
    
        std::shared_ptr<BaseProtocol> baseclientptr(creator(_loop, client, name));
        _clients.push_back(baseclientptr);
        client->data(baseclientptr);
        return baseclientptr;
    }

    void CheckAllTimeout()
    {
        // LOG_DEBUG << "CheckAllTimeout" <<LOG_ENDL;
        std::vector<std::shared_ptr<BaseProtocol>> lstDelete;
        for (auto iter = _clients.begin(); iter != _clients.end(); iter++)
        {
            auto bret = (*iter)->CheckTimeout();
            if (bret)
            {
                lstDelete.push_back(*iter);
                // iter->second->Close();
                break;
            }
        }
        // LOG_DEBUG << "CheckAllTimeout - DELETE" <<LOG_ENDL;
        for (size_t i = 0; i < lstDelete.size(); i++)
        {
            lstDelete[i]->Close();
        }
    }
    void SaveDataByTargetID(uint64_t targetID, bool enable)
    {
        for (auto iter = _clients.begin(); iter != _clients.end(); iter++)
        {
            if ((*iter)->ID() == targetID)
            {
                (*iter)->SaveData(enable);
            }
        }
    }
    void GetAllStreamInfo(std::vector<StreamInfo>& result)
    {
        for (auto iter = _clients.begin(); iter != _clients.end(); iter++)
        {
            result.push_back((*iter)->GetStreamInfo());
        }
    }

    static void SetupOnce(std::shared_ptr<uvw::Loop> loop)
    {
        if (_instance)
        {
            delete _instance;
            _instance = nullptr;
        }
        
        _instance = new ClientManager(loop);
    }
    static ClientManager* Instance()
    {
        return _instance;
    }
};


}


#endif // _BASECLIENT_H_