# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    Makefile                                           :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: qmennen <qmennen@student.codam.nl>         +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2024/10/15 11:48:46 by whaffman          #+#    #+#              #
#    Updated: 2025/06/11 17:41:17 by qmennen          ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

NAME = cub3D

FLAGS="-DFULLSCREEN=1"

DIST_PATH  = dist
SRC_PATH   = src
INC_PATH   = inc
LIB_PATH   = lib
BUILD_PATH = build

LIBFT_PATH     = $(LIB_PATH)/libft
LIBFT_INC_PATH = $(LIBFT_PATH)/inc
LIBFT          = $(LIBFT_PATH)/libft.a

MLX42_PATH = $(LIB_PATH)/MLX42
MLX42_TOP_INCLUDE = $(MLX42_PATH)/include
MLX42_INC_PATH = $(MLX42_PATH)/include/MLX42
GLAD_INC_PATH = $(MLX42_PATH)/include/glad
MLX42 = $(MLX42_PATH)/build/libmlx42.a

CC = cc
RM = rm -rf

INCLUDES = -I./$(INC_PATH) -I./$(LIBFT_INC_PATH) -I./$(MLX42_INC_PATH) -I./$(GLAD_INC_PATH) -I./$(MLX42_TOP_INCLUDE)

UNAME_S	:= $(shell uname -s)
ifeq ($(UNAME_S),Linux)
    LDLIBS	:= -L$(LIBFT_PATH) -lft -L$(MLX42_PATH)/build -lmlx42 -ldl -lglfw -pthread -lm
endif

VPATH = $(shell find $(SRC_PATH) -type d | tr '\n' ':')
SOURCES = $(shell basename -a $(shell find $(SRC_PATH) -type f -name "*.c"))
# Include sources.mk if it exists
# -include sources.mk

# Build configurations
BUILD_CONFIGS = release debug asan tsan

release_CFLAGS = -Wall -Wextra -Werror -flto -Ofast -march=native -mtune=native -ffast-math
unity_CFLAGS = -Wall -Wextra -Werror -Ofast -march=native -mtune=native -ffast-math
debug_CFLAGS = -Wall -Wextra -Werror -g3 -DDEBUG -DDBG='fprintf(stderr, RED "DEBUG: " RESET "%s:%d (%s)\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);'
asan_CFLAGS = -Wall -Wextra -Werror -flto -fsanitize=address,leak,undefined -g3
tsan_CFLAGS =  -Wall -Wextra -Werror -fsanitize=thread -g3

RUN_ARGS=test.cub

# Targets for each build configuration
define BUILD_TARGETS
$(1)_OBJ_PATH = $(BUILD_PATH)/$(1)/obj
$(1)_DEPENDS = $$(addprefix $$($(1)_OBJ_PATH)/, $$(SOURCES:.c=.d))
$(1)_OBJECTS = $$(addprefix $$($(1)_OBJ_PATH)/, $$(SOURCES:.c=.o))

.PHONY: $(1)
$(1): CFLAGS = $$($(1)_CFLAGS) $$(FLAGS)
$(1): $(BUILD_PATH)/$(1)/$(NAME)

.PHONY: run_$(1)
run_$(1): $(1)
	$$(info $$(bold)$$(green)Running $(1)$$(reset))
	./$(BUILD_PATH)/$(1)/$(NAME) $(RUN_ARGS)

$(BUILD_PATH)/$(1)/$(NAME): $(LIBFT) $(MLX42) $$($(1)_OBJECTS) Makefile
	$$(info $$(bold)$$(green)Linking $(1) config$$(reset))
	$$(CC) $$(CFLAGS) $$($(1)_OBJECTS) $$(LDLIBS) -o $$@

-include $$($(1)_DEPENDS)

$$($(1)_OBJ_PATH)/%.o: %.c $(LIBFT) $(MLX42) Makefile | $$($(1)_OBJ_PATH)
	$$(CC) $$(CFLAGS) $$(INCLUDES) -MMD -MP -c $$< -o $$@

$$($(1)_OBJ_PATH):
	$$(info $$(bold)$$(green)Creating $(1) object directory$$(reset))
	mkdir -p $$@
endef

