#ifndef THREADMANAGER_H
#define THREADMANAGER_H
#include <vector>
#include <thread>
#include <string>
#include <iostream>
#include "../Ask1/Product.h"
#include "../Ask1/Machine.h"
#include "../Ask4/ThreadSafeBelt.h"
using namespace std;

class ThreadManager{
	private:
		vector<thread> workers;
		vector<string> threadNames;
		int totalThreads;
		ThreadSafeBelt factoryBelt;
		void runDeliveryTruck(int totalProductsToDeliver);
	public:
		ThreadManager(int numThreads);
		void startFactorySegment(int productsToConsume, string threadName);
		void spawnWorkers();
		void joinAll();
		void printManagerStatus();
};

ThreadManager::ThreadManager(int numThreads):factoryBelt(10){
	totalThreads=numThreads;
	cout<<"Thread Manager online. Belt capacity set to 10."<<endl;
}

void ThreadManager::printManagerStatus(){
	cout<<"----------------------"<<endl<<"|                    |"
	<<endl<<"| Lanching "<<totalThreads<<" threads |"<<endl<<"|                    |"
	<<endl<<"----------------------"<<endl;
}

void ThreadManager::runDeliveryTruck(int totalProductsToDeliver){
	cout<<"[MANAGER] The Delivery Truck has arrived with "<<totalProductsToDeliver<<" raw materials."<<endl;
	for(int i=1; i<=totalProductsToDeliver; i++){
		Product rawMaterial(i);
		factoryBelt.dropProductOnBelt(rawMaterial, "Delivery_Truck");
	}
	cout<<"[MANAGER] Delivery Truck is empty and going home."<<endl;
}

void ThreadManager::startFactorySegment(int productsToConsume, string threadName){
	Machine localAssembler("Assembler",1);
	Machine localPainter("Painter",2);
	Machine localPackager("Packager",1);
	for(int i=0; i<productsToConsume; i++){
		Product p=factoryBelt.pickUpProduct(threadName);
		localAssembler.process(p);
		localPainter.process(p);
		localPackager.process(p);
		cout<<"[ "<<threadName<<" ] finished processing product "<<i<<endl;
	}
}

void ThreadManager::spawnWorkers(){
	int totalProducts=100;
	int productsPerThread=totalProducts/totalThreads;
	workers.push_back(thread(&ThreadManager::runDeliveryTruck, this, totalProducts));
	threadNames.push_back("Delivery_Truck");
	for(int i=0;i<totalThreads;i++){
		string tName="Worker_Thread_"+to_string(i+1);
		threadNames.push_back(tName);
		workers.push_back(thread(&ThreadManager::startFactorySegment,this,productsPerThread,tName));
	}
}

void ThreadManager::joinAll(){
	cout<<"\nInitiating Factory Shutdown Sequence..."<<endl;
	for(int i=0;i<workers.size();i++){
		if(workers[i].joinable()){
			cout<<"Waiting for "<<threadNames[i]<<" to clock out..."<<endl;
			workers[i].join();
			cout<<threadNames[i]<<" has safely powered down."<<endl;
		}
	}
	cout<<"All workers and the Delivery Truck succesfully joined. Factory is closed."<<endl;
}





#endif
