#ifndef THREADSAFEBELT_H
#define THREADSAFEBELT_H
#include <queue>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include "../Ask1/Product.h"
using namespace std;

class ThreadSafeBelt{
	private:
		queue<Product> beltQueue;
		int maxCapacity;
		mutex beltLock;
		condition_variable notEmpty;
		condition_variable notFull;
	public:
		ThreadSafeBelt(int capacity);
		void dropProductOnBelt(Product p, string producerName);
		Product pickUpProduct(string consumerName);
};

ThreadSafeBelt::ThreadSafeBelt(int capacity){
	maxCapacity=capacity;
	cout<<"[BELT] Thread-safe conveyor belt initialized with capacity: "<<maxCapacity<<endl;
}

void ThreadSafeBelt::dropProductOnBelt(Product p, string producerName){
	unique_lock<mutex> lock(beltLock);
	notFull.wait(lock, [this]() {return beltQueue.size()<maxCapacity;});
	beltQueue.push(p);
	cout<<"[PRODUCER] "<<producerName<<" dropped Product ID "<<p.getId()<<" one the belt. (Items on belt: "
	<<beltQueue.size()<<")"<<endl;
	notEmpty.notify_one();
}

Product ThreadSafeBelt::pickUpProduct(string consumerName){
	unique_lock<mutex> lock(beltLock);
	notEmpty.wait(lock, [this](){return !beltQueue.empty();});
	Product p=beltQueue.front();
	beltQueue.pop();
	cout<<"[CONSUMER] "<<consumerName<<" picked up Product ID "<<p.getId()<<" from the belt. (Items on belt: "
	<<beltQueue.size()<<")"<<endl;
	notFull.notify_one();
	return p;
}




#endif