# Copy the release build configuration to the root
$(NAME): release
	$(info $(bold)$(green)Copying release build to root$(reset))
	cp $(BUILD_PATH)/release/$(NAME) $@

$(foreach config,$(BUILD_CONFIGS),$(eval $(call BUILD_TARGETS,$(config))))

# Build all configurations
all: release debug asan tsan
	$(info $(bold)$(green)All builc config have been build$(reset))

# Unity/Jumbo/Blob build
ALL_SOURCES = $(shell find $(SRC_PATH) -type f -name "*.c")

run_unity: $(BUILD_PATH)/unity/$(NAME)
	$(info $(bold)$(green)Running unity build$(reset))
	./$(BUILD_PATH)/unity/$(NAME) $(RUN_ARGS)

unity: $(BUILD_PATH)/unity/$(NAME)

$(BUILD_PATH)/unity/$(NAME): $(BUILD_PATH)/unity/blob.c $(LIBFT) $(MLX42) $(ALL_SOURCES)
	$(info $(bold)$(green)Building unity blob$(reset))
	$(CC) $(unity_CFLAGS) $(INCLUDES) -Isrc -MMD -MP -c $(BUILD_PATH)/unity/blob.c -o $(BUILD_PATH)/unity/blob.o
	$(CC) $(unity_CFLAGS) $(INCLUDES) -o $@ $(BUILD_PATH)/unity/blob.o $(LDLIBS)


$(BUILD_PATH)/unity/blob.c: $(ALL_SOURCES) $(BUILD_PATH)/unity
	$(info $(bold)$(green)Generating unity blob.c$(reset))
	@echo "/* This file is generated by the Makefile */" > $@
	@echo "#include \"cub3d.h\"" >> $@
	@echo $(ALL_SOURCES) | tr ' ' '\n' | sed 's%^%#include "../../%; s/$$/"/' >> $@

$(BUILD_PATH)/unity:
	$(info $(bold)$(green)Creating unity build directory$(reset))
	mkdir -p $(BUILD_PATH)/unity

# Build libft
$(LIBFT): $(LIBFT_PATH) submodules
	$(info $(bold)$(green)Building libft$(reset))
	$(MAKE) -C $(LIBFT_PATH)

$(LIBFT_PATH):
	$(info $(bold)$(green)Adding libft submodule$(reset))
	git submodule add https://gitea.duinvoetje.nl/willem/libft.git $(LIBFT_PATH)

# Build MLX42
$(MLX42): $(MLX42_PATH)
	$(info $(bold)$(green)Building MLX42$(reset))
	cmake $(MLX42_PATH) -B $(MLX42_PATH)/build
	$(MAKE) -C $(MLX42_PATH)/build -j4

$(MLX42_PATH):
	git submodule add https://github.com/codam-coding-college/MLX42.git $(MLX42_PATH);

# Generate sources.mk
sources.mk:
	$(info $(bold)$(green)Generating sources.mk$(reset))
	@echo "VPATH = $$(find $(SRC_PATH) -type d | tr '\n' ':')" > sources.mk
	@echo "SOURCES = $$(find $(SRC_PATH) -type f -name '*.c' -exec basename {} \; | tr '\n' ' ' | fold -s -w 70 | sed 's/$$/ \\/')" >> sources.mk

# Remove build artifacts
clean:
	$(info $(bold)$(red)Cleaning$(reset))
	find $(BUILD_PATH) -type d -name 'obj' -exec $(RM) {} +
	$(MAKE) -C $(LIBFT_PATH) fclean
	$(MAKE) -C $(MLX42_PATH)/build clean

# Remove build artifacts and the executable
fclean: clean
	$(info $(bold)$(red)Full cleaning$(reset))
	$(RM) $(BUILD_PATH)
	$(RM) $(NAME)

# Rebuild the project
re: fclean
	$(info $(bold)$(green)Rebuilding$(reset))
	$(MAKE) all $(NAME)

# Run the project with the release build configuration
run: run_release

run_valgrind: debug
	valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --suppressions=MLX42.supp ./$(BUILD_PATH)/debug/$(NAME)
#
# Remove sources.mk to force regeneration
srcs:
	$(info $(bold)$(green)Regenerating sources.mk on next make$(reset))
	$(RM) sources.mk

