#ifndef H_CORAL_OCL
#define H_CORAL_OCL
// This file is part of the Coral project.
// Please read the copyright notice in the LICENSE file.

#include <coral/coral.h>
#include <coral/lib/ref_counted.h>
#include <coral/lib/unicodestring.h>

#include <coral/lib/hashed_ptr.h>
#include <coral/lib/swig.h>

#include <list>
#include <set>
#include <ext/hash_set>

#include <iostream>

#include <stdexcept>

namespace coral {
	namespace Transaction {
		class EXPORTFWD_coral Manager;
	}

     class EXPORTFWD_coral Iterator;
     class EXPORTFWD_coral ref_counted;
     class EXPORTFWD_coral Slot;
     class EXPORTFWD_coral Set;

     class EXPORT_coral Collection : public ref_counted, public noncopy {
     protected:
	  size_t n_elements;
	  CORAL_HIDDEN Collection();
     public:
	  virtual ~Collection() throw ();
	  virtual bool isOrdered() const throw () { return false; }
	  virtual bool isBag() const throw () { return false; }
	  /* OCL compat. */
	  size_t size() const throw () { return this->n_elements; }
	  size_t __len__() const throw () { return this->n_elements; }
	  bool isEmpty() const throw () { return this->n_elements == 0; }
	  bool __nonzero__() const throw () { return this->n_elements != 0; }
	  bool nonEmpty() const throw () { return this->n_elements != 0; }
	  virtual bool includes(const ref_counted*) const throw () CORAL_VIRTUAL;
	  bool __contains__(const ref_counted* e) const throw () {
		  return includes(e);
	  }
	  bool excludes(const ref_counted* e) const throw () { return (!this->includes(e)); }
	  virtual std::size_t count(const ref_counted*) const throw () CORAL_VIRTUAL;
	  virtual bool includesAll(const Collection*) const throw ();
	  virtual bool excludesAll(const Collection*) const throw ();
	  virtual void unionWith(const Collection*) throw (std::runtime_error, std::exception);
	  virtual void intersectWith(const Collection*) throw (std::runtime_error, std::exception);
	  virtual coral::autounref<coral::Set> setDifference(const Collection*) const throw (std::runtime_error, std::exception);
	  /* select is in kernel.py */
	  /* reject is in kernel.py */
	  Iterator* __iter__() const throw (std::bad_alloc);
	  /*
	   * Returns true if we actually did insert something.
	   * Needed for Sets.
	   */
	  virtual bool insert(const ref_counted*, int index = -1) CORAL_VIRTUAL;
	  virtual ref_counted* __getitem__(int index) const throw (std::out_of_range) CORAL_VIRTUAL;
	  virtual bool __setitem__(int index, const ref_counted*) CORAL_VIRTUAL;
	  virtual ref_counted* remove_keepref(int index) throw (std::out_of_range) CORAL_VIRTUAL ;
	  virtual int drop(const ref_counted*) throw () CORAL_VIRTUAL;

	  bool add(const ref_counted* e) { return this->insert(e, -1); }
	  bool append(const ref_counted* e) { return this->insert(e, -1); }
	  void drop_index(int index);

	  virtual void reset() throw () CORAL_VIRTUAL;
	  coral::unicodestring __str__() const;
	  coral::unicodestring __unicode__() const { return __str__(); }
	  coral::autounref<coral::Collection> newSimilarCollection() const;
	  virtual coral::autounref<coral::Collection> clone() const;

	  static coral::autounref<coral::Collection> newCollection(bool is_bag, bool is_ordered);
     };

     class EXPORT_coral Bag: public Collection {
     public:
	  typedef __gnu_cxx::hash_multiset<const coral::ref_counted*, coral::ptr_hash<const coral::ref_counted> > values_type;
     private:
#ifndef SWIG
	  friend class Iterator;
	  DELEGATE_FUNC(values_type::iterator, begin,, values);
	  DELEGATE_FUNC(values_type::iterator, end,, values);
	  DELEGATE_FUNC(values_type::const_iterator, begin, const, values);
	  DELEGATE_FUNC(values_type::const_iterator, end, const, values);
	  DELEGATE_TYPE(values_type, iterator, iterator);
	  DELEGATE_TYPE(values_type, const_iterator, const_iterator);
#endif
	  values_type values;
     public:
	  Bag();
	  virtual ~Bag() throw ();
#ifndef SWIG
	  bool isBag() const throw (){ return true; }
	  bool insert(const ref_counted*, int index = -1);
	  ref_counted* __getitem__(int index) const throw (std::out_of_range);
	  bool __setitem__(int index, const ref_counted*);
	  ref_counted* remove_keepref(int index) throw (std::out_of_range);
	  int drop(const ref_counted*) throw ();

	  std::size_t count(const ref_counted*) const throw ();
	  void reset() throw ();
	  bool includes(const ref_counted*) const throw ();
#endif
     };

