#---*- Makefile -*-------------------------------------------------------

# Use "make schemas schemas_html_pretty=true" to apply OPTIMADE styling to the html pages

# Use "make schemas schemas_html_ext=true" to generate html files with .html extensions also for files meant to be served
# without extensions, which is useful for hosting, e.g., on github that automatically redirects URLs without extensions.

# Dependencies from optimade-property-tools
PROCESS_SCHEMAS=dependencies/submodules/optimade-property-tools/bin/process_schemas
EXT_SCHEMAS := $(filter-out dependencies/submodules/optimade-property-tools/external/json-schema/LICENSE, $(wildcard dependencies/submodules/optimade-property-tools/external/json-schema/*))

BASEDIR = schemas/src/defs/
BASEID = https://schemas.optimade.org/defs/

BASEDIR_META = schemas/src/meta/
BASEID_META = https://schemas.optimade.org/meta/

ifeq ($(origin schemas_html_pretty), undefined)
	OPTIMADE_HTML_HEADER ?=
	OPTIMADE_HTML_TOP ?=
else
	OPTIMADE_HTML_HEADER = <link rel="stylesheet" type="text/css" media="screen" href="https://www.optimade.org/assets/css/style.css" /><style>body {background: \#f2f2f2;} html {margin: 0 auto; max-width: 900px;}</style>
	OPTIMADE_HTML_TOP = <a href="https://www.optimade.org/"><img style="margin: 0.5em; float: left" src="https://avatars0.githubusercontent.com/u/23107754" width="10%" /></a><div style="width: 100%; clear: both"></div>
endif

ALL_SCHEMAS := $(wildcard schemas/src/*/*/*/*/*/*/*.yaml schemas/src/*/*/*/*/*/*.yaml schemas/src/*/*/*/*/*.yaml schemas/src/*/*/*/*.yaml schemas/src/*/*/*.yaml)

META_SCHEMAS := $(filter schemas/src/meta/%.yaml, $(ALL_SCHEMAS))
META_SCHEMAS_JSON := $(patsubst schemas/src/%.yaml,schemas/output/%.json,$(META_SCHEMAS))
META_SCHEMAS_ARGS := $(foreach schema,$(META_SCHEMAS_JSON),--schema $(schema))

DEFINITIONS := $(filter schemas/src/defs/%.yaml, $(ALL_SCHEMAS))
DEFINITIONS_JSON := $(patsubst schemas/src/%.yaml,schemas/output/%.json,$(DEFINITIONS))
DEFINITIONS_MD := $(patsubst schemas/src/%.yaml,schemas/output/%.md,$(DEFINITIONS))

OTHER_SCHEMAS := $(filter-out schemas/src/meta/%.yaml,$(filter-out schemas/src/defs/%,$(ALL_SCHEMAS)))
OTHER_SCHEMAS_JSON := $(patsubst schemas/src/%.yaml,schemas/output/%.json,$(OTHER_SCHEMAS))
OTHER_SCHEMAS_MD := $(patsubst schemas/src/%.yaml,schemas/output/%.md,$(OTHER_SCHEMAS))

ifeq ($(origin schemas_html_ext), undefined)
	DEFINITIONS_HTML := $(patsubst schemas/src/%.yaml,schemas/output/%,$(DEFINITIONS))
	DEFINITIONS_HTML_EXT =
else
	DEFINITIONS_HTML := $(patsubst schemas/src/%.yaml,schemas/output/%.html,$(DEFINITIONS))
	DEFINITIONS_HTML_EXT = .html
endif

EXT_SCHEMAS_ARGS := $(foreach schema,$(EXT_SCHEMAS),--schema $(schema))

DEF_INDEXES_HTML = schemas/output/defs/index.html
DEF_INDEXES_MD = schemas/output/defs/index.md
RELEASES_INDEXES_HTML = schemas/output/releases/latest/index.html
RELEASES_INDEXES_MD = schemas/output/releases/latest/index.md

OPTIMADE_VERSION := $(shell awk 'NR==2 && /OPTIMADE API specification/ { sub(/~develop/, "", $$NF); print $$NF; exit }' optimade.rst)

ifeq ($(OPTIMADE_VERSION),)
  OPTIMADE_VERSION_MINOR :=
  OPTIMADE_VERSION_SUBST :=
else
  OPTIMADE_VERSION_MINOR := "$(basename $(OPTIMADE_VERSION))"
  OPTIMADE_VERSION_SUBST := --sub '$$$${OPTIMADE_VERSION}' "$(OPTIMADE_VERSION)"
endif

.PHONY: submodule-optimade-property-tools

submodule-optimade-property-tools:
	@if [ ! -e "dependencies/submodules/optimade-property-tools/bin/process_schemas" ] ; then \
                echo "*************************************************************************************************************************"; \
		echo "ERROR: The optimade-property-tools submodule is required to build the OPTIMADE schemas. Please run the following command:"; \
		echo "git submodule update --init dependencies/submodules/optimade-property-tools"; \
                echo "*************************************************************************************************************************"; \
		false; \
	elif git submodule status dependencies/submodules/optimade-property-tools | egrep -q '^[-+]' ; then \
                echo "********************************************************************************************************"; \
		echo "NOTE: The optimade-property-tools submodule is not in a clean state, if this is unintentional, consider:"; \
		echo "git submodule update --init dependencies/submodules/optimade-property-tools"; \
                echo "********************************************************************************************************"; \
	fi

.PHONY: schemas schemas_meta schemas_json schemas_docs schemas_html schemas_symlinks schema_releases schemas_indexes_docs schemas_release_indexes_docs

schemas: submodule-optimade-property-tools schemas_build schemas_releases schemas_release_indexes_docs
schemas_build: schemas_symlinks schemas_meta schemas_defs_json schemas_defs_docs schemas_defs_html schemas_other_json schemas_indexes_docs
schemas_meta: $(META_SCHEMAS_JSON)
schemas_defs_json: $(DEFINITIONS_JSON) schemas_meta
schemas_defs_docs: $(DEFINITIONS_MD) schemas_meta
schemas_defs_html: $(DEFINITIONS_HTML) schemas_meta
schemas_other_json: $(OTHER_SCHEMAS_JSON) schemas_defs_json
schemas_indexes_docs: $(DEF_INDEXES_HTML) $(DEF_INDEXES_MD) schemas_meta
schemas_release_indexes_docs: $(RELEASES_INDEXES_HTML) $(RELEASES_INDEXES_MD) schemas_meta

# The 'schemas_symlinks' rule is run before schema builds to try to maintain a structure under '/output' that helps
# handling multiple parallel versions of schema definitions. Normally a build would go into a minor version directory (e.g., 'v1.2')
# since the source files have to be organized that way for versioned $$inherit to work. The 'schemas_symlinks' rule
# symlinks a full version directory (e.g., v1.2.0) to the corresponding minor version directory where the build then goes.
# The result is an 'output' that allows a straightforward:
#
#   rsync -a output/ /path/to/arhive/of/versions/
#
# to do the right thing, where previously generated historical versions remains maintained correctly under '/path/to/arhive/of/versions/'
#
# Note: output/defs is deliberatly not handled by this rule since updated property defintions with the same ids are meant to replace
# older versions in the /defs/<minor version> directories.

schemas_symlinks:
	mkdir -p schemas/output/; \
	cd schemas/output/; \
	for KIND in meta json-schema json-ld releases; do \
	  if [ ! -e "$$KIND" ]; then \
            mkdir -p "$$KIND" ;\
          fi ;\
	  if [ -n "$(OPTIMADE_VERSION)" ]; then \
            if [ ! -e "$$KIND/$(OPTIMADE_VERSION)" ]; then \
	      mkdir "$$KIND/$(OPTIMADE_VERSION)" ;\
            fi ;\
            if [ ! -e "$$KIND/$(OPTIMADE_VERSION_MINOR)" -o -h "$$KIND/$(OPTIMADE_VERSION_MINOR)" ]; then \
	      ln -nsf "$(OPTIMADE_VERSION)" "$$KIND/$(OPTIMADE_VERSION_MINOR)" ;\
	    fi ;\
            if [ ! -e "$$KIND/latest" -o -h "$$KIND/latest" ]; then \
	      ln -nsf "$(OPTIMADE_VERSION_MINOR)" "$$KIND/latest" ;\
	    fi ;\
	  fi \
	done

# The releases directory aggregates this releases versions of all property definitions and is thus
# how one finds the definition file that was part of a specific relase.
schemas_releases: schemas_build
	mkdir -p schemas/output/releases/latest
	cd schemas/output/defs; \
	find . -type f -exec cp --parents \{\} ../releases/latest \;

# Old version that keeps only the latest version of all definitions. We may want to go back to this in the future
# if these historical definition archives gets too large.
#schemas_releases: schemas_build
#	mkdir -p schemas/output/releases/latest
#	cd schemas/output/defs; \
#	for DIR in $$(ls -vrd v*); do \
#          ( cd "$$DIR"; \
#	    find . -type f -exec cp --parents \{\} ../../releases/latest \; ;\
#	  ) \
#        done

# Meta schemas need a separate rule since the other rules depend on the meta schemas for validation (and the meta schemas cannot depend on themselves)
$(META_SCHEMAS_JSON): schemas/output/meta/%.json: schemas/src/meta/%.yaml | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --remove-null $(OPTIMADE_VERSION_SUBST) --basedir "$(BASEDIR_META)" --baseid "$(BASEID_META)" $(EXT_SCHEMAS_ARGS) --output "$@" "$<"

$(DEFINITIONS_JSON) $(OTHER_SCHEMAS_JSON): schemas/output/%.json: schemas/src/%.yaml $(META_SCHEMAS_JSON) | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --remove-null $(OPTIMADE_VERSION_SUBST) --basedir "$(BASEDIR)" --baseid "$(BASEID)" $(META_SCHEMAS_ARGS) $(EXT_SCHEMAS_ARGS) --output "$@" "$<"

$(DEFINITIONS_MD): schemas/output/%.md: schemas/src/%.yaml $(META_SCHEMAS_JSON) | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --remove-null -f md $(OPTIMADE_VERSION_SUBST) --basedir "$(BASEDIR)" --baseid "$(BASEID)" --output "$@" "$<"

$(DEFINITIONS_HTML): schemas/output/%$(DEFINITIONS_HTML_EXT): schemas/src/%.yaml $(META_SCHEMAS_JSON) | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --remove-null -f html $(OPTIMADE_VERSION_SUBST) --basedir "$(BASEDIR)" --baseid "$(BASEID)" --html-header '$(OPTIMADE_HTML_HEADER)' --html-top '$(OPTIMADE_HTML_TOP)' --output "$@" "$<"

$(DEF_INDEXES_MD): schemas/output/%/index.md: schemas/src/% $(META_SCHEMAS_JSON) | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --index --basedir "$(BASEDIR)" --baseid "$(BASEID)" -f md $(EXT_SCHEMAS_ARGS) --output "$@" "$<"

$(RELEASES_INDEXES_MD): schemas/output/%/index.md: schemas/output/% $(META_SCHEMAS_JSON) | schemas_symlinks schemas_releases
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --index --basedir "$(BASEDIR)" --baseid "$(BASEID)" -f md $(EXT_SCHEMAS_ARGS) --output "$@" "$<"

$(DEF_INDEXES_HTML): schemas/output/%/index.html: schemas/src/% $(META_SCHEMAS_JSON) | schemas_symlinks
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --index --basedir "$(BASEDIR)" --baseid "$(BASEID)" -f html --html-header '$(OPTIMADE_HTML_HEADER)' --html-top '$(OPTIMADE_HTML_TOP)' $(EXT_SCHEMAS_ARGS) --output "$@" "$<"

$(RELEASES_INDEXES_HTML): schemas/output/%/index.html: schemas/output/% $(META_SCHEMAS_JSON) | schemas_symlinks schemas_releases
	mkdir -p "$(dir $@)"
	$(PROCESS_SCHEMAS) --index --basedir "$(BASEDIR)" --baseid "$(BASEID)" -f html --html-header '$(OPTIMADE_HTML_HEADER)' --html-top '$(OPTIMADE_HTML_TOP)' $(EXT_SCHEMAS_ARGS) --output "$@" "$<"


.PHONY: clean clean_schemas

clean: clean_schemas

clean_schemas:
	rm -rf schemas/output

.PHONY: validate_schemas

validate_meta_schemas: schemas
	tests/scripts/validate_json_schema.py schemas/output/meta/latest/optimade/property_definition.json dependencies/submodules/optimade-property-tools/external/json-schema/schema
	tests/scripts/validate_json_schema.py schemas/output/meta/latest/optimade/physical_unit_definition.json dependencies/submodules/optimade-property-tools/external/json-schema/schema

validate_schemas: schemas validate_meta_schemas
	tests/scripts/validate_json_schema.py schemas/tests/example-structures.optimade schemas/output/json-schema/latest/optimade.json

.PHONY: check_schemas_variables

schemas_check_variables:
	@echo "DEFINITIONS = $(DEFINITIONS)"
	@echo "DEFINITIONS_JSON = $(DEFINITIONS_JSON)"
	@echo "DEFINITIONS_HTML = $(DEFINITIONS_HTML)"
	@echo ""
	@echo "OTHER_SCHEMAS = $(OTHER_SCHEMAS)"
	@echo "OTHER_SCHEMAS_JSON = $(OTHER_SCHEMAS_JSON)"
	@echo ""
	@echo "META_SCHEMAS = $(META_SCHEMAS)"
	@echo "META_SCHEMAS_JSON = $(META_SCHEMAS_JSON)"
	@echo "META_SCHEMAS_ARGS = $(META_SCHEMAS_ARGS)"
	@echo ""
	@echo "OPTIMADE_VERSION = $(OPTIMADE_VERSION)"
	@echo "OPTIMADE_VERSION_SUBST = $(OPTIMADE_VERSION_SUBST)"
	@echo ""
	@echo "INDEXES_HTML = $(INDEXES_HTML)"

