CC ?= gcc
# Use ANSI89 and pedantic flags for strict compliance
CFLAGS = -O3 -ansi -pedantic -Wall -fPIC
TCL_INC ?= /usr/include/tcl8.6
TCL_LIB ?= -ltcl8.6 -ltk8.6
LIBS = 

# Cross-compilation settings for MinGW-w64
CROSS_WIN32_CC ?= i686-w64-mingw32-gcc
CROSS_WIN64_CC ?= x86_64-w64-mingw32-gcc

# Detect system type automatically
UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)

# Set defaults for shared library and executable extensions
SHLIB_EXT = .so
EXE_EXT =

# Target OS detection
ifneq ($(findstring MINGW,$(UNAME_S)),)
    SYS_TYPE = WINDOWS
endif
ifneq ($(findstring MSYS,$(UNAME_S)),)
    SYS_TYPE = WINDOWS
endif
ifneq ($(findstring CYGWIN,$(UNAME_S)),)
    SYS_TYPE = WINDOWS
endif
ifeq ($(UNAME_S),Darwin)
    SYS_TYPE = DARWIN
endif
ifeq ($(UNAME_S),IRIX)
    SYS_TYPE = IRIX
endif
ifeq ($(UNAME_S),IRIX64)
    SYS_TYPE = IRIX
endif
ifndef SYS_TYPE
    SYS_TYPE = LINUX
endif

# Multi-threading support (pthreads)
# Set USE_THREADS=1 to enable, USE_THREADS=0 to disable
USE_THREADS ?= 1
USE_OPENGL ?= 1

# Default Linux / Unix settings
SHLIB_FLAGS = -shared
TCL_INCLUDES = -I$(TCL_INC)
DL_LIB = -ldl
ifeq ($(USE_OPENGL),1)
    OPENGL_LIBS = -lGL -lGLU -lglut -lXmu -lX11
endif

# ------------------------------------------------------------------------------
# WINDOWS CONFIGURATION
# ------------------------------------------------------------------------------
ifeq ($(SYS_TYPE),WINDOWS)
    export PATH := /ucrt64/bin:/mingw64/bin:$(PATH)
    SHLIB_EXT = .dll
    EXE_EXT = .exe

    # Default compiler lookup for MinGW / MSYS2
    HAVE_UCRT64_GCC := $(wildcard /ucrt64/bin/gcc.exe)
    HAVE_MINGW64_GCC := $(wildcard /mingw64/bin/gcc.exe)
    HAVE_C_UCRT64_GCC := $(wildcard C:/msys64/ucrt64/bin/gcc.exe)

    ifeq ($(origin CC),default)
        ifneq ($(HAVE_UCRT64_GCC),)
            CC = /ucrt64/bin/gcc
        else
            ifneq ($(HAVE_MINGW64_GCC),)
                CC = /mingw64/bin/gcc
            else
                ifneq ($(HAVE_C_UCRT64_GCC),)
                    CC = C:/msys64/ucrt64/bin/gcc
                else
                    CC = gcc
                endif
            endif
        endif
    endif

    TCL_DIR ?= C:/Tcl
    HAVE_UCRT64_TCL := $(wildcard /ucrt64/include/tcl.h)
    HAVE_MINGW64_TCL := $(wildcard /mingw64/include/tcl.h)
    HAVE_C_UCRT64_TCL := $(wildcard C:/msys64/ucrt64/include/tcl.h)
    HAVE_C_MINGW64_TCL := $(wildcard C:/msys64/mingw64/include/tcl.h)
    HAVE_TCL_DIR_TCL := $(wildcard $(TCL_DIR)/include/tcl.h)

    ifneq ($(HAVE_UCRT64_TCL),)
        WIN_TCL_INC = /ucrt64/include
        WIN_TCL_LIB = -L/ucrt64/bin -L/ucrt64/lib -ltclstub86
    else
        ifneq ($(HAVE_MINGW64_TCL),)
            WIN_TCL_INC = /mingw64/include
            WIN_TCL_LIB = -L/mingw64/bin -L/mingw64/lib -ltclstub86
        else
            ifneq ($(HAVE_C_UCRT64_TCL),)
                WIN_TCL_INC = C:/msys64/ucrt64/include
                WIN_TCL_LIB = -L"C:/msys64/ucrt64/bin" -L"C:/msys64/ucrt64/lib" -ltclstub86
            else
                ifneq ($(HAVE_C_MINGW64_TCL),)
                    WIN_TCL_INC = C:/msys64/mingw64/include
                    WIN_TCL_LIB = -L"C:/msys64/mingw64/bin" -L"C:/msys64/mingw64/lib" -ltclstub86
                else
                    ifneq ($(HAVE_TCL_DIR_TCL),)
                        WIN_TCL_INC = $(TCL_DIR)/include
                        WIN_TCL_LIB = -L"$(TCL_DIR)/bin" -L"$(TCL_DIR)/lib" -ltclstub86
                    else
                        WIN_TCL_INC = /usr/include/tcl8.6
                        WIN_TCL_LIB = -ltclstub86
                    endif
                endif
            endif
        endif
    endif

    TCL_INC = $(WIN_TCL_INC)
    TCL_INCLUDES = -I$(TCL_INC)
    TCL_LIB = $(WIN_TCL_LIB)
    CFLAGS += -DUSE_TCL_STUBS
    DL_LIB =
    LIBS = -lws2_32 -lgdi32 -luser32 -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic
    SHLIB_FLAGS = -shared -Wl,--export-all-symbols
    FEM_SHLIB_FLAGS = $(SHLIB_FLAGS)
    FEPRO_SHLIB_FLAGS = $(SHLIB_FLAGS)
    ifeq ($(USE_OPENGL),1)
        OPENGL_LIBS = -lopengl32 -lglu32
        FREEGLUT_CHECK := $(wildcard /mingw64/lib/libfreeglut.a)$(wildcard /ucrt64/lib/libfreeglut.a)$(wildcard C:/msys64/mingw64/lib/libfreeglut.a)
        ifneq ($(FREEGLUT_CHECK),)
            OPENGL_LIBS += -lfreeglut
        endif
    endif
