#include "AdvConvergenceStat.hh"

const std::string AdvConvergenceStat::className=std::string("AdvConvergenceStat");

/**
 *  constructor
 */
AdvConvergenceStat::AdvConvergenceStat() {
#ifdef USE_PTHREAD
#if defined USE_MUTEX
    pthread_mutex_init( &(this->mutex), NULL);
#elif defined USE_RWLOCK
    pthread_rwlock_init( &(this->rwlock), NULL);
#endif

    pthread_cond_init( &(this->guard), NULL);
#endif // USE_PTHREAD
}


AdvConvergenceStat::AdvConvergenceStat(UInt4 capacity) {
    this->capacity=capacity;
    DebugMessage(className, "AdvConvergenceStat(UInt4)", "enter");
    DebugMessage(className, "AdvConvergenceStat(UInt4)", "capacity=%u", this->capacity);
#ifdef USE_PTHREAD
#if defined USE_MUTEX
    pthread_mutex_init( &(this->mutex), NULL);
#elif defined USE_RWLOCK
    pthread_rwlock_init( &(this->rwlock), NULL);
#endif

    pthread_cond_init( &(this->guard), NULL);
    DebugMessage(className, "AdvConvergenceStat(UInt4)", "exit");
#endif // USE_PTHREAD
}

/**
 *  destructor
 */
AdvConvergenceStat::~AdvConvergenceStat() {
    AdvParamSet *entry;

    while ( ! q.empty() ) {
        entry = q.front();
        q.pop_front();
        delete entry;
    }
}

/**
 *  \retval true, if the queue is empty.
 */
Bool AdvConvergenceStat::empty() {
    Bool retval;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_rdlock( &(this->rwlock) );
#endif // lock
    retval = q.empty();
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else
    retval=q.empty();
#endif // USE_PTHREAD
    return retval;
}

/**
 *  \return size of stat entries in the queue.
 */
UInt4 AdvConvergenceStat::size() {
    UInt4 retval;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_rdlock( &(this->rwlock) );
#endif // lock
    retval = q.size();
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else // USE_PTHREAD
    retval=q.size();
#endif // USE_PTHREAD
    return retval;
}

/**
 *  pop the earliest stat from the queuq. the eariest stat is deleted form the queue
 */
AdvParamSet *AdvConvergenceStat::pop() {
    std::string memberName = std::string("pop()");
    DebugMessage(className, memberName, "enter\n");

    AdvParamSet *retval;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_wrlock( &(this->rwlock) );
#endif // lock
    while ( q.empty() ) {
        DebugMessage(className, memberName, __FILE__, __LINE__, "wait\n");
        pthread_cond_wait( &(this->guard), &(this->mutex) );
    }
    retval=q.front();
    q.pop_front();
    DebugMessage(className, memberName, __FILE__, __LINE__, "get returnd value that is %s NULL.\n", ((retval != NULL) ? "not" : "" ));
    pthread_cond_signal( &(this->guard) );
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else // USE_PTHREAD
    if (q.empty()) {
        DebugMessage(className, memberName, __FILE__, __LINE__, "queue is empty.\n");
        retval=NULL;
    } else {
        retval=q.front();
        q.pop_front();
    }
#endif // USE_PTHREAD
    DebugMessage(className, memberName, "exit\n");
    return retval;
}

/**
 *  push the latest stat in the queuq.
 */
void AdvConvergenceStat::push(AdvParamSet *param) {
    std::string memberName = std::string("push(AdvParamSet *)");
    DebugMessage(className, memberName, "enter\n");

#ifdef USE_PTHREAD
#ifdef USE_MUTEX   // Lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_wrlock( &(this->rwlock) );
#endif  // Lock
    //DebugMessage(className, memberName, "size: %u\n", q.size());
    q.push_back(param);
    while (q.size() >= this->capacity) {
        AdvParamSet *fp=q.front();
        q.pop_front();
        DebugMessage(className, memberName, "delete a data in Convergence stat. \"%d \"\n", fp->getInt4(LevmarConsts::ITERATION_COUNT));
        delete fp;
    }
    //DebugMessage(className, memberName, "size: %u\n", q.size());
    pthread_cond_signal( &(this->guard) );
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else // USE_PTHREAD
    q.push_back(param);
#endif // USE_PTHREAD

    DebugMessage(className, memberName, "exit\n");
}

/**
 *  refer the earliest stat in the queue, the earliest stat is not deleted.
 */
AdvParamSet *AdvConvergenceStat::referEarliestStat() {
    std::string memberName = std::string("referEarliestStat(AdvParamSet *)");
    DebugMessage(className, memberName, "enter\n");

    AdvParamSet *p=NULL;;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_rdlock( &(this->rwlock) );
#endif // lock
    while ( q.empty() ) {
        DebugMessage(className, memberName, "wait\n");
        pthread_cond_wait( &(this->guard), &(this->mutex) );
    }
    p=q.front();
    DebugMessage(className, memberName, "get\n");
    pthread_cond_signal( &(this->guard) );
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else
    if ( q.empty() ) {
        p=NULL;
    } else {
        p=q.front();
    }
#endif // USE_PTHREAD

    DebugMessage(className, memberName, "exit\n");
    return p;
}

/**
 *  refer the latest stat in the queue, the latest stat is not deleted.
 */
AdvParamSet *AdvConvergenceStat::referLatestStat() {
    std::string memberName = std::string("referLatestStat(AdvParamSet *)");
    DebugMessage(className, memberName, "enter\n");

    AdvParamSet *p=NULL;;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_rdlock( &(this->rwlock) );
#endif // lock
    while( q.empty() ) {
        DebugMessage(className, memberName, "wait\n");
        pthread_cond_wait( &(this->guard), &(this->mutex) );
    }
    //DebugMessage(className, memberName, "size of q: %u\n", q.size());
    p=q.back();
    DebugMessage(className, memberName, "get\n");
    pthread_cond_signal( &(this->guard) );
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else
    if ( q.empty() ) {
        p=NULL;
    } else {
        p=q.back();
    }
#endif // USE_PTHREAD

    DebugMessage(className, memberName, "exit\n");
    return p;
}


AdvParamSet *AdvConvergenceStat::at(UInt4 i) {
    std::string memberName = std::string("at(UInt4)");
    DebugMessage(className, memberName, "enter\n");

    AdvParamSet *p=NULL;
#ifdef USE_PTHREAD
#ifdef USE_MUTEX // lock
    pthread_mutex_lock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_rdlock( &(this->rwlock) );
#endif // lock
    while( q.empty() ) {
        DebugMessage(className, memberName, "wait\n");
        pthread_cond_wait( &(this->guard), &(this->mutex) );
    }
    //DebugMessage(className, memberName, "size of q: %u\n", q.size());
    if ( i < q.size() ) {
        p=q.at(i);
    }
    DebugMessage(className, memberName, "get\n");
    pthread_cond_signal( &(this->guard) );
#ifdef USE_MUTEX // unlock
    pthread_mutex_unlock( &(this->mutex) );
#elif defined USE_RWLOCK
    pthread_rwlock_unlock( &(this->rwlock) );
#endif // unlock
#else
    if ( q.empty() ) {
        p=NULL;
    } else {
        p=q.at(i);
    }
#endif
    DebugMessage(className, memberName, "exit\n");
    return p;
}
