#include <unistd.h>
#include "ControlBandit.hpp"

/* --- Public --- */

ControlBandit::ControlBandit() {
	//Initialisation de la queue pour les 1er passes
	for(int i = 0; i < 2; i++) {
		//2 tours pour les 2 passe initiale
		for(int f = 2; f < 6; f++) {
			for(int h = 0; h < 7; h++) {
				fillAndHeuristic fah;
				fah.fill = f;
				fah.heuristic = h;
				queue.push_back(fah);
			}
		}
	}
	//Remplissage tableau moyenne
	for(int f = 0; f < NB_FILL; f++) {
		favg[f] = 0;
		fnb[f] = 0;
	}
	for(int h = 0; h < NB_HEURISTIC; h++){
		havg[h] = 0;
		hnb[h] = 0;
	}
	//Ini method
	method = MT_AVG;
	epsilon = 10;
	//Ini random
	srand(getpid());
}

ControlBandit::~ControlBandit() {

}

void ControlBandit::setMethod(int cstMethod) {
	method = cstMethod;
}

void ControlBandit::setEpsilon(double newEpsilon) {
	if(newEpsilon >= 0 && newEpsilon <= 1) {
		epsilon = (int) (newEpsilon * 100);
	}
}

bool ControlBandit::queueIsEmpty() {
	bool res;
	mutex.lock();
	res = queue.size() == 0;
	mutex.unlock();
	return res;
}

fillAndHeuristic ControlBandit::next() {
	fillAndHeuristic fah;
	mutex.lock();
	if(queue.size() == 0) {
		switch(method) {
			case MT_EPS:
				fah = this->methodEps();
				break;
			default:
				fah = this->methodAvg();
		}
	} else {
		fah = queue[0];
		queue.erase(queue.begin());
	}
	mutex.unlock();
	return fah;
}

void ControlBandit::addFill(int num, int score) {
	num -= 2;
	mutexFill.lock();
	favg[num] = favg[num] + (1 / (fnb[num] + 1.0)) * (score - favg[num]);
	fnb[num]++;
	mutexFill.unlock();
}

void ControlBandit::addHeuristic(int num, int score) {
	mutexHeuristic.lock();
	havg[num] = havg[num] + (1 / (hnb[num] + 1.0)) * (score - havg[num]);
	hnb[num]++;
	mutexHeuristic.unlock();
}

/* --- Private --- */

fillAndHeuristic ControlBandit::methodAvg() {
	fillAndHeuristic fah;
	fah.fill = this->getBestFill();
	fah.heuristic = this->getBestHeuristic();
	return fah;
}

fillAndHeuristic ControlBandit::methodEps() {
	fillAndHeuristic fah;
	//Tirage au sort pour savoir si on prend la meilleur moyenne ou non
	int random = rand() % 100;
	if(random < epsilon) {
		//Tirage au sort de fill et heuristic
		fah.fill = this->getRandomFill();
		fah.heuristic = this->getRandomHeuristic();
		//printf("=== Random === : %d %d\n", fah.fill, fah.heuristic);
	} else {
		//Utilisation des meilleurs fill et heuristic
		fah.fill = this->getBestFill();
		fah.heuristic = this->getBestHeuristic();
	}
	return fah;
}

int ControlBandit::getBestFill() {
	int max = 0;
	int fill = 0;
	mutexFill.lock();
	for(int i = 0; i < NB_FILL; i++) {
		if(favg[i] > max) {
			max = favg[i];
			fill = i;
		}
	}
	mutexFill.unlock();
	return fill + 2;
}

int ControlBandit::getBestHeuristic() {
	int max = 0;
	int h = 0;
	mutexHeuristic.lock();
	for(int i = 0; i < NB_HEURISTIC; i++) {
		if(havg[i] > max) {
			max = havg[i];
			h = i;
		}
	}
	mutexHeuristic.unlock();
	return h;
}