#ifndef _HASHSTRUCT_H_
#define _HASHSTRUCT_H_

#include "simplex.h"
#include <map>
#include <queue>
#include <iterator>


class hashFaceKey
{
private :
    int _key;
    int min;
    int max;
    Tetra *_t;
    int _f;
    int _id;
//     void *_obj;

public :
    hashFaceKey(Tetra *t, int face);
//     inline size_t memory()
//     {
//       return sizeof(*this);
//     }
    inline int face()
    {
        return _f;
    }
    inline Tetra * tetra()
    {
        return _t;
    }
    inline int key()
    {
        return _key;
    }
    inline int equal(hashFaceKey *k)
    {
        return (k->min == this->min) && (k->max == this->max);
    }
    inline void setIndex(int i)
    {
        _id = i;
    }
    inline int index()
    {
        return _id;
    }
//     inline void set_obj(void *obj)
//     {
//         _obj = obj;
//     }
//     inline void *get_obj()
//     {
//         return _obj;
//     }
};


class hashFaceStruct
{
private :
    std::multimap<int, hashFaceKey*> table;

public :
    hashFaceKey *addFace(Tetra *t, int face);
//     inline size_t memory()
//     {
//       return sizeof(*this) + table.size()*(sizeof(int) + sizeof(hashFaceKey*));
//     }
    int size()
    {
      return table.size();
    }
    void clear();
};

class hashEdgeKey
{
private :
    int _key;
    int min;
    Vertex *_v[2];
    Tetra *_t;
    int _id;
    Vertex *_m;

public :
    hashEdgeKey(Tetra *t, int edge, Vertex *m);
//     inline size_t memory()
//     {
//       return sizeof(*this);
//     }
    inline Tetra * tetra()
    {
        return _t;
    }
    inline Vertex * vertex(int i)
    {
        assert(i>=0 && i<2);
        return _v[i];
    }
    inline void setTetra(Tetra *t)
    {
        _t = t;
    }
    inline int key()
    {
        return _key;
    }
    inline int equal(hashEdgeKey *k)
    {
        return (k->min == this->min);    // si la key est identique !!
    }
    inline void setIndex(int i)
    {
        _id = i;
    }
    inline int index()
    {
        return _id;
    }
    inline Vertex * middle()
    {
        return _m;
    }
};

class hashEdgeStruct
{
private :
    std::multimap<int, hashEdgeKey*> _table;
    std::multimap<int, hashEdgeKey*>::iterator _it;
    std::vector<std::queue<hashEdgeKey*> > _stack;
    int _ss;
    int _cstack;
    int _lock_it;

public :
    hashEdgeStruct()
    {
      _cstack = 0;
      _ss = 0;
      _lock_it = 0;
      _stack.resize(1);
    }

//     inline size_t memory()
//     {
//       return sizeof(*this) + _table.size()*(sizeof(int) + sizeof(hashEdgeKey*)) + sizeof(_it) + _stack.size()*sizeof(hashEdgeKey*);
//     }
    void dump();
    hashEdgeKey *stack_front();
    void stack_pop();
    hashEdgeKey *query(hashEdgeKey *k1);
    hashEdgeKey *addEdge(Tetra *t, int edge, Vertex *m);
//     void updateEdges(Tetra *t_old, int edge_old, Tetra *t1, Tetra *t2);
    void updateEdge(Tetra *t_old, int edge_old, Tetra *t_new/*, int edge_new*/);
    void deleteCurrent();
    void nextEdge();
    void getEdge(Tetra **t, int *edge);
    inline Vertex *getVertex(int i);
    inline void set_stack_number(int i)
    {
      _stack.resize(i);
      _cstack = 0;
      _ss = 0;
      _lock_it = 0;
    }
    inline int get_stack_number()
    {
        return _stack.size();
    }
    inline int size()
    {
        int ss = 0;
        for (int i = 0; i < _stack.size(); i++)
            ss += _stack[i].size();
        assert(_ss == ss);
        return _ss;
    }
    inline int get_current_surf()
    {
        return _cstack;
    }

    void check_internal();
    inline void lock_query() {_lock_it = 1;}
    inline void unlock_query() {_lock_it = 0;}
    inline int query_locked() {return _lock_it;}
    void clear();
};

#endif