all: install
.PHONY: .
.SECONDARY:
.SUFFIXES:
	MAKEFLAGS += -r
.SHELLFLAGS += -e

#
##  environment
###
CABAL_SANDBOX:=.cabal-sandbox
GHC_PKG:=ghc-pkg
GHC_PROF_CATEGORIES:=hc hm hd hy hr hb
GHC_PROF_CPUS:=
GHC_PROF_PS_WIDTH:=11in
GHC_PROF_RATE:=0.1
GHC_PROF_CC_LENGTH:=50
HCOMPTA_CLI_PROF:=$(CABAL_SANDBOX)/bin/hcompta-prof
HCOMPTA_COMMANDS:=balance gl journal
HCOMPTA_PACKAGES:=lib jcc ledger cli web
HCOMPTA_IN_FORMATS:=jcc ledger
commit:=$(shell if which git >/dev/null; then git describe --long; else echo COMMIT; fi)

#
##  helpers
###
if_arg=$(if $2,$1 $2)
rmw=$(call if_arg,rm,$(wildcard $1))
rmdirw=$(call if_arg,rmdir -p --ignore-fail-on-non-empty,$(wildcard $1))

#
##  install
###
install: cabal/install $(HCOMPTA_PACKAGES:=/install)
cabal/install:
	cabal $(CABAL_FLAGS) update $(CABAL_UPDATE_FLAGS)
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) cabal
.PHONY: $(HCOMPTA_PACKAGES)
lib lib/install: \
 cli/unregister \
 web/unregister \
 ledger/unregister \
 jcc/unregister \
 cli/unregister/sandbox \
 web/unregister/sandbox \
 ledger/unregister/sandbox \
 jcc/unregister/sandbox
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) ./lib
jcc jcc/install: \
 cli/unregister \
 web/unregister \
 cli/unregister/sandbox \
 web/unregister/sandbox
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) ./jcc
ledger ledger/install: \
 cli/unregister \
 web/unregister \
 cli/unregister/sandbox \
 web/unregister/sandbox
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) ./ledger
cli cli/install:
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) ./cli
web web/install:
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) alex happy
	cabal $(CABAL_FLAGS) install -v $(CABAL_INSTALL_FLAGS) ./web

%/recomp: CABAL_INSTALL_FLAGS+=--ghc-options -fforce-recomp
%/recomp: %
	

#
##  clean
###
clean: lib/clean $(HCOMPTA_PACKAGES:=/clean)
lib/clean:
	(cd lib && cabal clean)
jcc/clean:
	(cd jcc && cabal clean)
ledger/clean:
	(cd ledger && cabal clean)
cli/clean:
	(cd cli && cabal clean)
web/clean:
	(cd web && cabal clean)

#
##  test
###
test: $(HCOMPTA_PACKAGES:=/test)
lib/test:
	(cd lib && cabal $(CABAL_FLAGS) test --show-details=always $(CABAL_TEST_FLAGS))
jcc/test:
	(cd jcc && cabal $(CABAL_FLAGS) test --show-details=always $(CABAL_TEST_FLAGS))
ledger/test:
	(cd ledger && cabal $(CABAL_FLAGS) test --show-details=always $(CABAL_TEST_FLAGS))
cli/test:
	(cd cli && cabal $(CABAL_FLAGS) test --show-details=always $(CABAL_TEST_FLAGS))
web/test:
	(cd web && cabal $(CABAL_FLAGS) test --show-details=always $(CABAL_TEST_FLAGS))
%/install/test: CABAL_INSTALL_FLAGS+=--enable-tests
%/install/test: %/install
	

#
##  doc
###
.PHONY: doc
doc: doc/xhtml $(HCOMPTA_PACKAGES:=/doc)

lib/doc:
	(cd lib && \
	cabal $(CABAL_FLAGS) configure $(CABAL_CONFIGURE_FLAGS) && \
	cabal $(CABAL_FLAGS) haddock --hyperlink-source $(CABAL_HADDOCK_FLAGS))
jcc/doc:
	(cd jcc && \
	cabal $(CABAL_FLAGS) configure $(CABAL_CONFIGURE_FLAGS) && \
	cabal $(CABAL_FLAGS) haddock --hyperlink-source $(CABAL_HADDOCK_FLAGS))
