
#ifndef _BASESERVICE_H_
#define _BASESERVICE_H_

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

namespace mfs
{

// 基于tcp&libuv&uvw的传输层封装
class BaseService
{
protected:
    std::shared_ptr<uvw::Loop> _loop = nullptr;
    int _port = 0;
    std::string _name;

    BaseClientCreator _creator = nullptr;

    bool _init = false;
    bool _abort = false;
    bool _running = false;
    std::shared_ptr<uvw::TCPHandle> _tcpserver;
    std::vector<std::shared_ptr<BaseProtocol>> _clients;
    // std::map<std::shared_ptr<uvw::TCPHandle>, std::shared_ptr<BaseProtocol>> _clients;

    void InitLoop(uvw::Loop& loop, int port)
    {
        _tcpserver = loop.resource<uvw::TCPHandle>();
        // _tcpserver
        _tcpserver->on<uvw::ErrorEvent>([this](const uvw::ErrorEvent & event, uvw::TCPHandle &) {
            if (ECONNRESET != event.code() &&  -ECONNRESET != event.code())
            {
                LOG_ERROR << "server("<< _name <<":"<<_port<<") error="<< event.code()<<",name="<<event.name()<<",waht="<<event.what() << LOG_ENDL;
            }
        });
        _tcpserver->once<uvw::CloseEvent>([this](const uvw::CloseEvent &, uvw::TCPHandle &) {
            LOG_DEBUG << "server("<< _name <<":"<<_port<<") close" <<LOG_ENDL;
        });
        _tcpserver->on<uvw::ListenEvent>([this](const uvw::ListenEvent &, uvw::TCPHandle &srv) {
            std::shared_ptr<uvw::TCPHandle> client = srv.loop().resource<uvw::TCPHandle>();
            client->on<uvw::CloseEvent>([this](const uvw::CloseEvent &, uvw::TCPHandle &client) 
            {
                auto ptrClient = client.data<BaseProtocol>();
                // client.data(nullptr);
                VectorRemoveObject(_clients, ptrClient);
                ptrClient->OnClose();
                // LOG_DEBUG << "CloseEvent("<<_name<<"),_clients:"<<_clients.size()<<",ptrClient="<<(void*)ptrClient.get()<<",count="<<ptrClient.use_count() << LOG_ENDL;
                //  client.data(nullptr);
                //  _clients[client.shared_from_this()]->OnClose();
                //  _clients.erase(client.shared_from_this());
            });
            client->on<uvw::WriteEvent>([this](const uvw::WriteEvent &event, uvw::TCPHandle &client) 
            {
                 client.data<BaseProtocol>()->OnWrite(event);
                //  _clients[client.shared_from_this()]->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);
                // _clients[client.shared_from_this()]->OnError(event);
                client.close();
            });
            client->on<uvw::DataEvent>([this](uvw::DataEvent &event, uvw::TCPHandle &client) 
            {
                client.data<BaseProtocol>()->OnRecvData((int)event.length);
                if (client.userAlloc())
                {
                    // LOG_DEBUG << "uvw::DataEvent release" << LOG_ENDL;
                    client.data<BaseProtocol>()->OnData(event.data.release(), (int)event.length);
                    // _clients[client.shared_from_this()]->OnData(event.data.release(), (int)event.length);
                }
                else
                {
                    // LOG_DEBUG << "uvw::DataEvent get" << LOG_ENDL;
                    client.data<BaseProtocol>()->OnData(event.data.get(), (int)event.length);
                    // _clients[client.shared_from_this()]->OnData(event.data.get(), (int)event.length);
                }
                
            });
            client->on<uvw::AllocEvent>([this](const uvw::AllocEvent &event, uvw::TCPHandle &client) 
            {
                client.data<BaseProtocol>()->PreAlloc(event.buf, (int)event.suggested);
                //  _clients[client.shared_from_this()]->OnAlloc(event.buf, (int)event.suggested);
            });
		
            std::shared_ptr<BaseProtocol> baseclientptr(_creator(srv.loop().shared_from_this(), client, _name));
            // _clients.insert(std::pair<std::shared_ptr<uvw::TCPHandle>, std::shared_ptr<BaseProtocol>>(client, baseclientptr));
            _clients.push_back(baseclientptr);
            client->data(baseclientptr);
            srv.accept(*client);
            uvw::Addr remote = client->peer();
            uvw::Addr local = client->sock();
            baseclientptr->UpdateAddress(remote, local);
            baseclientptr->OnConnection();
            OnListen(baseclientptr);
            client->read();
            
            // auto ptrClienttt = client->data<BaseProtocol>();
            // LOG_DEBUG << "ListenEvent("<<_name<<"),_clients:"<<_clients.size()<<",ptrClient="<<(void*)ptrClienttt.get() << LOG_ENDL;
        });

        _tcpserver->bind("0.0.0.0", port);
        _tcpserver->listen();

    }
    void Loop()
    {
        if (!_loop)
        {
            _loop = uvw::Loop::create();
            this->InitLoop(*_loop, _port);
        }
        _loop->run();
        _running = false;
    }

    virtual void OnListen(std::shared_ptr<BaseProtocol> client){};

public:
    BaseService(const std::string& name, int port, std::shared_ptr<uvw::Loop> loop):_name(name),_port(port),_loop(loop){}

    virtual void Init(BaseClientCreator creator)
    {
        _creator = creator;
        if (!_creator)
        {
            return;
        }
        
        if (!_loop)
        {
            _loop = uvw::Loop::create();
        }
        this->InitLoop(*_loop, _port);
        _init = true;
    }
    virtual void Start(bool async = true)
    {
        if (_running)
        {
            return;
        }
        if (!_init)
        {
            return;
        }
        
        _running = true;
        _abort=false;

        if (async)
        {
            // dynamic_cast<>
            std::thread(&BaseService::Loop, this).detach();
        }
        else
        {
            this->Loop();
        }
    }
    
    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());
        }
    }
};


}


#endif // _BASESERVICE_H_