#ifndef __PLIST__H__
#define __PLIST__H__

#include <list>
#include <vector>

#include "PElement.h"
#include "PIterator.h"

///@brief classe qui permet de gérer des liste de Types abstrait
/**	J'entend d'ici les gens me dire, tu as encore réinventé la roue. Alors pour ma défence (même si je ne suis pas un éléphant)
 * 	je tiens à dire que je n'ai pas réécris les std::list pour le plaisir, mais pour me faire la main, pour pouvoir faire des
 * 	listes plus complètes que std::list (déjà), et surtout pour pouvoir créer dans une prochaine étape des liste (enfin je ne
 *	sais pas encore le nom que je leur donnerai), pour gérer des listes avec des indices négatifs.
 * 	Ce qui n'a rien a voir avec les std::list on est bien d'accord.
*/

template <class T>
class PList{
	public:
		PList();
		PList(const T & el);
		PList(const PList<T> & liste);
		virtual ~PList();
		
		PList & operator = (const PList<T> & liste);
		PList & operator += (const T & el);
		PList & operator += (const PList<T> & liste);
		
		void normalise(const T & scal);
		
		T front() const;
		T back() const;
		T getAt(size_t index) const;
		void setAt(const T & value, size_t index);
		T operator [] (size_t index) const;
		T & operator [] (size_t index);
		
		PIterator<T> begin() const;
		PIterator<T> end() const;
		PIterator<T> rbegin() const;
		PIterator<T> rend() const;
		
		
		bool pushBack(const T & el);
		bool pushBack(const PList<T> & liste);
		bool pushFront(const T & el);
		bool pushFront(const PList<T> & liste);
		
		bool popBack();
		bool popFront();
		void clear();
		
		bool erase(PIterator<T> & it);
		bool erase(int index);
		
		size_t size() const;
		
		std::list<T> toStdList() const;
		std::vector<T> toStdVector() const;
		
		///définition de l'opérateur << pour ajouter une valeur à une autre liste
		/**	@param liste : liste dont on va ajouter les élements de list
		 * 	@param el : élément à ajouter
		 * 	@return liste modifiée
		*/
		friend PList & operator << (PList<T> & liste, const T & el){
			liste.pushBack(el);
			return liste;
		}
		///définition de l'opérateur << pour ajouter une liste à une autre liste
		/**	@param liste : liste dont on va ajouter les élements de list
		 * 	@param list : liste d'éléments à ajouter
		 * 	@return liste modifiée
		*/
		friend PList & operator << (PList<T> & liste, const PList<T> & list){
			liste.pushBack(list);
			return liste;
		}
		
		///définition de l'opérateur de flux << pour une PList
		/**	@param out : ostream dans lequel on va écrire la liste
		 * 	@param list : PList que l'on veut écrire dans la console
		 * 	@return ostream dans lequel on a écrit
		*/
		friend std::ostream & operator << (std::ostream & out, const PList<T> & list){
			if(list.p_size == 0) return out;
			for(PIterator<T> it(list.begin()); it != list.end(); ++it){
				out << *it << ", ";
			}
			return out;
		}
		
	private:
		void intialisationPList();
		void copyPList(const PList<T> & liste);
		///PElement qui permet d'accéder au autres
		PElement<T> p_handle;
		///nombre d'élements de la PList
		size_t p_size;
		
};



#include "PList_impl.h"

#endif