endif

# ------------------------------------------------------------------------------
# MACOS (DARWIN) CONFIGURATION
# ------------------------------------------------------------------------------
ifeq ($(SYS_TYPE),DARWIN)
    SHLIB_EXT = .dylib
    EXE_EXT =
    MACOS_TCL_DIR ?= /opt/homebrew/Cellar/tcl-tk@8/8.6.18

    HAVE_MACOS_CELLAR_TCL := $(wildcard $(MACOS_TCL_DIR)/include/tcl-tk/tcl.h)
    HAVE_MACOS_OPT_TCL := $(wildcard /opt/homebrew/opt/tcl-tk@8/include/tcl-tk/tcl.h)
    HAVE_MACOS_USR_TCL := $(wildcard /usr/local/opt/tcl-tk@8/include/tcl-tk/tcl.h)
    HAVE_MACOS_GEN_TCL := $(wildcard /opt/homebrew/include/tcl.h)

    ifeq ($(HAVE_MACOS_CELLAR_TCL),)
        ifneq ($(HAVE_MACOS_OPT_TCL),)
            MACOS_TCL_DIR = /opt/homebrew/opt/tcl-tk@8
        else
            ifneq ($(HAVE_MACOS_USR_TCL),)
                MACOS_TCL_DIR = /usr/local/opt/tcl-tk@8
            else
                ifneq ($(HAVE_MACOS_GEN_TCL),)
                    MACOS_TCL_DIR = /opt/homebrew
                endif
            endif
        endif
    endif

    TCL_INCLUDES = -I$(MACOS_TCL_DIR)/include/tcl-tk -I$(MACOS_TCL_DIR)/include
    TCL_LIB =
    SHLIB_FLAGS = -dynamiclib -undefined dynamic_lookup
    FEM_SHLIB_FLAGS = $(SHLIB_FLAGS)
    FEPRO_SHLIB_FLAGS = $(SHLIB_FLAGS)
    FEPRO_SOLVER_CFLAGS = -O3 -ansi -pedantic -Wall -fPIC -DUSE_PTHREADS
    MACOS_GL_INC = -I.macos_inc
    MACOS_INC_DEP = .macos_inc/GL/glut.h
    DL_LIB =
    CFLAGS += -DGL_SILENCE_DEPRECATION
    OPENGL_LIBS = -framework OpenGL -framework GLUT -framework Cocoa
endif

# ------------------------------------------------------------------------------
# SGI IRIX CONFIGURATION
# ------------------------------------------------------------------------------
ifeq ($(SYS_TYPE),IRIX)
    USE_THREADS = 0
    CC = cc
    CFLAGS = -O3 -mips4 -r10000 -OPT:IEEE_arithmetic=3 -OPT:roundoff=3 -OPT:alias=typed -LNO:opt=1 -ansi -fullwarn
    TCL_INC = /usr/freeware/include
    TCL_INCLUDES = -I$(TCL_INC)
    TCL_LIB = /usr/freeware/lib32/libtk.so /usr/freeware/lib32/libtcl.so
    SHLIB_FLAGS = -shared
    DL_LIB = -ldl
    ifeq ($(USE_OPENGL),1)
        OPENGL_LIBS = -lglut -lGL -lGLU -lXmu -lX11
    endif
endif

# Fallback defaults for flags if not set
SHLIB_FLAGS ?= -shared
FEM_SHLIB_FLAGS ?= $(SHLIB_FLAGS)
FEPRO_SHLIB_FLAGS ?= $(SHLIB_FLAGS)

