/********************************************************************/
/* Copyright (c) 2017 System fugen G.K. and Yuzi Mizuno          */
/* All rights reserved.                                             */
/********************************************************************/
#ifndef _MGPlist_HH_
#define _MGPlist_HH_

// Plist.h
//

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <algorithm>
#include <list>
#include "mg/MGCL.h"

/** @file */
/** @addtogroup BASE
 *  @{
 */

///Defines List of newed object pointers.

///MGPlist is a list of std::auto_ptr<class T>. The member pointers of newed objects will
///be destructed when MGPlist object is destructed. That is, the ownerships of the members
//of MGPlist are transfered to MGPlist, and at the copy and assignment of MGPlist,
///all of the ownerships will be transfered to the copied or assigned new MGPlist.
template <class T>
class MGPlist{
public:
/// Alias.
/// 別名定義 
	typedef typename std::list<T*>::iterator               iterator;
	typedef typename std::list<T*>::const_iterator         const_iterator;
	typedef typename std::list<T*>::reverse_iterator       reverse_iterator;
	typedef typename std::list<T*>::const_reverse_iterator const_reverse_iterator;
	typedef typename std::list<T*>::reference              reference;
	typedef typename std::list<T*>::const_reference        const_reference;
	typedef typename std::list<T*>::size_type              size_type;

/// Member Data
	std::list<T*> m_list;

	///String stream function
	MG_DLL_DECLR friend std::ostream& operator<< (std::ostream& out, const MGPlist<T>& lst);

/// Constructors.

	/// The default constructor.
	MGPlist(){;}

	/// The copy constructor.
	/// The argument rhs will be cleared, since the ownership
	/// of all data of rhs should be transfered to this object.
	///所有権はすべて、新しいオブジェクトに移るので
	///rhsのすべての要素はNULLになります。(sizeは 0となります)
	MGPlist(const MGPlist<T>& rhs) : m_list(rhs.m_list){
		MGPlist<T>& rhsp = const_cast<MGPlist<T>&>(rhs);
		rhsp.m_list.clear();
	}

	/// Create a list whose size is n.
	explicit MGPlist(size_type n) : m_list(n, 0){;}

	/// Create a list with a range. The ownership will be transfered.
	template <class InputIter>
	MGPlist(InputIter first, InputIter last){
		insert(begin(), first, last);
	}

///Destructor
	/// Destroy the object and delete all pointers that this holds.
	~MGPlist();

/// operator overload

	/// assignment operator
	/// The argument rhs will be empty after assignment, 
	/// and transfer the ownership of all pointers to this object.
	/// 代入演算子
	///所有権はすべて、新しいオブジェクトに移るので
	///rhsは空になります)
	MGPlist<T>& operator=(const MGPlist<T>& rhs);

/// member functions

	/// Assignment that takes a range.
	/// The intersection of this object and [first, last) must be empty.
	template <class InputIter>
	void assign(InputIter first, InputIter last){
		iterator cur= begin(), finish = end();
		for(; first != last && cur != finish; ++first, ++cur){
			delete *cur; *cur = *first;
		}
		(first == last) ? erase(cur, finish) : insert(finish, first, last);
	}

	/// Return(but does not remove) last element in the list.
	/// If list is empty, behavior is undefined.
	const_reference back() const{
		return m_list.back();
	}
	reference back(){
		return m_list.back();
	}

	/// Return const_iterator at the beginning of list.
	const_iterator begin() const{
		return m_list.begin();
	}
	iterator begin(){
		return m_list.begin();
	}

	/// clear list, that is, erase all the elements in the list.
	void clear(){
		iterator first = begin(), last = end();
		for(; first != last; ++first)
			delete *first;
		m_list.clear();
	}

	///Return true if there are no items in the list,
	/// false otherwise.
	bool empty() const{
		return m_list.empty();
	}

	/// Return const_iterator at the end of list.
	const_iterator end() const{
		return m_list.end();
	}
	iterator end(){
		return m_list.end();
	}

	/// erase element x.
	iterator erase(iterator x){
		delete *x;
		return m_list.erase(x);
	}
	/// erase sequence [first, last).
	iterator erase(iterator first, iterator last){
		for(; first != last; ++first) delete *first;
		return m_list.erase(first, last);
	}

	///find the position of the object T* found first.
	///If not found, end() will be returned.
	const_iterator find(T* obj) const{
		return std::find(begin(),end(),obj);
	}
	iterator find(T* obj){
		return std::find(begin(),end(),obj);
	}

