// queue stl/clr header
// Copyright (c) Microsoft Corporation. All rights reserved.
#ifndef _CLI_QUEUE_
 #define _CLI_QUEUE_
#include <cliext/algorithm>	// for push/pop heap
#include <cliext/deque>	// for default queue container
#include <cliext/functional>	// for BinaryDelegate
#include <cliext/iterator>
#include <cliext/vector>	// for default priority_queue container

namespace cliext {
	namespace impl {
//
// TEMPLATE CLASS queue_base
//
template<typename _Value_t,
	typename _Cont_t>
	ref class queue_base
	:	public _STLCLR IQueue<_Value_t,
		typename _Container_traits<_Cont_t>::generic_container_handle>
	{	// FIFO queue of elements
public:
	// types
	typedef queue_base<_Value_t, _Cont_t> _Mytype_t;
	typedef _STLCLR IQueue<_Value_t,
		typename _Container_traits<_Cont_t>::generic_container_handle>
		_Mycont_it;
	typedef cli::array<_Value_t> _Myarray_t;

	typedef int size_type;
	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

	typedef _Mycont_it generic_container;
	typedef value_type generic_value;

	typedef typename _Dehandle<_Cont_t>::type container_type;

	// basics
	queue_base()
		:	c(gcnew container_type)
		{	// default constructor
		}

	queue_base% operator=(queue_base% _Right)
		{	// assign
		assign(_Right);
		return (*this);
		}

	operator _Mycont_it^()
		{	// convert to interface
		return (this);
		}

	// constructors
	explicit queue_base(container_type% _Cont)
		:	c(gcnew container_type(_Cont))
		{	// construct from container
		}

	// destructor
	~queue_base()
		{	// destroy the object
		delete c;
		}

	// accessors
	property value_type front_item
		{	// get or set front element
		value_type get()
			{	// get first element
			return (front());
			}

		void set(value_type _Val)
			{	// set first element
			front() = _Val;
			}
		};

	property value_type back_item
		{	// get or set back element
		value_type get()
			{	// get last element
			return (back());
			}

		void set(value_type _Val)
			{	// set last element
			back() = _Val;
			}
		};

	virtual reference front()
		{	// get oldest element
		return (((typename container_type::generic_container^)c)->front());
		}

	virtual reference back()
		{	// get newest element
		return (((typename container_type::generic_container^)c)->back());
		}

	virtual container_type^ get_container()
		{	// return container
		return (c);
		}

	// converters
	virtual System::Object^ Clone()
		{	// clone the queue
		return (gcnew queue_base(*c));
		}

	_Myarray_t^ to_array()
		{	// convert to array
		return (c->to_array());
		}

	// size controllers
	virtual size_type size()
		{	// return length of sequence
		return (c->size());
		}

	virtual bool empty()
		{	// test if sequence is empty
		return (size() == 0);
		}

	// mutators
	virtual void push(value_type _Val)
		{	// insert element at back end
		c->push_back(_Val);
		}

	virtual void pop()
		{	// erase element at front end
		c->pop_front();
		}

	virtual void assign(_Mytype_t% _Right)
		{	// assign
		*c = *_Right.get_container();
		}

_STLCLR_FIELD_ACCESS:
	// data members
	container_type^ c;	// the underlying container

private:
	virtual reference front_virtual() sealed
		= _Mycont_it::front
		{	// get oldest element
		return (front());
		}

	virtual reference back_virtual() sealed
		= _Mycont_it::back
		{	// get newest element
		return (back());
		}

	virtual typename _Container_traits<_Cont_t>::generic_container_handle
		get_container_virtual() sealed
		= _Mycont_it::get_container
		{	// return container
		return (get_container());
		}

	// size controllers
	virtual size_type size_virtual() sealed
		= _Mycont_it::size
		{	// return length of sequence
		return (size());
		}

	virtual bool empty_virtual() sealed
		= _Mycont_it::empty
		{	// test if sequence is empty
		return (empty());
		}

	// mutators
	virtual void push_virtual(value_type _Val) sealed
		= _Mycont_it::push
		{	// insert element at end
		push(_Val);
		}

	virtual void pop_virtual() sealed
		= _Mycont_it::pop
		{	// erase element at end
		pop();
		}

	virtual void assign_virtual(_Mycont_it^ _Right) sealed
		= _Mycont_it::assign
		{	// assign
		assign(*(_Mytype_t^)_Right);
		}
	};

//
// TEMPLATE CLASS queue_select
//
template<typename _Value_t,
	typename _Cont_t,
	bool _Is_ref>
	ref class queue_select
	:	public queue_base<_Value_t, _Cont_t^>
	{	// FIFO queue of elements
public:
	// types
	typedef queue_select<_Value_t, _Cont_t, _Is_ref> _Mytype_t;
	typedef queue_base<_Value_t, _Cont_t^> _Mybase_t;
//	typedef _STLCLR IQueue<_Value_t, _Cont_t> _Mycont_it;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;

	// basics
	queue_select()
		{	// construct with empty container
		}

	queue_select% operator=(queue_select% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	// constructors
	explicit queue_select(container_type% _Cont)
		:	_Mybase_t(_Cont)
		{	// construct with specified container
		}
	};

//
// TEMPLATE CLASS queue_select: _Value_t REF SPECIALIZATION
//
template<typename _Value_t,
	typename _Cont_t>
	ref class queue_select<_Value_t, _Cont_t, true>
	:	public queue_base<_Value_t^, _Cont_t^>
	{	// FIFO queue of elements
public:
	// types
	typedef queue_select<_Value_t, _Cont_t, true> _Mytype_t;
	typedef queue_base<_Value_t^, _Cont_t^> _Mybase_t;
//	typedef _STLCLR IQueue<_Value_t, _Cont_t> _Mycont_it;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;

	// basics
	queue_select()
		{	// construct with empty container
		}

	queue_select% operator=(queue_select% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	// constructors
	explicit queue_select(container_type% _Cont)
		:	_Mybase_t(_Cont)
		{	// construct with specified container
		}

	// accessors
	property value_type front_item
		{	// get or set front element
		value_type get()
			{	// get last element
			return (front());
			}

		void set(value_type _Val)
			{	// set last element
			front() = _Val;
			}
		};

	property value_type back_item
		{	// get or set back element
		value_type get()
			{	// get last element
			return (back());
			}

		void set(value_type _Val)
			{	// set last element
			back() = _Val;
			}
		};

	virtual reference front() new
		{	// get top element
		return (c->front());
		}

	virtual reference back() new
		{	// get top element
		return (c->back());
		}

	// mutators
	void push(value_type _Val)
		{	// insert element at end
		c->push_back(_Val);
		}
	};
	}	// namespace cliext::impl

//
// TEMPLATE CLASS queue
//
template<typename _Value_t,
	typename _Cont_t = cliext::deque<_Value_t>^>
	ref class queue
	:	public impl::queue_select<
			_Value_t,
			typename _Dehandle<_Cont_t>::type,
			__is_ref_class(typename _Dehandle<_Value_t>::type)
				&& !is_handle<_Value_t>::value>
	{	// FIFO queue of elements
public:
	// types
	typedef queue<_Value_t, _Cont_t> _Mytype_t;
	typedef impl::queue_select<
		_Value_t,
		typename _Dehandle<_Cont_t>::type,
		__is_ref_class(typename _Dehandle<_Value_t>::type)
			&& !is_handle<_Value_t>::value> _Mybase_t;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
//	typedef _Value_t value_type;
//	typedef value_type% reference;
//	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;

	// basics
	queue()
		{	// construct with empty container
		}

	queue(queue% _Right)
		:	_Mybase_t(*_Right.get_container())
		{	// construct by copying a queue
		}

	queue(queue^ _Right)
		:	_Mybase_t(*_Right->get_container())
		{	// construct by copying a queue
		}

	queue% operator=(queue% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	queue% operator=(queue^ _Right)
		{	// assign
		_Mybase_t::operator=(*_Right);
		return (*this);
		}

	// constructors
	explicit queue(container_type% _Cont)
		:	_Mybase_t(_Cont)
		{	// construct with specified container
		}

	// interfaces
	virtual System::Object^ Clone() override
		{	// clone the vector
		return (gcnew _Mytype_t(*this));
		}
	};

//
// TEMPLATE COMPARISONS
//
template<typename _Value_t,
	typename _Cont_t> inline
	bool operator==(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left == _Right
	return (*_Left.get_container() == *_Right.get_container());
	}

template<typename _Value_t,
	typename _Cont_t> inline
	bool operator!=(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left != _Right
	return (!(_Left == _Right));
	}

template<typename _Value_t,
	typename _Cont_t> inline
	bool operator<(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left < _Right
	return (*_Left.get_container() < *_Right.get_container());
	}

template<typename _Value_t,
	typename _Cont_t> inline
	bool operator>=(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left >= _Right
	return (!(_Left < _Right));
	}

template<typename _Value_t,
	typename _Cont_t> inline
	bool operator>(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left > _Right
	return (_Right < _Left);
	}

template<typename _Value_t,
	typename _Cont_t> inline
	bool operator<=(queue<_Value_t, _Cont_t>% _Left,
		queue<_Value_t, _Cont_t>% _Right)
	{	// test if _Left <= _Right
	return (!(_Right < _Left));
	}

//
// TEMPLATE FUNCTION _Queue_compare
//
template<typename _Key_t> inline
	bool _Queue_compare(_Key_t _Left, _Key_t _Right)
	{	// test if _Left < _Right
	return (_Left < _Right);
	}

inline bool _Queue_compare(System::String^ _Left, System::String^ _Right)
	{	// test if _Left < _Right for String
	return (_Left->CompareTo(_Right) < 0);
	}

	namespace impl {
//
// TEMPLATE CLASS priority_queue_base
//
template<typename _Value_t,
	typename _Cont_t>
	ref class priority_queue_base
	:	public _STLCLR IPriorityQueue<_Value_t,
		typename _Container_traits<_Cont_t>::generic_container_handle>
	{	// priority queue of elements
public:
	// types
	typedef priority_queue_base<_Value_t, _Cont_t> _Mytype_t;
	typedef _STLCLR IPriorityQueue<_Value_t,
		typename _Container_traits<_Cont_t>::generic_container_handle>
		_Mycont_it;
	typedef cli::array<_Value_t> _Myarray_t;

	typedef int size_type;
	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

	typedef _Mycont_it generic_container;
	typedef value_type generic_value;

	typedef typename _Dehandle<_Cont_t>::type container_type;
	typedef _STLCLR BinaryDelegate<_Value_t, _Value_t, bool>
		value_compare;

	// basics
	priority_queue_base()
		:	comp(gcnew value_compare(&_Queue_compare)),
				c(gcnew container_type)
		{	// default constructor
		}

	priority_queue_base% operator=(priority_queue_base% _Right)
		{	// assign
		assign(_Right);
		return (*this);
		}

	operator _Mycont_it^()
		{	// convert to interface
		return (this);
		}

	// constructors
	explicit priority_queue_base(value_compare^ _Pred)
		:	comp(_Pred),
				c(gcnew container_type)
		{	// construct with empty container, specified predicate
		}

	priority_queue_base(value_compare^ _Pred, container_type% _Cont)
		:	comp(_Pred),
				c(gcnew container_type(_Cont))
		{	// construct with specified predicate and container
		}

	// destructor
	~priority_queue_base()
		{	// destroy the object
		delete c;
		}

	// accessors
	property value_type top_item
		{	// get or set top element
		virtual value_type get()
			{	// get highest priority element
			return (top());
			}

		virtual void set(value_type _Val)
			{	// set highest priority element ???
			top() = _Val;
			}
		};

	reference top()
		{	// get highest priority element
		return (((typename container_type::generic_container^)c)->front());
		}

	container_type^ get_container()
		{	// return container
		return (c);
		}

	value_compare^ value_comp()
		{	// return object for comparing values
		return (comp);
		}

	// converters
	virtual System::Object^ Clone()
		{	// clone the priority_queue
		return (gcnew priority_queue_base(comp, *c));
		}

	_Myarray_t^ to_array()
		{	// convert to array
		return (c->to_array());
		}

	// size controllers
	size_type size()
		{	// return length of sequence
		return (c->size());
		}

	bool empty()
		{	// test if sequence is empty
		return (size() == 0);
		}

	// mutators
	void push(value_type _Val)
		{	// insert element at back end
		c->push_back(_Val);
		cliext::push_heap(c->begin(), c->end(), comp);
		}

	void pop()
		{	// erase element at front end
		cliext::pop_heap(c->begin(), c->end(), comp);
		c->pop_back();
		}

	void assign(_Mytype_t% _Right)
		{	// assign
		*c = *_Right.get_container();
		}

_STLCLR_FIELD_ACCESS:
	// data members
	value_compare^ comp;	// the comparator predicate for values, < or >
	container_type^ c;	// the underlying container

private:
	virtual reference top_virtual() sealed
		= _Mycont_it::top
		{	// get top element
		return (top());
		}

	virtual typename _Container_traits<_Cont_t>::generic_container_handle
		get_container_virtual() sealed
		= _Mycont_it::get_container
		{	// return container
		return (get_container());
		}

	virtual value_compare^ value_comp_virtual() sealed
		= _Mycont_it::value_comp
		{	// return object for comparing values
		return (value_comp());
		}

	// size controllers
	virtual size_type size_virtual() sealed
		= _Mycont_it::size
		{	// return length of sequence
		return (size());
		}

	virtual bool empty_virtual() sealed
		= _Mycont_it::empty
		{	// test if sequence is empty
		return (empty());
		}

	// mutators
	virtual void push_virtual(value_type _Val) sealed
		= _Mycont_it::push
		{	// insert element at end
		push(_Val);
		}

	virtual void pop_virtual() sealed
		= _Mycont_it::pop
		{	// erase element at end
		pop();
		}

	virtual void assign_virtual(_Mycont_it^ _Right) sealed
		= _Mycont_it::assign
		{	// assign
		assign(*(_Mytype_t^)_Right);
		}
	};

//
// TEMPLATE CLASS priority_queue_select
//
template<typename _Value_t,
	typename _Cont_t,
	bool _Is_ref>
	ref class priority_queue_select
	:	public priority_queue_base<_Value_t, _Cont_t^>
	{	// priority queue of elements
public:
	// types
	typedef priority_queue_select<_Value_t, _Cont_t, _Is_ref> _Mytype_t;
	typedef priority_queue_base<_Value_t, _Cont_t^> _Mybase_t;
//	typedef _STLCLR IPriorityQueue<_Value_t, _Cont_t> _Mycont_it;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;
//	typedef _STLCLR BinaryDelegate<_Value_t, _Value_t, bool>
//		value_compare;

	// basics
	priority_queue_select()
		{	// construct with empty container
		}

	priority_queue_select% operator=(priority_queue_select% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	// constructors
	priority_queue_select(value_compare^ _Pred)
		:	_Mybase_t(_Pred)
		{	// construct with specified predicate
		}

	priority_queue_select(value_compare^ _Pred, container_type% _Cont)
		:	_Mybase_t(_Pred, _Cont)
		{	// construct with specified predicate and container
		}
	};

//
// TEMPLATE CLASS priority_queue_select: _Value_t REF SPECIALIZATION
//
template<typename _Value_t,
	typename _Cont_t>
	ref class priority_queue_select<_Value_t, _Cont_t, true>
	:	public priority_queue_base<_Value_t^, _Cont_t^>
	{	// priority queue of elements
public:
	// types
	typedef priority_queue_select<_Value_t, _Cont_t, true> _Mytype_t;
	typedef priority_queue_base<_Value_t^, _Cont_t^> _Mybase_t;
//	typedef _STLCLR IPriorityQueue<_Value_t, _Cont_t> _Mycont_it;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
	typedef _Value_t value_type;
	typedef value_type% reference;
	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;
//	typedef _STLCLR BinaryDelegate<_Value_t, _Value_t, bool>
//		value_compare;

	// basics
	priority_queue_select()
		{	// construct with empty container
		}

	priority_queue_select% operator=(priority_queue_select% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	// constructors
	priority_queue_select(value_compare^ _Pred)
		:	_Mybase_t(_Pred)
		{	// construct with specified predicate
		}

	priority_queue_select(value_compare^ _Pred, container_type% _Cont)
		:	_Mybase_t(_Pred, _Cont)
		{	// construct with specified predicate and container
		}

	// accessors
	property value_type top_item
		{	// get or set top element
		value_type get()
			{	// get last element
			return (top());
			}

		void set(value_type _Val)
			{	// set last element
			top() = _Val;
			}
		};

	virtual reference top() new
		{	// get top element
		return (c->front());
		}

	// mutators
	void push(value_type _Val)
		{	// insert element at end
		c->push_back(_Val);
		cliext::push_heap(c->begin(), c->end(), comp);
		}
	};
	}	// namespace cliext::impl

//
// TEMPLATE CLASS priority_queue
//
template<typename _Value_t,
	typename _Cont_t = cliext::vector<_Value_t> >
	ref class priority_queue
	:	public impl::priority_queue_select<
			_Value_t,
			typename _Dehandle<_Cont_t>::type,
			__is_ref_class(typename _Dehandle<_Value_t>::type)
				&& !is_handle<_Value_t>::value>
	{	// priority queue of elements
public:
	// types
	typedef priority_queue<_Value_t, _Cont_t> _Mytype_t;
	typedef impl::priority_queue_select<
		_Value_t,
		typename _Dehandle<_Cont_t>::type,
		__is_ref_class(typename _Dehandle<_Value_t>::type)
			&& !is_handle<_Value_t>::value> _Mybase_t;
//	typedef cli::array<_Value_t> _Myarray_t;

//	typedef int size_type;
//	typedef int difference_type;
//	typedef _Value_t value_type;
//	typedef value_type% reference;
//	typedef value_type% const_reference;

//	typedef _Mycont_it generic_container;
//	typedef value_type generic_value;

//	typedef _Cont_t container_type;
//	typedef _STLCLR BinaryDelegate<_Value_t, _Value_t, bool>
//		value_compare;

	// basics
	priority_queue()
		{	// construct with empty container
		}

	priority_queue(priority_queue% _Right)
		:	_Mybase_t(_Right.value_comp(), *_Right.get_container())
		{	// construct by copying a priority_queue
		}

	priority_queue(priority_queue^ _Right)
		:	_Mybase_t(_Right->value_comp(), *_Right->get_container())
		{	// construct by copying a priority_queue
		}

	priority_queue% operator=(priority_queue% _Right)
		{	// assign
		_Mybase_t::operator=(_Right);
		return (*this);
		}

	priority_queue% operator=(priority_queue^ _Right)
		{	// assign
		_Mybase_t::operator=(*_Right);
		return (*this);
		}

	// constructors
	explicit priority_queue(value_compare^ _Pred)
		:	_Mybase_t(_Pred)
		{	// construct with empty container, specified predicate
		}

	priority_queue(value_compare^ _Pred, container_type% _Cont)
		:	_Mybase_t(_Pred, _Cont)
		{	// construct with specified predicate and container
		cliext::make_heap(c->begin(), c->end(), comp);
		}

	template<typename _Iter>
		priority_queue(_Iter _First, _Iter _Last)
		{	// construct by copying [_First, _Last), default comparator
		c->insert(c->end(), _First, _Last);
		cliext::make_heap(c->begin(), c->end(), comp);
		}

	template<typename _Iter>
		priority_queue(_Iter _First, _Iter _Last, value_compare^ _Pred)
		:	_Mybase_t(_Pred)
		{	// construct by copying [_First, _Last), specified comparator
		c->insert(c->end(), _First, _Last);
		cliext::make_heap(c->begin(), c->end(), comp);
		}

	template<typename _Iter>
		priority_queue(_Iter _First, _Iter _Last, value_compare^ _Pred,
			container_type% _Cont)
		:	_Mybase_t(_Pred, _Cont)
		{	// construct by copying [_First, _Last), container, and comparator
		c->insert(c->end(), _First, _Last);
		cliext::make_heap(c->begin(), c->end(), comp);
		}

	// interfaces
	virtual System::Object^ Clone() override
		{	// clone the vector
		return (gcnew _Mytype_t(*this));
		}
	};
}	// namespace cliext
#endif // _CLI_QUEUE_