ifeq ($(USE_THREADS),1)
    CFLAGS += -DUSE_PTHREADS
    ifneq ($(SYS_TYPE),WINDOWS)
        LIBS += -lpthread
    endif
endif

ifeq ($(USE_OPENGL),1)
    ifeq ($(SYS_TYPE),LINUX)
        CFLAGS += -DUSE_OPENGL
        LIBS += $(OPENGL_LIBS)
    endif
    ifeq ($(SYS_TYPE),IRIX)
        CFLAGS += -DUSE_OPENGL
        LIBS += $(OPENGL_LIBS)
    endif
endif

FEPRO_SOLVER_CFLAGS ?= $(CFLAGS)

FEM_SOLVER_LIB = fem_solver$(SHLIB_EXT)
FEPRO_SOLVER_LIB = fepro_solver$(SHLIB_EXT)
UFEM_BROWSER_LIB = ufem_browser$(SHLIB_EXT)
FEPRO_GL_VIEW_EXE = fepro_gl_view$(EXE_EXT)

all: $(FEM_SOLVER_LIB) $(FEPRO_SOLVER_LIB) $(FEPRO_GL_VIEW_EXE)

# Target to generate GL forwarding headers for macOS
.macos_inc/GL/glut.h:
	@mkdir -p .macos_inc/GL
	@echo '#include <GLUT/glut.h>' > .macos_inc/GL/glut.h
	@echo '#include <OpenGL/gl.h>' >> .macos_inc/GL/glut.h
	@echo '#include <OpenGL/glu.h>' >> .macos_inc/GL/glu.h
	@echo '#include <OpenGL/gl.h>' > .macos_inc/GL/gl.h
	@echo '#include <OpenGL/glu.h>' > .macos_inc/GL/glu.h

# Explicit macOS target
macos:
	$(MAKE) SYS_TYPE=DARWIN MACOS_TCL_DIR=$(MACOS_TCL_DIR) all

darwin: macos

# Explicit SGI / IRIX target
sgi:
	$(MAKE) -f Makefile.sgi all

irix: sgi

# Explicit Windows / MSYS2 targets
windows:
	$(MAKE) SYS_TYPE=WINDOWS fem_solver.dll fepro_solver.dll

msys2: windows
win-msys2: windows
win-ucrt64: windows
win-mingw64: windows

doc: THEORY_MANUAL.pdf USER_GUIDE.pdf
.SUFFIXES: .tex .dvi .pdf

$(FEM_SOLVER_LIB): fem_c_solver_v2.c
	$(CC) $(CFLAGS) $(TCL_INCLUDES) $(FEM_SHLIB_FLAGS) -o $@ fem_c_solver_v2.c $(TCL_LIB) $(LIBS)

$(FEPRO_SOLVER_LIB): fepro_c_solver.c
ifeq ($(SYS_TYPE),DARWIN)
	$(CC) $(FEPRO_SOLVER_CFLAGS) $(TCL_INCLUDES) $(FEPRO_SHLIB_FLAGS) -o $@ fepro_c_solver.c fepro_macos_gl.m $(TCL_LIB) $(LIBS) $(OPENGL_LIBS)
else
	$(CC) $(FEPRO_SOLVER_CFLAGS) $(TCL_INCLUDES) $(FEPRO_SHLIB_FLAGS) -o $@ fepro_c_solver.c $(TCL_LIB) $(LIBS)
endif

$(FEPRO_GL_VIEW_EXE): fepro_gl_view.c $(MACOS_INC_DEP)
	$(CC) $(CFLAGS) $(TCL_INCLUDES) $(MACOS_GL_INC) -o $@ fepro_gl_view.c $(LIBS) $(OPENGL_LIBS) -lm

$(UFEM_BROWSER_LIB): ufem_browser.c
	$(CC) $(CFLAGS) $(TCL_INCLUDES) -I../ufem/fdb -I../ufem/cint -I../ufem/fem -I../ufem/common $(SHLIB_FLAGS) -o $@ ufem_browser.c ../ufem/fdb/libfdb.a ../ufem/cint/libcint.a ../ufem/meval/libmeval.a ../ufem/common/libfem_comm.a $(TCL_LIB) $(DL_LIB) $(LIBS) -lm

.tex.dvi:
	latex $<
	latex $<

.dvi.pdf:
	dvipdfm $<

clean:
	rm -rf fem_solver.so fem_solver.dll fem_solver32.dll fem_solver.dylib fepro_solver.so fepro_solver.dll fepro_solver32.dll fepro_solver.dylib ufem_browser.so ufem_browser.dll ufem_browser.dylib fepro_gl_view fepro_gl_view.exe U*.pdf T*.pdf P*.pdf *.log *.aux *.toc *.out *.dvi core .macos_inc .build_compat