	/// Return(but does not remove) first element in the list.
	/// If list is empty, behavior is undefined.
	const_reference front() const{
		return m_list.front();
	}
	reference front(){
		return m_list.front();
	}

	///insert an element x before the position it.
	///Function's return value is the iterator of x after inserted.
	iterator insert(iterator it, T* x){
		return m_list.insert(it,x);
	}

	/// Insert given range denoted by [first, last) into one before pos.
	template <class InputIter>
	void insert(iterator pos, InputIter first, InputIter last){
		for(; first != last; ++first) insert(pos, *first);
	}

	///Returns the size of maximum size.
	size_type max_size() const{
		return m_list.max_size();
	}

	/// Equivalent to call std::list::merge().
	void merge(MGPlist<T>& rhs){
		m_list.merge(rhs.m_list);
	}

	/// pop last element.
	void pop_back(){
		delete m_list.back();
		m_list.pop_back();
	}

	/// pop first element.
	void pop_front(){
		delete m_list.front();
		m_list.pop_front();
	}

	/// push element x at the end.
	void push_back(T* x){
		m_list.push_back(x);
	}
	void push_back(MGPlist<T>& x){
		insert(end(), x.begin(), x.end());
		x.m_list.clear();
	}

	/// push element x at the first.
	void push_front(T* x){
		m_list.push_front(x);
	}

	/// Return const_reverse_iterator at the beginning of list.
	const_reverse_iterator rbegin() const{
		return m_list.rbegin();
	}
	reverse_iterator rbegin(){
		return m_list.rbegin();
	}

	/// Return const_reverse_iterator at the end of list.
	const_reverse_iterator rend() const{
		return m_list.rend();
	}
	reverse_iterator rend(){
		return m_list.rend();
	}

	///Release the pointer at th position i.
	///Returned will be the position after the released gel.
	iterator release(iterator i){
		return m_list.erase(i);
	}

	/// Release the ownership of elements that point the same as x.
	void remove(T* x){
		m_list.remove(x);
	}

	/// Release the ownership of elements that pred(x) is true, 
	/// where x is an element of the list.
	template <class Pred>
	void remove_if(Pred pred){
		iterator first = begin(), last = end();
		while(first != last){
			iterator next = first;
			++next;
			if(pred(*first)) m_list.erase(first);
			first = next;
		}
	}

	///Remove the T* at the iterator x and return the T*. If x is no valid, 
	/// behavior is undefined.
	///現在の所有権を放棄し、ただのポインタを返す。
	T* removeAt(iterator x){
		T* ret = *x;
		m_list.erase(x);
		return ret;
	}
	
	/// reverse sequence.
	void reverse(){	m_list.reverse();}

	/// Return the number of items that are in the list.
	size_type size() const{ return m_list.size();}

	/// Equivalent to call std::list::sort().
	void sort(){ m_list.sort();}
	
	template<class Traits> 
	void sort(Traits _Comp){m_list.sort(_Comp);}

	void splice(iterator pos, MGPlist<T>& ls){
		m_list.splice(pos, ls.m_list);
	}
	void splice(iterator pos, MGPlist<T>& ls, iterator i){
		m_list.splice(pos, ls.m_list, i);
	}
	void splice(iterator pos, MGPlist<T>& ls, iterator first, iterator last){
		m_list.splice(pos, ls.m_list, first, last);
	}

	/// Equivalent to call std::list::swap().
	void swap(MGPlist<T>& x){
		m_list.swap(x.m_list);
	}

	/// Equivalent to call std::list::unique().
	void unique(){ m_list.unique();}
};

///////////////Implementation////////////

template <class T>
MGPlist<T>::~MGPlist(){
	iterator first = begin(), last = end();
	for(; first != last; ++first) delete *first;
}

template <class T>
MGPlist<T>& MGPlist<T>::operator=(const MGPlist<T>& rhs){
	if(this != &rhs){
		clear();///もとのデータをクリア
		m_list = rhs.m_list;///代入する。
		MGPlist<T>& rhsp=const_cast<MGPlist<T>&>(rhs);
		rhsp.m_list.clear();///代入元をクリア
	}
	return *this;
}

template <class T>
std::ostream& operator<< (std::ostream& out, const MGPlist<T>& lst){
	out << "MGPlist<T>::";
	int n=lst.size();
	out<<"number of entries="<<n<<std::endl;
	MGPlist<T>::const_iterator itr; int i=0;
	for(itr=lst.begin(); itr!=lst.end(); itr++){
		out<<i++<<":"<<(*itr)<<std::endl;
		if(*itr) out << (**itr) << std::endl;
	}
	return out;
}

/** @} */ // end of BASE group
#endif