// queuetp.h -- šablona fronty s vnořenou třídou
#ifndef QUEUETP_H_
#define QUEUETP_H_

template <class Item>
class QueueTP
{
private:
	enum {Q_SIZE = 10};
	// Node je definice vnořené třídy
	class Node
	{
	public:
		Item item;
		Node * next;
		Node(const Item & i):item(i), next(0){ }
	};
	Node * front; // ukazatel na začátek fronty
	Node * rear; // ukazatel na konec fronty
	int items; // aktuální počet položek fronty
	const int qsize; // maximální počet položek fronty
	QueueTP(const QueueTP & q) : qsize(0) {}
	QueueTP & operator=(const QueueTP & q) { return *this; }
public:
	QueueTP(int qs = Q_SIZE);
	~QueueTP();
	bool isempty() const
	{
	return items == 0;
	}
	bool isfull() const
	{
	return items == qsize;
	}
	int queuecount() const
	{
	return items;
	}
	bool enqueue(const Item &item); // přidá položku na konec fronty
	bool dequeue(Item &item); // odebere položku z fronty
};

// metody šablony QueueTP
template <class Item>
QueueTP<Item>::QueueTP(int qs) : qsize(qs)
{
	front = rear = 0;
	items = 0;
}
template <class Item>
QueueTP<Item>::~QueueTP()
{
	Node * temp;
	while (front != 0) // dokud fronta není prázdná
	{
		temp = front; // uloží adresu první položky
		front = front->next;// nastaví ukazatel na následující položku
		delete temp; // zruší původní první položku
	}
}

// Přidání položky na konec fronty
template <class Item>
bool QueueTP<Item>::enqueue(const Item & item)
{
	if (isfull())
		return false;
	Node * add = new Node(item); // vytvoří uzel
	if (add == NULL)
		return false; // konec v případě nedostatku paměti
	items++;
	if (front == 0) // jestliže je fronta prázdná,
		front = add; // přidá položku na začátek fronty
	else
		rear->next = add; // jinak na konec fronty
	rear = add; // ukazatel na konec fronty ukazuje na nový uzel
	return true;
}

// Uloží první položku do proměnné item a odstraní ji z fronty
template <class Item>
bool QueueTP<Item>::dequeue(Item & item)
{
	if (front == 0)
		return false;
	item = front->item; // nastaví item na první položku fronty
	items--;
	Node * temp = front; // uloží adresu první položky
	front = front->next; // nastaví začátek na následující položku
	delete temp; // zruší původní první položku
	if (items == 0)
		rear = 0;
	return true;
}

#endif