ledger/doc:
	(cd ledger && \
	cabal $(CABAL_FLAGS) configure $(CABAL_CONFIGURE_FLAGS) && \
	cabal $(CABAL_FLAGS) haddock --hyperlink-source $(CABAL_HADDOCK_FLAGS))
cli/doc:
	(cd cli && \
	cabal $(CABAL_FLAGS) configure $(CABAL_CONFIGURE_FLAGS) && \
	cabal $(CABAL_FLAGS) haddock --hyperlink-source $(CABAL_HADDOCK_FLAGS))
web/doc:
	(cd web && \
	cabal $(CABAL_FLAGS) configure $(CABAL_CONFIGURE_FLAGS) && \
	cabal $(CABAL_FLAGS) haddock --hyperlink-source $(CABAL_HADDOCK_FLAGS))
doc/%: .
	$(MAKE) -C doc $*

#
##  dev
###
%/dev: CABAL_INSTALL_FLAGS+=-fdev
%/dev: %
	

#
##  dump
###
%/dump: CABAL_INSTALL_FLAGS+=-fdump
%/dump: %
	

#
##  hlint
###
hlint: $(HCOMPTA_PACKAGES:=/hlint.html)
%/hlint: %/hlint.html
	
%/hlint.html: .
	if hlint \
	 -i 'Redundant $$' \
	 -i 'Redundant bracket' \
	 -i 'Redundant do' \
	 -i 'Redundant lambda' \
	 -i "Use camelCase" \
	 -i 'Use if' \
	 -i 'Use String' \
	 -i 'Use string literal' \
	 --quiet --report="$@" \
	 "$*"/Hcompta; \
	then rm -f "$@"; \
	else echo; echo "BROWSE REPORT AT: file://$(abspath $@)"; fi

#
##  prof
###
.PHONY: prof
prof: $(addprefix prof/,$(HCOMPTA_COMMANDS))

prof/commit/$(commit):
	mkdir -p "$@"

lib/install/prof: CABAL_INSTALL_FLAGS+=-fprof --enable-library-profiling
lib/install/prof: cli/unregister/sandbox lib/install | $(CABAL_SANDBOX)
	

jcc/install/prof: CABAL_INSTALL_FLAGS+=-fprof --enable-library-profiling
jcc/install/prof: cli/unregister/sandbox web/unregister/sandbox jcc/install | $(CABAL_SANDBOX)
	

ledger/install/prof: CABAL_INSTALL_FLAGS+=-fprof --enable-library-profiling
ledger/install/prof: cli/unregister/sandbox web/unregister/sandbox ledger/install | $(CABAL_SANDBOX)
	

cli/install/prof: CABAL_INSTALL_FLAGS+=-fprof --enable-library-profiling --enable-executable-profiling
cli/install/prof: cli/install | $(CABAL_SANDBOX)
	mv \
	 $(CABAL_SANDBOX)/bin/hcompta \
	 $(HCOMPTA_CLI_PROF)

define prof/command
prof/clean: prof/$(command)/clean

endef

define prof/in
prof/%.$(in)/clean: \
 $(foreach command,$(HCOMPTA_COMMANDS), \
  $(foreach journal,$(HCOMPTA_IN_FORMATS), \
  prof/%.$(in)/$(command)/clean ))
	

endef

define prof/command/in

prof/%.$(in)/$(command)/clean: \
 $(foreach hC,$(GHC_PROF_CATEGORIES), \
 prof/%.$(in)/$(command)/$(hC)/clean \
 )
	$$(call rmw, \
	 prof/$$*.$(in).$(command) \
	 )

endef