     class EXPORT_coral OrderedSet: public Collection {
     public:
	  /* Note that this is not a vector! Makes pushing/poping
	     very fast, but indexing slow. This might be very stupid also. */
	  typedef std::list<const ref_counted*> values_type;
     private:
#ifndef SWIG
	  friend class Iterator;
	  friend class SlotManyref_countedsSequence;
	  DELEGATE_FUNC(values_type::iterator, begin,, values);
	  DELEGATE_FUNC(values_type::iterator, end,, values);
	  DELEGATE_FUNC(values_type::const_iterator, begin, const, values);
	  DELEGATE_FUNC(values_type::const_iterator, end, const, values);
	  DELEGATE_TYPE(values_type, iterator, iterator);
	  DELEGATE_TYPE(values_type, const_iterator, const_iterator);
#endif
	  values_type values;
     public:
	  OrderedSet();
	  virtual ~OrderedSet() throw ();

#ifndef SWIG
	  bool isOrdered() const throw () { return true; }
	  ref_counted* __getitem__(int index) const throw (std::out_of_range);

	  bool insert(const ref_counted*, int index = -1);
	  bool __setitem__(int index, const ref_counted*);
	  ref_counted* remove_keepref(int index) throw (std::out_of_range);
	  int drop(const ref_counted*) throw ();

	  std::size_t count(const ref_counted*) const throw ();
	  void reset() throw ();
	  bool includes(const ref_counted*) const throw ();
#endif
     };

     class EXPORT_coral Sequence: public Collection {
     public:
	  /* Note that this is not a vector. */
	  typedef std::list<const ref_counted*> values_type;
     private:
#ifndef SWIG
	  friend class Iterator;
	  friend class SlotManyref_countedsSequence;
	  DELEGATE_FUNC(values_type::iterator, begin,, values);
	  DELEGATE_FUNC(values_type::iterator, end,, values);
	  DELEGATE_FUNC(values_type::const_iterator, begin, const, values);
	  DELEGATE_FUNC(values_type::const_iterator, end, const, values);
	  DELEGATE_TYPE(values_type, iterator, iterator);
	  DELEGATE_TYPE(values_type, const_iterator, const_iterator);
#endif
	  values_type values;
     public:
	  Sequence();
	  virtual ~Sequence() throw ();

#ifndef SWIG
	  bool isOrdered() const throw () { return true; }
	  bool isBag() const throw () { return true; }
	  ref_counted* __getitem__(int index) const throw (std::out_of_range);

	  bool insert(const ref_counted*, int index = -1);
	  bool __setitem__(int index, const ref_counted*);
	  ref_counted* remove_keepref(int index) throw (std::out_of_range);
	  int drop(const ref_counted*) throw ();

	  std::size_t count(const ref_counted*) const throw ();
	  void reset() throw ();
	  bool includes(const ref_counted*) const throw ();
#endif
     };


     class EXPORT_coral Set: public Collection {
     public:
	  typedef __gnu_cxx::hash_set<const coral::ref_counted*, coral::ptr_hash<coral::ref_counted> > values_type;
     private:
#ifndef SWIG
	  friend class Iterator;
	  friend class SlotManyref_countedsSet;
	  friend class Transaction::Manager;
	  DELEGATE_FUNC(values_type::iterator, begin,, values);
	  DELEGATE_FUNC(values_type::iterator, end,, values);
	  DELEGATE_FUNC(values_type::const_iterator, begin, const, values);
	  DELEGATE_FUNC(values_type::const_iterator, end, const, values);
	  DELEGATE_TYPE(values_type, iterator, iterator);
	  DELEGATE_TYPE(values_type, const_iterator, const_iterator);
#endif
	  values_type values;
     public:
	  Set();
	  virtual ~Set() throw ();
#ifndef SWIG
	  int drop(const ref_counted*) throw ();
	  /* HACK! */
	  ref_counted* __getitem__(int index) const throw (std::out_of_range);

	  bool includes(const ref_counted*) const throw ();
	  void reset() throw ();
	  bool insert(const ref_counted*, int index = -1);
	  bool __setitem__(int index, const ref_counted*);
	  ref_counted* remove_keepref(int index) throw (std::out_of_range);
	  std::size_t count(const ref_counted*) const throw ();
#endif
     };




     class EXPORT_coral Iterator : public ref_counted, public noncopy {
     private:
	  enum iter_type { ITER_MMSET,
			   ITER_MMBAG,
			   ITER_MMORDSET,
			   ITER_MMSEQ,
			   ITER_ONE_ELEMENT };
	  const Collection* collection;
	  enum iter_type iter_type;
	  Set::const_iterator seti;
	  Bag::const_iterator bagi;
	  OrderedSet::const_iterator oseti;
	  Sequence::const_iterator seqi;
	  const ref_counted* element;
	  CORAL_HIDDEN void __collection(const Collection* c);
     public:
	  explicit Iterator(const Collection* c);
#ifndef SWIG
	  explicit Iterator(const Collection& c);
	  explicit Iterator(const Slot& s);
#endif
	  explicit Iterator(const Slot* c);
	  ~Iterator() throw ();
	  ref_counted* next() throw ();
	  Iterator* __iter__() throw () { return this; }
     };


}


#endif
