#include <raylib.h>
#include <rdrawing.h>
#include <math.h>

#define RAYGUI_IMPLEMENTATION
#include <raygui.h>

void updateRadius(float baseL, float outerL,float pointL, float *pBaseR, float *pOuterR, float *pPointR)  {
	int totalL=baseL+outerL;
	if (pointL>outerL)
		totalL+=pointL;
	else
		totalL+=outerL;
	int totalR = 340;
	int remainder = totalR % totalL;
	if (remainder!=0) {
		if (remainder < totalL / 2) {
			totalR -= remainder;
		} else {
			totalR += ( totalL - remainder);
		}
	}
	*pBaseR = (totalR) / totalL * baseL;
	*pOuterR = (totalR) / totalL * outerL;
	*pPointR = (totalR) / totalL * pointL;
}


int main() {
	float baseL=2;
	float outerL=13;
	float pointL=3;
	float baseR,outerR,pointR;
	int cx=350,cy=350;
	float speed = 1;
	Color trackColor = BLUE;
	updateRadius(baseL, outerL, pointL, &baseR, &outerR, & pointR);
	InitWindow(1000,700,"Epitrochoid");
	SetTraceLogLevel(LOG_WARNING);
	SetTargetFPS(60);
	GuiSetStyle(DEFAULT,TEXT_SIZE,20);
	
	Image trackImage=GenImageColor(700,700,WHITE);
	//border
	ImageFillRectangleEx(&trackImage,0,0,700,700,LIGHTGRAY);
	ImageFillRectangleEx(&trackImage,5,5,690,690,WHITE);
	
	Image circlesImage = GenImageColor(700,700,BLANK);
	float r=0;
	int lastx,lasty;
	lasty=cy;
	lastx=cx+(baseR+outerR-pointR);
	int frameCount = 0;
	while(!WindowShouldClose()) {
		//GUI
		float newOuterL = outerL, newBaseL = baseL, newPointL = pointL;
		GuiSliderBar((Rectangle){ 70, 20,  100, 30 },"Outer",TextFormat("%i", (int)outerL), &newOuterL, 1, 50);
		GuiSliderBar((Rectangle){ 70, 60,  100, 30 },"Base",TextFormat("%i", (int)baseL), &newBaseL, 1, 50);
		GuiSliderBar((Rectangle){ 70, 100, 100, 30 },"Point",TextFormat("%i", (int)pointL), &newPointL, 1, 50);
		GuiSliderBar((Rectangle){ 70, 150, 100, 30 },"Speed",TextFormat("%i", (int)speed), &speed, 1, 50);
		GuiLabel((Rectangle){ 20, 220, 180, 30 },TextFormat("Color: 0x%02X%02X%02X",(int)(trackColor.r), (int)(trackColor.g),(int)(trackColor.b)));
		GuiColorPicker((Rectangle){ 50, 250, 196, 192 }, NULL, &trackColor);
		int doClear = GuiButton((Rectangle){ 120, 500, 80, 30 },"Clear");
		if (newOuterL!=outerL || newBaseL!=baseL || newPointL!=pointL) {
			if (newOuterL!=outerL) 
				pointL=newOuterL;
			else
				pointL=newPointL;
			outerL=newOuterL;
			baseL=newBaseL;
			updateRadius(baseL, outerL, pointL, &baseR, &outerR, & pointR);
			lasty=cy;
			lastx=cx+(baseR+outerR-pointR);
			r=0;
			ImageClearBackground(&trackImage,WHITE);
			ImageFillRectangleEx(&trackImage,0,0,700,700,LIGHTGRAY);
			ImageFillRectangleEx(&trackImage,5,5,690,690,WHITE);			
		} else if (doClear) {
			ImageClearBackground(&trackImage,WHITE);
			ImageFillRectangleEx(&trackImage,0,0,700,700,LIGHTGRAY);
			ImageFillRectangleEx(&trackImage,5,5,690,690,WHITE);						
		}
		//update datas
		r+=0.01;
		float outerCX=cx+ (baseR+outerR)*cos(r);
		float outerCY=cy+ (baseR+outerR)*sin(r);
		float theta = r * (baseL+outerL) / outerL; 
		int x=round(outerCX - pointR * cos(theta));
		int y=round(outerCY - pointR * sin(theta));		
		
		//update image (in CPU)
		//ImageClearBackground(&trackImage,WHITE);
		ImageDrawLineEx2(&trackImage,lastx,lasty,x,y,3,trackColor);

		frameCount++;
		if (frameCount>=speed) {
			ImageClearBackground(&circlesImage,BLANK);
			//base circle
			ImageDrawCircleEx(&circlesImage,cx,cy,baseR,1,LIGHTRED);
			ImageDrawCircleEx(&circlesImage,outerCX,outerCY,outerR,1,LIGHTSLATEGRAY);
			ImageDrawLineEx2(&circlesImage,cx,cy,outerCX,outerCY,1,LIGHTRED);
			ImageDrawLineEx2(&circlesImage,x,y,outerCX,outerCY,1,LIGHTSLATEGRAY);
			ImageDrawPointEx(&circlesImage,x,y,7,RED);
			
			//Drawing in GPU
			Texture trackTexture = LoadTextureFromImage(trackImage);
			Texture circlesTexture = LoadTextureFromImage(circlesImage);
			BeginDrawing();
			ClearBackground(WHITE);
			DrawTexture(trackTexture,300,0,WHITE);
			DrawTexture(circlesTexture,300,0,WHITE);
			EndDrawing();
			UnloadTexture(circlesTexture);
			UnloadTexture(trackTexture);
			frameCount=0;			
		}
		
		lastx=x;
		lasty=y;
	}
	
	//Clean up
	UnloadImage(circlesImage);
	UnloadImage(trackImage);
	CloseWindow();
}
