#include "vn_client_curl.h"
#include "vn_client_internal.h"

VN_CURL_Event_Handler::VN_CURL_Event_Handler()
{
    cm_ = curl_multi_init();
    
    FD_ZERO(&rfds_);
    FD_ZERO(&wfds_);
    FD_ZERO(&efds_);
}

/*virtual*/ VN_CURL_Event_Handler::~VN_CURL_Event_Handler()
{
//    ACE_Guard<ACE_Recursive_Thread_Mutex> g(lock_);
    
    // ACE_Reactor::instance()->remove_handler(this, READ_MASK);
    // ACE_Reactor::instance()->remove_handler(this, WRITE_MASK);
    // ACE_Reactor::instance()->remove_handler(this, EXCEPT_MASK);
    // ACE_Reactor::instance()->remove_handler(this, TIMER_MASK);

    curl_multi_cleanup(cm_);
    
    cm_ = 0;
}

void VN_CURL_Event_Handler::perform(const VN_Resource<CURL> &curl)
{
    ACE_Reactor::instance()->schedule_timer(this, (CURL*)curl, ACE_Time_Value(0));
}

/*virtual*/ int VN_CURL_Event_Handler::handle_timeout(const ACE_Time_Value &current_time, const void *act)
{
//    ACE_Guard<ACE_Recursive_Thread_Mutex> g(lock_);

    if (act != 0)
    {
        CURL *curl = (CURL*)act;
        curl_multi_add_handle(cm_, curl);
    }

    ACE_Reactor::instance()->remove_handler(ACE_Handle_Set(rfds_), READ_MASK);
    ACE_Reactor::instance()->remove_handler(ACE_Handle_Set(wfds_), WRITE_MASK);
    ACE_Reactor::instance()->remove_handler(ACE_Handle_Set(efds_), EXCEPT_MASK);

    int running_handles;
    curl_multi_perform(cm_, &running_handles);

    if (running_handles == 0)
    {
        // if no running handles we need to do curl_multi_info_read() anyway 
        handle_curl_multi(ACE_INVALID_HANDLE);
        return 0;
    }

    // clearing sets, as they will be filled bellow again
    FD_ZERO(&rfds_);
    FD_ZERO(&wfds_);
    FD_ZERO(&efds_);

    int max_fd;
    if (curl_multi_fdset(cm_, &rfds_, &wfds_, &efds_, &max_fd)) 
    {
        fprintf(stderr, "E: curl_multi_fdset\n");
        return 0;
    }

    if (max_fd == -1) // fdset not ready (http://curl.haxx.se/libcurl/c/curl_multi_fdset.html)
    {
        fprintf(stderr, "max_fd == -1\n");
        ACE_Reactor::instance()->schedule_timer(this, 0, ACE_Time_Value(0, 100000));
        return 0;
    }
       
    ACE_Reactor::instance()->register_handler(ACE_Handle_Set(rfds_), this, READ_MASK);
    ACE_Reactor::instance()->register_handler(ACE_Handle_Set(wfds_), this, WRITE_MASK);
    ACE_Reactor::instance()->register_handler(ACE_Handle_Set(efds_), this, EXCEPT_MASK);
    
    return 0;
}

/*virtual*/ int VN_CURL_Event_Handler::handle_output(ACE_HANDLE fd)
{
//    ACE_Guard<ACE_Recursive_Thread_Mutex> g(lock_);
    
    handle_curl_multi(fd);

    return -1;
}
 
/*virtual*/ int VN_CURL_Event_Handler::handle_exception(ACE_HANDLE fd)
{
//    ACE_Guard<ACE_Recursive_Thread_Mutex> g(lock_);

    handle_curl_multi(fd);

    return -1;
}

/*virtual*/ int VN_CURL_Event_Handler::handle_input(ACE_HANDLE fd)
{
//    ACE_Guard<ACE_Recursive_Thread_Mutex> g(lock_);

    handle_curl_multi(fd);

    return -1;

}

int VN_CURL_Event_Handler::handle_curl_multi(ACE_HANDLE fd)
{
    CURLMsg *msg;
    int msg_in_queue;
    while ((msg = curl_multi_info_read(cm_, &msg_in_queue))) 
    {
        if (msg->msg == CURLMSG_DONE) 
        {
            VN_Client_Result_Handler *rh;
            CURL *e = msg->easy_handle;
            curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &rh);
            assert(rh);
//            fprintf(stderr, "R: (%d) %d - %s <%s>\n",
//                    ++done, msg->data.result, curl_easy_strerror(msg->data.result), (char*)p->user_data);
  
            rh->handle_result(msg->data.result);

            curl_multi_remove_handle(cm_, e);

            delete rh;
        }
        else {
            fprintf(stderr, "E: CURLMsg (%d)\n", msg->msg);
        }
    }


    if (fd != ACE_INVALID_HANDLE)
        ACE_Reactor::instance()->schedule_timer(this, (void*)0, ACE_Time_Value(0));

    return 0;
}

