# The MIT License (MIT)
#
# Copyright (C) 2026 Scott Duensing
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

# The DVX installer.
#
#   bin/setup.exe     SETUP.EXE: one static DOS program -- the DVX core,
#                     the widgets Setup uses, fileops, miniz's inflate, the
#                     Setup program, its fonts (setupFonts.ini), and its
#                     start page's icons (mkicon) --
#                     linked with --gc-sections so only what Setup reaches
#                     is in it, then packed with UPX (it unpacks itself in
#                     memory when it starts).  Also shipped in the package
#                     (the installed copy uninstalls).
#   bin/host/dvxpkg   the package tool `make dist` runs (src/installer/
#                     mkDist.sh).
#
# The core sources are taken as they are (every libdvx/*.c and the DOS
# platform files, into an archive so only the objects used are linked);
# the widgets are compiled with their wgtRegister renamed to
# wgtRegister<Name>, which setup.c calls.

include ../common.mk

LIBDVX     = ../libs/kpunch/libdvx
KPUNCH     = ../libs/kpunch
WIDGETS    = ../widgets/kpunch
PKGLIB     = $(KPUNCH)/pkg
MINIZ      = $(PKGLIB)/thirdparty/miniz
MONO       = $(PKGLIB)/thirdparty/monocypher/src
LICENSE    = ../../LICENSE.txt

OBJDIR     = ../../obj/installer
DOSOBJ     = $(OBJDIR)/dos
HOSTOBJ    = $(OBJDIR)/host
BINDIR     = ../../bin
HOSTBIN    = ../../bin/host
TARGET     = $(BINDIR)/setup.exe
TOOL       = $(HOSTBIN)/dvxpkg
LICENSE_H  = $(OBJDIR)/setupLicense.h
FONTS_H    = $(OBJDIR)/setupFonts.h
FONTS_INI  = setupFonts.ini
FONTS_DIR  = $(OBJDIR)/fonts
MKFONT     = $(HOSTBIN)/mkfont
ICONS_H    = $(OBJDIR)/setupIcons.h
ICONS_DIR  = $(OBJDIR)/icons
MKICON     = $(HOSTBIN)/mkicon
# The start page's icons: mkicon types, each sIcon<Type> in setupIcons.h
SETUP_ICONS = install upgrade remove
# NRV2E: about half the size, and it unpacks in a fraction of a second on
# a 486 (LZMA saves 15 KB more but unpacks several times slower).  UPX
# keeps the CWSDPMI stub.
UPX_FLAGS  = -qq --best --nrv2e

INCLUDES   = -I. -I$(PKGLIB) -I$(MINIZ) -I$(OBJDIR) -I$(LIBDVX) -I$(LIBDVX)/platform -I$(LIBDVX)/thirdparty -I$(KPUNCH) -I$(KPUNCH)/libtasks -I$(WIDGETS)
MINIZ_DOS  = $(PKG_MINIZ_FLAGS) -DMINIZ_NO_DEFLATE_APIS
CFLAGS     = $(DOS_CFLAGS) -ffunction-sections -fdata-sections $(INCLUDES) $(MINIZ_DOS)
LDFLAGS    = -s -Wl,--gc-sections -lm

