#include <common.h>
#include <FCGI/SocketHandler.h>
#include <FCGI/RecordReader.h>
#include <sys/epoll.h>

#define ON_ERRNO() recordError(__LINE__,errno)
#define ON_ERROR(S) recordError(__LINE__,(S))

static void recordError(int iLine,int iError) {
    TRACE_PRINT(("*" __FILE__ "(%d) - ERROR(%d) %s",iLine,iError,::strerror(iError)));
}

static void recordError(int iLine,const char* sError) {
    TRACE_PRINT(("*" __FILE__ "(%d) - ERROR %s",iLine,sError));
}

struct FCGI::AcceptHandler: FCGI::SocketHandler {
    SOCKET socket;
    int hPoll;
    virtual void onRead();
};

struct FCGI::ConnectionHandler: FCGI::SocketHandler {
    SOCKET socket;
    FCGI::RecordReader reader;
    virtual void onRead();
    virtual void onWrite();
};

static bool makeNonBlocking(SOCKET socket) {
    int v = fcntl(socket,F_GETFL,0);
    return (0 <= v) && (0 <= fcntl(socket,F_SETFL,v | O_NONBLOCK));
}

void FCGI::AcceptHandler::onRead() {
    TRACE_FN(AcceptHandler::onRead);

    struct sockaddr_storage addressClient;
    socklen_t lengthAddress = sizeof(addressClient);
    SOCKET socketClient = ::accept(socket,(struct sockaddr*) &addressClient,&lengthAddress);
    if (socketClient < 0) {
        if ((EWOULDBLOCK == errno) || (EAGAIN == errno)) {
            return; // ignore
        }
        ON_ERRNO();
        return;
    }
    //TRACE_PRINT(("*CONNECTION from ",addressClient.))
    if (!makeNonBlocking(socketClient)) {
        ON_ERRNO();
        return;
    }

    struct epoll_event ev;
    ev.events = EPOLLIN | EPOLLET | EPOLLOUT;
    ev.data.ptr = new ConnectionHandler(socketClient);
    if (epoll_ctl(hPoll,EPOLL_CTL_ADD,socketClient,&ev)) {
        ON_ERRNO();
        return;
    }
}

void FCGI::ConnectionHandler::onRead() {
    TRACE_FN(ConnectionHandler::onRead);
    reader.onRead(socket);
}

void FCGI::ConnectionHandler::onWrite() {
    TRACE_FN(ConnectionHandler::onWrite);
    // TODO
}