#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <graph.h>
#include "graphsup.h"

//----------------------------- Framerate -----------------------------//

#define DEFAULT_FRAMERATE 60.0

//Des variables afin de faciliter le calcul du temps entre chaque image pour int nextFrame().
double targetFramerate = DEFAULT_FRAMERATE;
double delta = (1/DEFAULT_FRAMERATE) * 1000000;
unsigned long suivant = (1/DEFAULT_FRAMERATE) * 1000000;

//Ajuste la fréquence de rafraichissement donnée par nextFrame().
void setFramerate(int framerate) {
	targetFramerate = (double)framerate;
	delta = (1/targetFramerate) * 1000000;
	suivant = Microsecondes() + delta;
}

//Permet de faire tourner la partie graphique à X images par seconde définit par targetFramerate et setFramerate.
int nextFrame() {
	unsigned long t = Microsecondes();
	if (t >= suivant) {
		suivant = t + delta;
		return 1;
	}

	return 0;
}

//------------------------------ Couleurs ------------------------------//

//Retourne une couleur suivant son nom.
couleur getColorN(char* name) {
	return CouleurParNom(name);
}

//Retourne une couleur suivant son code RGB.
couleur getColor(unsigned char r, unsigned char g, unsigned char b) {
	return CouleurParComposante(r, g, b);
}

//Définit la couleur des dessins à suivre suivant un code RGB.
void setColor(unsigned char r, unsigned char g, unsigned char b) {
	ChoisirCouleurDessin(GetColor(r, g, b));
}

//Définit la couleur des dessins à suivre suivant la couleur donnée.
void setColorC(couleur Color) {
	ChoisirCouleurDessin(Color);
}

//Définit la couleur des dessins à suivre suivant le nom donné.
void setColorN(char* name) {
	ChoisirCouleurDessin(GetColorN(name));
}

couleur getHSVColor(double h, double s, double v) {

	double c = v * s;
	double m = v - c;

	double r, g, b;
	h -= (double)(int)h;

	if (h <= 1.0 / 6.0) {
		r = 255.0;
		g = h * 6.0 * 255.0;
		b = 0.0;
	} else if (h <= 2.0 / 6.0) {
		r = (1.0 - (h - 1.0 / 6.0) * 6.0) * 255.0;
		g = 255.0;
		b = 0.0;
	} else if (h <= 3.0 / 6.0) {
		r = 0.0;
		g = 255.0;
		b = (h - 1.0 / 6.0) * 6.0 * 255.0;
	} else if (h <= 4.0 / 6.0) {
		r = 0.0;
		g = (1.0 - (h - 0.5) * 6.0) * 255.0;
		b = 255.0;
	} else if (h <= 5.0 / 6.0) {
		r = (h - 4.0 / 6.0) * 6.0 * 255.0;
		g = 0.0;
		b = 255.0;
	} else {
		r = 255.0;
		g = 0.0;
		b = (1.0 - (h - 5.0 / 6.0) * 6.0) * 255.0;
	}

	r += m;
	g += m;
	b += m;

	return CouleurParComposante(r, g, b);
}

//------------------------------ Dessins ------------------------------//

void drawRegPoly(int x, int y, int s, double r, double a) {
	double delta = M_PI * 2.0 / s;

	for (int i = 0; i < s; i++) {
		int x1 = (int)(cos(delta * i + a) * r + x);
		int y1 = (int)(sin(delta * i + a) * r + y);

		int x2 = (int)(cos(delta * (i+1) + a) * r + x);
		int y2 = (int)(sin(delta * (i+2) + a) * r + y);

		DessinerSegment(x1, y1, x2, y2);
	}
}

void fillRegPoly(int x, int y, int s, double r, double a) {
	double delta = M_PI * 2.0 / s;

	for (int i = 0; i < s; i++) {
		int x1 = (int)(cos(delta * i + a) * r + x);
		int y1 = (int)(sin(delta * i + a) * r + y);

		int x2 = (int)(cos(delta * (i+1) + a) * r + x);
		int y2 = (int)(sin(delta * (i+2) + a) * r + y);

		RemplirTriangle(x, y, x1, y1, x2, y2);
	}
}

//------------------------------ Boutons ------------------------------//

button* firstButton = NULL;

//Enlève tous les boutons présents
void clearButtons(void) {
	if (firstButton == NULL) return;

	button* bt = firstButton;

	while(bt != NULL) {
		button* next = bt->next;
		free(bt);
		bt = next;
	}
}

//Retourne un bouton suivant son identifiant
button* getButton(char* index) {
	button* bt = firstButton;

	while (bt != NULL) {
		char* btIndex;
		if (bt->type == RECT_BUTTON) btIndex = ((rectButton*)bt)->id;
		else if (bt-> type == CIRCLE_BUTTON) btIndex = ((circleButton*)bt)->id;
		else {
			printf("Button type error.");
			exit(1);
		}

		if (!strcmp(index, btIndex)) {
			return bt;
		}

		bt = bt->next;
	}
}

//Retourne un bouton rectangulaire suivant son identifiant
rectButton* getRectButton(char* index) {
	button* bt = firstButton;

	while (bt != NULL) {
		char* btIndex;
		if (bt->type == RECT_BUTTON) {
			btIndex = ((rectButton*)bt)->id;

			if (!strcmp(index, btIndex)) {
				return (rectButton*)bt->pointer;
			}
		}
	}
}

//Retourne un bouton rectangulaire ou NULL si le bouton donné n'est pas un bouton rectangulaire.
rectButton* toRectButton(button* bt) {
	if (bt->type != RECT_BUTTON) return NULL;
	return (rectButton*)bt->pointer;
}

//Crée un bouton rectangulaire et en retourne le pointeur.
rectButton* addRectButton(int x, int y, int w, int h, char* id) {
	rectButton* rbt = (rectButton*)malloc(sizeof(rectButton));

	rbt->x = x;
	rbt->y = y;
	rbt->w = w;
	rbt->h = h;
	rbt->id = id;

	button* bt = (button*)malloc(sizeof(button));
	bt->type = RECT_BUTTON;
	bt->pointer = (void*)rbt;
	bt->next = NULL;

	button* buttonChain = firstButton;
	while (buttonChain->next != NULL) buttonChain = buttonChain->next;
	buttonChain->next = bt;
	return rbt;
}


//Retourne un bouton rectangulaire suivant son identifiant
rectButton* getCircleButton(char* index) {
	button* bt = firstButton;

	while (bt != NULL) {
		char* btIndex;
		if (bt->type == CIRCLE_BUTTON) {
			btIndex = ((circleButton*)bt)->id;

			if (!strcmp(index, btIndex)) {
				return (circleButton*)bt->pointer;
			}
		}
	}
}

//Retourne un bouton circulaire ou NULL si le bouton donné n'est pas un bouton circulaire.
circleButton* toCircleButton(button* bt) {
	if (bt->type != CIRCLE_BUTTON) return NULL;
	return (circleButton*)bt->pointer;
}

//Crée un bouton rectangulaire et en retourne le pointeur.
circleButton* addCircleButton(int x, int y, int r, char* id) {
	circleButton* rbt = (circleButton*)malloc(sizeof(circleButton));

	rbt->x = x;
	rbt->y = y;
	rbt->r = r;
	rbt->id = id;

	button* bt = (button*)malloc(sizeof(button));
	bt->type = CIRCLE_BUTTON;
	bt->pointer = (void*)rbt;
	bt->next = NULL;

	button* buttonChain = firstButton;
	while (buttonChain->next != NULL) buttonChain = buttonChain->next;
	buttonChain->next = bt;
	return rbt;
}