// -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; -*-
////////////////////////////////////////////////////////////////////
//
// $Id: open_list.h 815 2011-09-10 12:57:27Z Sebastian Kupferschmid $
//
////////////////////////////////////////////////////////////////////

#ifndef SEARCH_OPEN_LIST_H
#define SEARCH_OPEN_LIST_H

#include <inttypes.h>
#include <iosfwd>
#include <queue>
#include <stack>
#include <vector>

class State;

class OpenList {
protected:
    uint32_t popped_states;
    uint32_t pushed_states;
    uint32_t current_states;

    OpenList() : popped_states(0), pushed_states(0), current_states(0) {}
    virtual ~OpenList() {}
public:
    virtual OpenList* clone() const = 0; 
    virtual void insert(State* state, int32_t, int32_t) = 0;
    virtual State* get() = 0;
    virtual bool empty() const { return current_states == 0; }
    virtual uint32_t size() const { return current_states; }
    virtual std::ostream& printstat(std::ostream& o) const;
};

////////////////////////////////////////////////////////////////////

class StackList : public OpenList {
private:
    std::stack<State*> states;
public:
    StackList();
    virtual OpenList* clone() const { return new StackList(); }
    virtual void insert(State* state, int32_t, int32_t);
    virtual State* get();
};

////////////////////////////////////////////////////////////////////

class QueueList : public OpenList {
private:
    std::queue<State*> states;
public:    
    QueueList();
    virtual OpenList* clone() const { return new QueueList(); }
    virtual void insert(State* state, int32_t, int32_t);
    virtual State* get();
};

////////////////////////////////////////////////////////////////////

class PriorityQueue : public OpenList {
private:
    typedef std::deque<State*> bucket_t;
    std::vector<bucket_t> buckets;
    mutable int32_t lowest_bucket;
public:
    PriorityQueue();

    virtual OpenList* clone() const { return new PriorityQueue(); }
    virtual void insert(State* state, int32_t, int32_t key);
    virtual State* get();
};

//////////////////////////////////////////////////////////////////

class MultiQueue : public OpenList {
private:
    const OpenList* prototype;
    std::vector<OpenList*> queues;
public:
    MultiQueue(const OpenList* prototype);
    
    virtual OpenList* clone() const { return new MultiQueue(prototype); }
    virtual void insert(State* state, int32_t key1, int32_t key2);
    virtual State* get();
    virtual std::ostream& printstat(std::ostream& o) const;
};

////////////////////////////////////////////////////////////////////

class UTQueue : public OpenList {
private:
    PriorityQueue* useless;
    PriorityQueue* normal;
public:
    UTQueue() : useless(new PriorityQueue), normal(new PriorityQueue) {}
    virtual OpenList* clone() const { return new UTQueue(); }
    virtual void insert(State* state, int32_t key1, int32_t key2);
    virtual State* get();    
    virtual std::ostream& printstat(std::ostream& o) const;
};

////////////////////////////////////////////////////////////////////

class UTIPQueue : public OpenList {
private:
    PriorityQueue* useless;
    PriorityQueue* normal;
    MultiQueue* ip;
public:
    UTIPQueue() : useless(new PriorityQueue), normal(new PriorityQueue), ip(new MultiQueue(new PriorityQueue)) {}

    virtual OpenList* clone() const { return new UTIPQueue(); }
    virtual void insert(State* state, int32_t key1, int32_t key2);
    virtual State* get();    
    virtual std::ostream& printstat(std::ostream& o) const;
};
    
inline std::ostream& operator<<(std::ostream& o, const OpenList& open) {
    return open.printstat(o);
}

#endif /* SEARCH_OPEN_LIST_H */