# dist: $(SRC_PATH) $(INC_PATH) $(LIB_PATH) release_makefile.mk
# 	@if [ ! -d $(DIST_PATH) ]; then \
# 		mkdir -p $(DIST_PATH); \
# 	else \
# 		rm -rf $(DIST_PATH)/*; \
# 	fi
# 	@rsync -av --include='*/' --include='*.c' --include='*.h' --include='Makefile' --exclude='*' src/ $(DIST_PATH)/src/
# 	@rsync -av --include='*/' --include='*.c' --include='*.h' --include='Makefile' --exclude='*' inc/ $(DIST_PATH)/inc/
# 	@rsync -av --include='*/' --include='*.c' --include='*.h' --include='Makefile' --exclude='*' lib/ $(DIST_PATH)/lib/
# 	@cp release_makefile.mk $(DIST_PATH)/Makefile
# 	@make -s sources.mk
# 	@cp sources.mk $(DIST_PATH)/sources.mk
# 	@norminette $(DIST_PATH) > /dev/null; \
# 	if [ $$? -ne 0 ]; then \
# 		echo "\e[31mNorminette failed, deleting dist folder\e[0m"; \
# 		norminette $(DIST_PATH) | grep "Error"; \
# 		rm -rf $(DIST_PATH); \
# 		exit 1; \
# 	fi
# 	@echo -e "\e[32mDistribute successful\e[0m"

# Show this help.
help:
	@echo "Usage: make [target]"
	@echo ""
	@echo "Targets:"
	@echo "  $(green)$(bold)all          $(reset)- Build all configurations (release, debug, asan, tsan)"
	@echo "  $(green)$(bold)dist         $(reset)- rebuild the folderstructure for distribution"
	@echo "  $(green)$(bold)clean        $(reset)- Remove build artifacts"
	@echo "  $(green)$(bold)fclean       $(reset)- Remove build artifacts and the executable"
	@echo "  $(green)$(bold)re           $(reset)- Rebuild the project"
	@echo "  $(green)$(bold)run          $(reset)- Run the release build"
	@echo "  $(green)$(bold)srcs         $(reset)- Remove sources.mk"
	@echo "  $(green)$(bold)help         $(reset)- Show this help message"
	@echo ""
	@echo "Build configurations:"
	@echo "  $(green)$(bold)release      $(reset)- Build with release configuration"
	@echo "  $(green)$(bold)debug        $(reset)- Build with debug configuration"
	@echo "  $(green)$(bold)asan         $(reset)- Build with AddressSanitizer configuration"
	@echo "  $(green)$(bold)tsan         $(reset)- Build with ThreadSanitizer configuration"
	@echo ""
	@echo "Run configurations:"
	@echo "  $(green)$(bold)run_release  $(reset)- Run the release build"
	@echo "  $(green)$(bold)run_debug    $(reset)- Run the debug build"
	@echo "  $(green)$(bold)run_asan     $(reset)- Run the AddressSanitizer build"
	@echo "  $(green)$(bold)run_tsan     $(reset)- Run the ThreadSanitizer build"
	@echo "  $(green)$(bold)run_valgrind $(reset)- Run the release build with valgrind"
	@echo ""
	@echo "Other targets:"
	@echo "  $(green)$(bold)submodules   $(reset)- Check and reinitialize git submodules"
	@echo "  $(green)$(bold)libft        $(reset)- Build libft"
	@echo "  $(green)$(bold)sources.mk   $(reset)- Generate sources.mk"
	@echo ""

.PHONY: submodules
submodules:
	$(info $(bold)$(green)Checking and reinitializing submodules$(reset))
	@if git submodule status | egrep -q '^[-+]' ; then \
			echo "INFO: Need to reinitialize git submodules"; \
			git submodule update --init; \
	fi

.PHONY: all clean fclean re srcs run help dist

red:=$(shell tput setaf 1)
green:=$(shell tput setaf 2)
yellow:=$(shell tput setaf 3)
blue:=$(shell tput setaf 4)
magenta:=$(shell tput setaf 5)
cyan:=$(shell tput setaf 6)
white:=$(shell tput setaf 7)

bold:=$(shell tput bold)
underline:=$(shell tput smul)

reset:=$(shell tput sgr0)

