#include <../../nrnconf.h>
#include <InterViews/resource.h>
#include "tqueue.h"
#include "pool.h"

#include "classreg.h"
#include "nrnoc2iv.h"

#define PROFILE 0
#include "profile.h"

#define DOCHECK 0

#if COLLECT_TQueue_STATISTICS
#define STAT(arg) ++arg;
#else
#define STAT(arg) /**/
#endif

static const char* errmess_;

static double insert(void* v) {
    TQueue* q = (TQueue*) v;
    q->insert(*getarg(1), (void*) 1);
    return 1.;
}
static double print(void* v) {
    TQueue* q = (TQueue*) v;
    q->print();
    return 1.;
}

static double least(void* v) {
    TQueue* q = (TQueue*) v;
    TQItem* i = q->least();
    double x = -1e9;
    if (i) {
        x = i->t_;
    }
    return x;
}
static double rmleast(void* v) {
    TQueue* q = (TQueue*) v;
    TQItem* i = q->least();
    double x = -1e9;
    if (i) {
        x = i->t_;
        q->remove(i);
    }
    return x;
}

static double mvleast(void* v) {
    TQueue* q = (TQueue*) v;
    q->move_least(*getarg(1));
    return 1.;
}

static double remove(void* v) {
    TQueue* q = (TQueue*) v;
    q->remove(q->find(*getarg(1)));
    return 1.;
}

static double find(void* v) {
    TQueue* q = (TQueue*) v;
    TQItem* i = q->find(*getarg(1));
    double x = -1e9;
    if (i) {
        x = i->t_;
        q->remove(i);
    }
    return x;
}
static double stats(void* v) {
    TQueue* q = (TQueue*) v;
    q->statistics();
    return 1.;
}

static Member_func members[] = {"insrt",
                                insert,
                                "least",
                                least,
                                "move_least",
                                mvleast,
                                "remove_least",
                                rmleast,
                                "remove",
                                remove,
                                "find",
                                find,
                                "stats",
                                stats,
                                "printf",
                                print,
                                0,
                                0};

static void* cons(Object*) {
    assert(0);
    TQueue* q = new TQueue(0);
    return (void*) q;
}

static void destruct(void* v) {
    TQueue* q = (TQueue*) v;
    delete q;
}

void TQueue_reg() {
    class2oc("TQueue", cons, destruct, members, NULL, NULL, NULL);
}

//----------------

implementPool(TQItemPool, TQItem)
#if BBTQ == 0
#include <bbtqueue.cpp>
#endif

#if BBTQ == 1
#include <rbtqueue.cpp>
#endif

#if BBTQ == 2
#include <sptqueue.cpp>
#endif

#if BBTQ == 3
#include <sptfifoq.cpp>
#endif

#if BBTQ == 4
#include <spt2queue.cpp>
#endif

#if BBTQ == 5
#include <sptbinq.cpp>
#endif

    SelfQueue::SelfQueue(TQItemPool* tp, int mkmut) {
    MUTCONSTRUCT(mkmut)
    tpool_ = tp;
    head_ = nil;
}
SelfQueue::~SelfQueue() {
    remove_all();
    MUTDESTRUCT
}
TQItem* SelfQueue::insert(void* d) {
    MUTLOCK
    TQItem* q = tpool_->alloc();
    q->left_ = nil;
    q->right_ = head_;
    if (head_) {
        head_->left_ = q;
    }
    head_ = q;
    q->data_ = d;
    MUTUNLOCK
    return q;
}
void* SelfQueue::remove(TQItem* q) {
    MUTLOCK
    if (q->left_) {
        q->left_->right_ = q->right_;
    }
    if (q->right_) {
        q->right_->left_ = q->left_;
    }
    if (q == head_) {
        head_ = q->right_;
    }
    tpool_->hpfree(q);
    MUTUNLOCK
    return q->data_;
}
void SelfQueue::remove_all() {
    MUTLOCK
    for (TQItem* q = first(); q; q = next(q)) {
        tpool_->hpfree(q);
    }
    head_ = nil;
    MUTUNLOCK
}
