#include "Event.h"

#include <errno.h>
#include <signal.h>

namespace jf {
EventException::EventException(::std::string const& strWhat, unsigned uCode) {
    m_strWhat = strWhat;
    m_uCode = uCode;
}

EventException::~EventException() {}

Event::Event(::std::string const& strName, bool bMannual, bool bSet) {
    m_strName = strName;
    m_bMannual = bMannual;
    m_bSet = bSet;
    int nRet = pthread_mutex_init(&m_mutex, NULL);
    if (nRet) {
        throw EventException("init mutex fail.", nRet);
    }
    nRet = pthread_cond_init(&m_cond, NULL);
    if (nRet) {
        throw EventException("init cond fail.", nRet);
    }
}

Event::~Event() {
    pthread_cond_destroy(&m_cond);
    pthread_mutex_destroy(&m_mutex);
}

bool Event::wait(unsigned uTimeout) {
    pthread_mutex_lock(&m_mutex);
    if (m_bSet) {
        if (!m_bMannual) {
            m_bSet = false;
        }
        pthread_mutex_unlock(&m_mutex);
        return true;
    }
    if (uTimeout) {
        if (INFINITE != uTimeout) {
            timespec ts;
            clock_gettime(CLOCK_REALTIME, &ts);
            ts.tv_sec += (uTimeout / 1000);
            ts.tv_nsec += ((uTimeout % 1000) * 1000 * 1000);
            if (ts.tv_nsec / 1000000000) {
                ts.tv_sec += ts.tv_nsec / 1000000000;
                ts.tv_nsec = ts.tv_nsec % 1000000000;
            }
            pthread_cond_timedwait(&m_cond, &m_mutex, &ts);
        } else {
            pthread_cond_wait(&m_cond, &m_mutex);
        }
    }

    bool bRet = m_bSet;
    if (!m_bMannual) m_bSet = false;
    pthread_mutex_unlock(&m_mutex);
    return bRet;
}

void Event::set() {
    pthread_mutex_lock(&m_mutex);
    m_bSet = true;
    pthread_cond_broadcast(&m_cond);
    pthread_mutex_unlock(&m_mutex);
}

void Event::reset() {
    pthread_mutex_lock(&m_mutex);
    m_bSet = false;
    pthread_mutex_unlock(&m_mutex);
}
}  // namespace jf