define prof/command/hC
prof/$(command):                      prof/$(command)/$(hC)
prof/$(command)/clean:                prof/$(command)/$(hC)/clean
prof/$(command)/$(hC): \
 $(addsuffix /$(command)/$(hC),$(wildcard prof/*.$(in)))
prof/$(command)/$(hC)/clean:
	$$(call rmw, \
	 prof/commit/$$(commit)/*.$(in).$(command).$(hC).aux \
	 prof/commit/$$(commit)/*.$(in).$(command).$(hC).hp \
	 prof/commit/$$(commit)/*.$(in).$(command).$(hC).prof \
	 prof/commit/$$(commit)/*.$(in).$(command).$(hC).ps \
	 prof/commit/$$(commit)/*.$(in).$(command).$(hC).stats \
	 )

endef

define prof/command/in/hC
prof/%.$(in)/$(command):       prof/%.$(in).$(command)/$(hC)
prof/%.$(in)/$(command)/$(hC): prof/commit/$$(commit)/%.$(in).$(command).$(hC).ps
	

prof/%.$(in).$(command): \
 prof/commit/$$(commit)/%.$(in).$(command).$(hC).hs

prof/commit/$$(commit)/%.$(in).$(command).$(hC).hp \
prof/%.$(in).$(command): \
 $$(HCOMPTA_CLI_PROF) \
 prof/%.$(in) \
 | prof/commit/$$(commit)
	GHCRTS=' \
	 -$(hC)$$(GHC_PROF_$(hC)) \
	 -i$$(GHC_PROF_RATE) \
	 -L$$(GHC_PROF_CC_LENGTH) \
	 -N$$(GHC_PROF_CPUS) \
	 -tprof/commit/$(commit)/$$*.$(in).$(command).$(hC).stats \
	 -p \
	 $$(GHCRTS)' \
	$$(HCOMPTA_CLI_PROF) $$(HCOMPTA_FLAGS) \
	 $(command) $$(HCOMPTA_COMMAND_FLAGS) $$(filter %.$(in),$$^) \
	 >prof/$$*.$(in).$(command)
	mv $(notdir $(HCOMPTA_CLI_PROF)).hp   prof/commit/$(commit)/$$*.$(in).$(command).$(hC).hp
	mv $(notdir $(HCOMPTA_CLI_PROF)).prof prof/commit/$(commit)/$$*.$(in).$(command).$(hC).prof

prof/%.$(in)/$(command)/$(hC)/clean:
	$$(call rmw, \
	 prof/commit/$$(commit)/$$*.$(in).$(command).$(hC).aux \
	 prof/commit/$$(commit)/$$*.$(in).$(command).$(hC).hp \
	 prof/commit/$$(commit)/$$*.$(in).$(command).$(hC).prof \
	 prof/commit/$$(commit)/$$*.$(in).$(command).$(hC).ps \
	 prof/commit/$$(commit)/$$*.$(in).$(command).$(hC).stats \
	 )

endef

$(foreach in,$(HCOMPTA_IN_FORMATS), \
 $(eval $(call prof/in)) )
$(foreach command,$(HCOMPTA_COMMANDS), \
 $(eval $(call prof/command)) \
 $(foreach hC,$(GHC_PROF_CATEGORIES), \
  $(eval $(call prof/command/hC)) ) \
 $(foreach in,$(HCOMPTA_IN_FORMATS), \
  $(eval $(call prof/command/in)) \
  $(foreach hC,$(GHC_PROF_CATEGORIES), \
   $(eval $(call prof/command/in/hC)) )))

%.hC.hp: $(foreach hC,$(GHC_PROF_CATEGORIES),%.$(hC).hp)
	
%.hC.ps: $(foreach hC,$(GHC_PROF_CATEGORIES),%.$(hC).ps)
	
%.ps: %.hp
	(cd $(@D) && hp2ps -b -c -e$(GHC_PROF_PS_WIDTH) -g $(notdir $*.hp))

#
##  not-threaded
###
%/not-threaded: CABAL_INSTALL_FLAGS+=-f-threaded
%/not-threaded: %
	

#
##  ghc-pkg
###
unregister: $(HCOMPTA_PACKAGES:=/unregister)

%/unregister: .
	if    $(GHC_PKG) list       hcompta-$* | grep -q '^ * hcompta-$*-' ; \
	 then $(GHC_PKG) unregister hcompta-$* ; \
	 fi

%/unregister/sandbox: GHC_PKG:=cabal sandbox hc-pkg
%/unregister/sandbox: .
	if    $(GHC_PKG) list       hcompta-$* | grep -q '^ * hcompta-$*-' ; \
	 then $(GHC_PKG) unregister hcompta-$* ; \
	 fi

#
##  sandbox
###
$(CABAL_SANDBOX):
	cabal $(CABAL_FLAGS) sandbox --sandbox="$@" $(CABAL_SANDBOX_FLAGS) init

%/sandbox: GHC_PKG:=cabal sandbox hc-pkg
%/sandbox: %
	

#
##  stats
###
.PHONY: stats
stats:
	gitstats . $@