# 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.

# DVX Shell Applications Makefile  -- builds DXE3 modules
#
# Source tree is now one dir per app, mirroring bin/apps/kpunch/.

include ../../common.mk

APP_INCLUDES  = -I../../libs/kpunch -I../../libs/kpunch/libdvx -I../../libs/kpunch/libdvx/platform -I../../libs/kpunch/libdvx/thirdparty -I../../widgets/kpunch -I../../libs/kpunch/libtasks -I../../libs/kpunch/dvxshell
CFLAGS        = $(DOS_CFLAGS) $(APP_INCLUDES)

OBJDIR  = ../../../obj/apps
BINROOT = ../../../bin
BINDIR  = $(BINROOT)/apps
DVXRES = ../../../bin/host/dvxres

# C apps are discovered, never listed: every directory <app>/ holding
# <app>/<app>.c is one app.  All .c files in that directory are linked into
# bin/apps/kpunch/<app>/<app>.app, and <app>/<app>.res (when present) is
# appended by dvxres with every .bmp in the directory as a dependency.
C_APP_MAINS = $(wildcard */*.c)
C_APPS      = $(sort $(foreach f,$(C_APP_MAINS),$(if $(filter $(notdir $(basename $(f))),$(patsubst %/,%,$(dir $(f)))),$(patsubst %/,%,$(dir $(f))))))

BASCOMP   = ../../../bin/host/bascomp

# BASIC apps: each is a .dbp project.  An entry is the project's directory,
# or dir:out when the program goes into another program's folder (the Help
# Editor, dvxhelp/helpedit, installs beside the Help Viewer in dvxhelp).
# The program is bin/apps/kpunch/<out>/<name>.app, <name> being the last
# part of the directory.
BASIC_APPS = iconed notepad imgview dvxhelp/helpedit:dvxhelp resedit basdemo widshow clock welcome fileMgr terminal

basicDir  = $(firstword $(subst :, ,$(1)))
basicName = $(notdir $(call basicDir,$(1)))
basicOut  = $(or $(word 2,$(subst :, ,$(1))),$(call basicName,$(1)))
basicApp  = $(BINDIR)/kpunch/$(call basicOut,$(1))/$(call basicName,$(1)).app

# Everything a project is built from: the files in its directory and the
# modules its .dbp names (include libraries elsewhere).
basicDeps = $(wildcard $(1)/*.dbp $(1)/*.frm $(1)/*.bas $(1)/*.cls $(1)/*.BMP) \
	$(addprefix $(1)/,$(shell sed -n 's/^File[0-9]* *= *\(.*\.bas\)\r*$$/\1/p' $(1)/$(notdir $(1)).dbp))

BASIC_TARGETS = $(foreach a,$(BASIC_APPS),$(call basicName,$(a)))
BASIC_OUTS    = $(foreach a,$(BASIC_APPS),$(call basicApp,$(a)))

.PHONY: all clean $(C_APPS) dvxbasic $(BASIC_TARGETS)

all: $(C_APPS) dvxbasic $(BASIC_TARGETS)

dvxbasic:
	$(MAKE) -C dvxbasic

# bascomp is produced by the dvxbasic sub-make; this rule gives the BASIC app
# rules a real target to depend on so parallel builds order correctly.
$(BASCOMP): | dvxbasic
	@:

# Per-app sources, objects and resource inputs.
appSrcs = $(wildcard $(1)/*.c)
appObjs = $(patsubst $(1)/%.c,$(OBJDIR)/$(1)/%.o,$(call appSrcs,$(1)))
appRes  = $(wildcard $(1)/$(1).res)
appDeps = $(call appRes,$(1)) $(if $(call appRes,$(1)),$(wildcard $(1)/*.bmp))

# Data files a program installs beside itself, C or BASIC alike:
# APP_DATA_<name> lists them (<name> being the last part of the program's
# source directory, the files relative to it); they are copied into the
# program's folder under bin/apps/kpunch.
APP_DATA_dvxdemo = logo.bmp new.bmp open.bmp sample.bmp save.bmp

appDataOut = $(addprefix $(BINDIR)/kpunch/$(2)/,$(APP_DATA_$(notdir $(1))))

# $(1) = source directory, $(2) = output folder under bin/apps/kpunch,
# $(3) = the program's make target.
define APP_DATA_RULES
$(3): $(call appDataOut,$(1),$(2))

$(call appDataOut,$(1),$(2)): $(BINDIR)/kpunch/$(2)/%: $(1)/%
	@mkdir -p $$(dir $$@)
	cp $$< $$@
endef

APP_DATA_OUTS = $(foreach a,$(C_APPS),$(call appDataOut,$(a),$(a))) $(foreach a,$(BASIC_APPS),$(call appDataOut,$(call basicDir,$(a)),$(call basicOut,$(a))))

# $(1) = app directory name.
define C_APP_RULES
$(1): $(BINDIR)/kpunch/$(1)/$(1).app

$(BINDIR)/kpunch/$(1)/$(1).app: $(call appObjs,$(1)) $(call appDeps,$(1))
	@mkdir -p $$(dir $$@)
	$$(DXE3GEN) -o $$@ -U $(call appObjs,$(1))
	$(if $(call appRes,$(1)),cd $(1) && ../$$(DVXRES) build ../$$@ $(1).res)

$(OBJDIR)/$(1)/%.o: $(1)/%.c $$(DVX_MAKEFILES)
	@mkdir -p $$(dir $$@)
	$$(CC) $$(CFLAGS) -c -o $$@ $$<
endef

$(foreach a,$(C_APPS),$(eval $(call C_APP_RULES,$(a))))
$(foreach a,$(C_APPS),$(if $(APP_DATA_$(a)),$(eval $(call APP_DATA_RULES,$(a),$(a),$(a)))))

C_APP_OBJS = $(foreach a,$(C_APPS),$(call appObjs,$(a)))

# BASIC apps (compiled from .dbp projects via bascomp), one rule set per
# BASIC_APPS entry.
#
# F1 needs no resource: the shell presets an app's help file to <name>.hlp
# beside the .app (compiled there from <dir>/<name>.dhs by compile-help).

# $(1) = BASIC_APPS entry.
define BASIC_APP_RULES
$(call basicName,$(1)): $(call basicApp,$(1))

$(call basicApp,$(1)): $(call basicDeps,$(call basicDir,$(1))) $$(BASCOMP) | dvxbasic
	@mkdir -p $$(dir $$@)
	$$(BASCOMP) $(call basicDir,$(1))/$(call basicName,$(1)).dbp -o $$@ -release
endef

$(foreach a,$(BASIC_APPS),$(eval $(call BASIC_APP_RULES,$(a))))
$(foreach a,$(BASIC_APPS),$(if $(APP_DATA_$(call basicName,$(a))),$(eval $(call APP_DATA_RULES,$(call basicDir,$(a)),$(call basicOut,$(a)),$(call basicName,$(a))))))

# Native host build (test harness): each C app becomes a plain ELF shared
# object under obj/host/apps/<name>.so with its resources appended by
# dvxres exactly as on DOS (the resource footer trails the ELF image, which
# the dynamic loader ignores).  SAN/COV per common.mk.
HOSTOBJDIR    = $(HOST_OBJROOT)/apps
HOSTCFLAGS    = $(HOST_CFLAGS) $(APP_INCLUDES)
HOSTLDFLAGS   = -shared $(HOST_LDFLAGS) $(HOST_APP_LDFLAGS)
HOST_SOS      = $(foreach n,$(C_APPS),$(HOSTOBJDIR)/$(n).so)

appHostObjs = $(patsubst $(1)/%.c,$(HOSTOBJDIR)/$(1)/%.o,$(call appSrcs,$(1)))

# $(1) = app directory name.
define C_APP_HOST_RULES
$(HOSTOBJDIR)/$(1).so: $(call appHostObjs,$(1)) $(call appDeps,$(1))
	$$(HOSTCC) $$(HOSTLDFLAGS) -o $$@ $(call appHostObjs,$(1))
	$(if $(call appRes,$(1)),cd $(1) && ../$$(DVXRES) build ../$$@ $(1).res)

$(HOSTOBJDIR)/$(1)/%.o: $(1)/%.c $$(DVX_MAKEFILES)
	@mkdir -p $$(dir $$@)
	$$(HOSTCC) $$(HOSTCFLAGS) -c -o $$@ $$<
endef

$(foreach a,$(C_APPS),$(eval $(call C_APP_HOST_RULES,$(a))))

HOST_APP_OBJS = $(foreach a,$(C_APPS),$(call appHostObjs,$(a)))

.PHONY: host host-clean

host: $(HOST_SOS)

host-clean:
	rm -rf $(HOSTOBJDIR)


-include $(C_APP_OBJS:.o=.d) $(HOST_APP_OBJS:.o=.d)

clean:
	rm -f $(C_APP_OBJS) $(C_APP_OBJS:.o=.d)
	rm -f $(foreach a,$(C_APPS),$(BINDIR)/kpunch/$(a)/$(a).app)
	rm -f $(APP_DATA_OUTS)
	rm -f $(BASIC_OUTS)
	$(MAKE) -C dvxbasic clean