# Setup's own sources; the core, fileops, and the text and list helpers
# as they are
SETUP_SRCS = setup.c setupCore.c pkgRead.c $(PKGLIB)/pkgDb.c $(PKGLIB)/pkgFormat.c $(PKGLIB)/pkgIni.c $(PKGLIB)/pkgManifest.c $(PKGLIB)/pkgZip.c $(MINIZ)/miniz.c
CORE_SRCS  = $(wildcard $(LIBDVX)/*.c) $(LIBDVX)/platform/dvxPlatformDos.c $(LIBDVX)/platform/dvxPlatformIrq.c $(LIBDVX)/platform/dvxPlatformUtil.c $(LIBDVX)/platform/dvxMemTrack.c $(LIBDVX)/thirdparty/stb_ds_impl.c ../tools/dvxResWrite.c $(wildcard $(KPUNCH)/fileops/*.c) $(KPUNCH)/texthelp/textHelp.c $(KPUNCH)/listhelp/listHelp.c

# The widgets Setup uses: <folder>/<source>:<Name> (wgtRegister -> wgtRegister<Name>);
# the list box and the dropdown are the folder dialog's
SETUP_WGTS = box/widgetBox:Box button/widgetButton:Button checkbox/widgetCheckbox:Checkbox dropdown/widgetDropdown:Dropdown imageButton/widgetImageButton:ImageButton label/widgetLabel:Label listBox/widgetListBox:ListBox progressBar/widgetProgressBar:Progress radio/widgetRadio:Radio spacer/widgetSpacer:Spacer textInput/widgetTextInput:TextInput

SETUP_OBJS = $(patsubst %.c,$(DOSOBJ)/%.o,$(notdir $(SETUP_SRCS)))
CORE_OBJS  = $(patsubst %.c,$(DOSOBJ)/core/%.o,$(notdir $(CORE_SRCS)))
WGT_OBJS   = $(foreach w,$(SETUP_WGTS),$(DOSOBJ)/wgt/$(notdir $(firstword $(subst :, ,$w))).o)
CORE_LIB   = $(DOSOBJ)/setupCore.a

# The package tool (host)
TOOL_SRCS  = pkgTool.c pkgBuild.c $(PKGLIB)/pkgFormat.c $(PKGLIB)/pkgCli.c $(PKGLIB)/pkgDb.c $(PKGLIB)/pkgDpk.c $(PKGLIB)/pkgIni.c $(PKGLIB)/pkgManifest.c $(PKGLIB)/pkgOp.c $(PKGLIB)/pkgPlan.c $(PKGLIB)/pkgSign.c $(PKGLIB)/pkgTrust.c $(PKGLIB)/pkgZip.c $(PKGLIB)/pkgZipWrite.c $(MINIZ)/miniz.c $(MONO)/monocypher.c $(MONO)/optional/monocypher-ed25519.c $(KPUNCH)/serial/security/secHash.c $(KPUNCH)/serial/security/security.c $(LIBDVX)/platform/dvxPlatformUtil.c $(LIBDVX)/thirdparty/stb_ds_impl.c
TOOL_OBJS  = $(patsubst %.c,$(HOSTOBJ)/%.o,$(notdir $(TOOL_SRCS)))
TOOL_FLAGS = $(HOST_TOOL_CFLAGS) -I. -I$(PKGLIB) -I$(MINIZ) -I$(MONO) -I$(KPUNCH) -I$(LIBDVX) -I$(LIBDVX)/platform -I$(LIBDVX)/thirdparty

vpath %.c . $(PKGLIB) $(MINIZ) $(MONO) $(MONO)/optional $(KPUNCH)/serial/security $(LIBDVX)/platform $(LIBDVX)/thirdparty

.PHONY: all clean

# A recipe that fails part way (UPX, after the stub is prepended) leaves
# no target behind to pass for a finished one
.DELETE_ON_ERROR:

all: $(TARGET) $(TOOL)

$(TARGET): $(SETUP_OBJS) $(CORE_LIB) | $(BINDIR)
	$(CC) -o $@ $(SETUP_OBJS) $(CORE_LIB) $(LDFLAGS)
	$(EXE2COFF) $@
	cat $(CWSDSTUB) $(BINDIR)/setup > $@
	rm -f $(BINDIR)/setup
	$(UPX) $(UPX_FLAGS) $@

$(CORE_LIB): $(CORE_OBJS) $(WGT_OBJS)
	rm -f $@
	$(DJGPP_PREFIX)/bin/$(DJGPP_TRIPLE)-ar rcs $@ $^

$(DOSOBJ)/%.o: %.c $(DVX_MAKEFILES) | $(LICENSE_H) $(FONTS_H) $(ICONS_H)
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c -o $@ $<

define CORE_RULE
$(DOSOBJ)/core/$(notdir $(1:.c=.o)): $1 $$(DVX_MAKEFILES)
	@mkdir -p $$(dir $$@)
	$$(CC) $$(CFLAGS) -c -o $$@ $$<
endef

$(foreach s,$(CORE_SRCS),$(eval $(call CORE_RULE,$s)))

define WGT_RULE
$(DOSOBJ)/wgt/$(notdir $(firstword $(subst :, ,$1))).o: $(WIDGETS)/$(firstword $(subst :, ,$1)).c $$(DVX_MAKEFILES)
	@mkdir -p $$(dir $$@)
	$$(CC) $$(CFLAGS) -DwgtRegister=wgtRegister$(lastword $(subst :, ,$1)) -c -o $$@ $$<
endef

$(foreach w,$(SETUP_WGTS),$(eval $(call WGT_RULE,$w)))

# LICENSE.txt as a C string, in ASCII (the copyright sign becomes (C)),
# its paragraphs re-flowed to the width of Setup's text box.
LICENSE_COLS = 58

$(LICENSE_H): $(LICENSE) $(DVX_MAKEFILES)
	@mkdir -p $(dir $@)
	{ echo '// Generated from LICENSE.txt by src/installer/Makefile'; \
	  echo 'static const char sSetupLicense[] ='; \
	  tr -d '\r' < $< | iconv -f UTF-8 -t ASCII//TRANSLIT | fmt -w $(LICENSE_COLS) | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/    "/' -e 's/$$/\\n"/'; \
	  echo ';'; } > $@.tmp && mv $@.tmp $@

# The bytes of file $(1) as the lines of a C array (for the headers below)
BYTES_C = od -An -v -tx1 $(1) | sed -e 's/  */ /g' -e 's/^ //' -e 's/ $$//' -e 's/ /, 0x/g' -e 's/^/    0x/' -e 's/$$/,/'

# The fonts Setup carries (setupFonts.ini), made by mkfont and written as
# C arrays, one per .DFN, and the table setup.c reads (sSetupFonts, of
# SetupFontDataT: name, bytes, and length)
$(FONTS_H): $(FONTS_INI) $(MKFONT) $(FONT_SOURCES)/.installed $(DVX_MAKEFILES)
	rm -rf $(FONTS_DIR)
	$(MKFONT) $(FONTS_INI) $(FONT_SOURCES) $(FONTS_DIR)
	{ echo '// Generated from setupFonts.ini by src/installer/Makefile'; \
	  echo '#include <stdint.h>'; \
	  echo 'typedef struct { const char *name; const uint8_t *data; uint32_t length; } SetupFontDataT;'; \
	  for f in $(FONTS_DIR)/*.DFN; do \
	    n=$$(basename $$f .DFN); \
	    echo "static const uint8_t sFont$$n[] = {"; \
	    $(call BYTES_C,$$f); \
	    echo '};'; \
	  done; \
	  echo 'static const SetupFontDataT sSetupFonts[] = {'; \
	  for f in $(FONTS_DIR)/*.DFN; do \
	    n=$$(basename $$f .DFN); \
	    echo "    { \"$$n\", sFont$$n, (uint32_t)sizeof(sFont$$n) },"; \
	  done; \
	  echo '};'; } > $@.tmp && mv $@.tmp $@

# The start page's icons (SETUP_ICONS), made by mkicon and written as C
# arrays of their BMP files: sIconInstall and so on
$(ICONS_H): $(MKICON) $(DVX_MAKEFILES)
	rm -rf $(ICONS_DIR)
	mkdir -p $(ICONS_DIR)
	for t in $(SETUP_ICONS); do $(MKICON) $(ICONS_DIR)/$$t.bmp $$t > /dev/null || exit 1; done
	{ echo '// Generated by src/installer/Makefile from mkicon (SETUP_ICONS)'; \
	  echo '#include <stdint.h>'; \
	  for t in $(SETUP_ICONS); do \
	    echo "static const uint8_t sIcon$$(echo $$t | sed 's/^./\u&/')[] = {"; \
	    $(call BYTES_C,$(ICONS_DIR)/$$t.bmp); \
	    echo '};'; \
	  done; } > $@.tmp && mv $@.tmp $@

$(TOOL): $(TOOL_OBJS) | $(HOSTBIN)
	$(HOSTCC) -o $@ $(TOOL_OBJS)

$(HOSTOBJ)/%.o: %.c $(DVX_MAKEFILES)
	@mkdir -p $(dir $@)
	$(HOSTCC) $(TOOL_FLAGS) -c -o $@ $<

$(BINDIR) $(HOSTBIN):
	mkdir -p $@

-include $(SETUP_OBJS:.o=.d) $(CORE_OBJS:.o=.d) $(WGT_OBJS:.o=.d) $(TOOL_OBJS:.o=.d)

clean:
	rm -rf $(OBJDIR) $(TARGET) $(TOOL)
