#include "fd_event.hpp"
#include "logger.hpp"
#include "reactor.hpp"
#include <cstring>
#include <functional>
#include <mutex>
#include <unistd.h>
#include <fcntl.h>
namespace tinyrpc {

    Reactor::Task FdEvent::m_default_callback = [] {
        logger() << "Default callback is calling";
    };



    FdEvent::FdEvent(int fd) : m_fd(fd) {
        
    }

    FdEvent::FdEvent(int fd, Reactor* reactor) : m_fd(fd), m_reactor(reactor) {

    }
    FdEvent:: ~FdEvent() {
        // if(m_fd != -1)
        //     close(m_fd);
    }

    bool FdEvent::setNonblock() {
        if (m_fd < 0) {
            logger() << "error fd < 0 !";
            return false;
        }

        int flag = fcntl(m_fd, F_GETFL);

        if(flag == -1) {
            logger() << "fcntl return -1 err:" << strerror(errno);
            return false;
        }

        flag |= O_NONBLOCK;

        int ret = fcntl(m_fd, F_SETFL, flag);

        if(ret == -1) {
            logger() << "fcntl return -1 err:" << strerror(errno);
            return false;
        }

        return true;
    }
    std::function<void()> FdEvent::getHandler(IOEvent event) const {
        if(event == IOEvent::READ) return m_read_callback;
        else if (event == IOEvent::WRITE)  return m_write_callback;
        logger() << "unknow IOEvent!";
        return nullptr;
    }

    void FdEvent::addListenEvent(IOEvent event) {
        int ev = static_cast<int>(event);
        if(m_listen_events & ev) {
            logger() << "already has this event";
            return;
        }
        m_listen_events |= static_cast<int>(event);
    }
    void FdEvent::delListenEvent(IOEvent event) {
        int ev = static_cast<int>(event);
        if(!(m_listen_events & ev)) {
            logger() << "this event not exist";
            return;
        }
        m_listen_events &= ~static_cast<int>(event);
    }

    void FdEvent::reset() {
        clearListenEvent();
        m_read_callback = m_default_callback;
        m_write_callback = m_default_callback;
    }
    FdEventPool* FdEventPool::getInstance() {
        static FdEventPool pool;
        return &pool;
    }

    FdEvent* FdEventPool::getFdEvent(int fd) {
        // std::lock_guard<std::mutex> lock(m_mtx);
        // if(m_fdEvents.count(fd)) {
        //     return m_fdEvents[fd];
        // }
        // return m_fdEvents[fd] = new FdEvent(fd);
        
        std::lock_guard<std::mutex> lock(m_mtx);
        FdEvent* ret = nullptr;
        if(m_fdEvents.count(fd)) {
            ret = m_fdEvents[fd];
        } else {
            ret = m_fdEvents[fd] = new FdEvent(fd);
        }
        // ret->clearListenEvent();
        return ret;
    }
    
    FdEventPool::~FdEventPool() {
        std::lock_guard<std::mutex> lock(m_mtx);
        for(const auto& item : m_fdEvents) {
            delete item.second;
        }
        m_fdEvents.clear();
    }
}