#include "Thread.h"

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


namespace jf {

Thread::Thread(std::string const& strName)
    : m_strName(strName),
      m_thread(-1),
      m_stopEvent("", true, false),  // unnamed, mannual-reset, unsignalled.
      m_stopedEvent("", true, false) {}

Thread::~Thread() {}

bool Thread::start() {
    if (active()) {
        return true;
    }
    bool bret = pthread_create(&m_thread, NULL, threadproc, (void*)this);
    if (!bret) {
        return false;
    }
    pthread_setname_np(m_thread, m_strName.c_str());
    return true;
}

bool Thread::stop(unsigned uTimeout, bool bForce) {
    if (pthread_t(-1) == m_thread) return true;

    if (!active()) {
        pthread_join(m_thread, NULL);
        m_thread = -1;
        return true;
    }
    // inform it to die:
    m_stopEvent.set();
    pthread_t threadID = pthread_self();
    if (threadID == m_thread) {
        return true;
    }
    if (INFINITE == uTimeout) {
        while (1) {
            if (m_stopedEvent.wait(1000)) break;
            if (pthread_kill(m_thread, 0)) break;
        }
        pthread_join(m_thread, NULL);
        m_thread = -1;
        return true;
    }

#ifdef __ANDROID__
    if (!m_stopedEvent.wait(uTimeout)) {
        if (!bForce) return false;

        int nRet = pthread_kill(m_thread, SIGRTMIN + 1);
        if (nRet) {
            return false;
        }
    }
#else
    if (!m_stopedEvent.wait(uTimeout)) {
        if (!bForce) {
            return false;
        }
        pthread_cancel(m_thread);
    }
#endif
    pthread_join(m_thread, NULL);
    m_thread = -1;
    return true;
}

bool Thread::signalled() { return m_stopEvent.wait(0); }

bool Thread::active() const {
    if (-1 == (int)m_thread) return false;

    int nRet = pthread_kill(m_thread, 0);
    if (ESRCH == nRet) return false;
    return true;
}

Event& Thread::stop_event() { return m_stopEvent; }

void* Thread::threadproc(void* obj) {
    unsigned unRet = 0;
    if (!obj) {
        return (void*)unRet;
    }
    Thread* pThread = (Thread*)obj;
#ifndef __ANDROID__
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
#endif
    unRet = pThread->run();
    pThread->m_stopedEvent.set();
    return (void*)unRet;
}

}  // namespace jf