#!/bin/bash

### Preprocessing 1
### Help message

csg_help() {
	echo 'Usage: csg [-h | -? | --help]
       csg <source_dir> <destination_dir> <title_format> [<scripts_dir>]

Options:
  -h, -?, --help    Print this help message (also available when given no
                    arguments)

Arguments:
  <source_dir>         Folder which contains source files
  <destination_dir>    Folder in which the generated site will be put
  <title_format>       Format string for page title
                       Accepts any text or HTML, & is replaced with contents
                       title (first h1 header).
  <scripts_dir>        Optional, folder which contains awk script for editing of
                       generated webpages.

Variables (you can predefine):
  CSG_TIMESTAMP_FILE    File path for git-based timestamps (when git exists)
                        Default: "./timestamps.txt"
                        Disable: ""
  CSG_TMP_DIR           Directory to put temporary files
                        Default: "/tmp"
  CSG_AWK               awk executable and flags
                        Default: searches for gawk
  CSG_MD_TO_HTML        Program to convert Markdown to HTML and it'\''s flags
                        Default: searches for lowdown

Dependencies (required):
  bash, printf, find, cpio


csg - complicated (static) site generator
Created by Syndamia, https://gitlab.com/Syndamia/csg'
  exit $1
}

[ -z "$1" -o "$1" = '-h' -o "$1" = '-?' -o "$1" = '--help' ] && csg_help 0

### Preprocessing 2
### Script parameters

SOURCE="$1"
[ ! -d "$SOURCE" ] && echo "[Error] $SOURCE (<source_dir>) isn't a directory or doesn't exist!" \
	&& csg_help 1
[ ! -r "$SOURCE" ] && echo "[Error] No read access to $SOURCE (<source_dir>)!" \
	&& csg_help 2

DESTINATION="$(realpath "$2")"
[ ! -d "$DESTINATION/.." ] && echo "[Error] Parent directory of $2 (<destination_dir>) isn't a directory or doesn't exist!" \
	&& csg_help 1
[ ! -w "$DESTINATION/.." ] && echo "[Error] No write access to parent directory of $2 (<destination_dir>)!" \
	&& csg_help 2

TITLEF="$3"

AWKSCRIPTS="$4"
[ -n "$AWKSCRIPTS" -a ! -d "$AWKSCRIPTS" ] && echo "[Error] $AWKSCRIPTS (<scripts_dir>) isn't a directory or doesn't exist!" \
	&& csg_help 1

### Preprocessing 3
### "Global" variables

: ${CSG_TIMESTAMP_FILE:="$(realpath ./timestamps.txt)"}

: ${CSG_TMP_DIR:='/tmp'}
[ ! -d "$CSG_TMP_DIR" ] && echo "[Error] $CSG_TMP_DIR (\$CSG_TMP_DIR) doesn't exist!" \
	&& csg_help 1
[ ! -r "$CSG_TMP_DIR" -o ! -w "$CSG_TMP_DIR" ] && echo "[Error] No read or write permissions for $CSG_TMP_DIR (\$CSG_TMP_DIR)!" \
	&& csg_help 2

isCommand() {
	command -v "$1" &> /dev/null
}

if [ -n "$CSG_AWK" ]
then :
elif isCommand 'gawk'
then
	CSG_AWK='gawk --posix'
else
	echo '[Error] Couldn'\''t find an awk implementation!'
	csg_help 3
fi

if [ -n "$CSG_MD_TO_HTML" ]
then :
elif isCommand 'lowdown'
then
	CSG_MD_TO_HTML="lowdown \
		--html-no-escapehtml \
		--html-no-skiphtml \
		--parse-no-metadata \
		--parse-no-autolink"
else
	echo '[Error] Couldn'\''t find a Markdown to HTML convertion program!'
	csg_help 3
fi

### Preprocessing 4
### Timer/status function definitions

overwriteLine() {
	printf "\e[1A\e[K$1\n"
}

_dur=0
startTimer() {
	_dur="$(date +%s%N)"
	printf "$1\n"
}
endTimer() {
	_dur="$(echo "scale=4 ; ($(date +%s%N) - $_dur) / 1000000000" | bc -l)"
	printf "\e[1A\e[K$1    %.3fs\n" $_dur
}

### Stage 0
### Create timestamps.txt file, if necessary

if [ -n "$CSG_TIMESTAMP_FILE" ] && isCommand 'git'
then
	timestamps_writeDates() {
		for file in $(find . -type f -name '*.md')
		do
			dates=($(git log --follow --pretty=format:%ad --date="format:%d %B %Y" -- "$file"))
			line="$DESTINATION${file:1:-2}html\t${dates[@]: -3:3} ${dates[@]:0:3}"
			echo -e "$line" >> "$CSG_TIMESTAMP_FILE"
		done
	}

	headc="$(git rev-parse HEAD)"
	if [ ! -f "$CSG_TIMESTAMP_FILE" ] || [ "$headc" != "$(head -1 "$CSG_TIMESTAMP_FILE")" ]
	then
	startTimer "[Stage 0] Creating timestamps file"
		echo "$headc" > "$CSG_TIMESTAMP_FILE"
		(cd "$SOURCE" && timestamps_writeDates)
	endTimer "[Stage 0] Done"
	fi
fi

### Stage 1
### Copy everything from SOURCE to DESTINATION
startTimer "[Stage 1] Moving files to destination"

(cd "$SOURCE" && \
	find . -type f -not -name "\.*" -not -name '_header.html' -not -name '_footer.html' | \
	cpio -pdu "$DESTINATION" >/dev/null 2>&1)

find "$DESTINATION" -type f -name "*index.md" -links +1 | while read -r file
do
	mv "$file" "${file%md}html"
done

if [ -n "$AWKSCRIPTS" ]
then
	overwriteLine "[Stage 1] Combining awk scripts"

	scr_path=()
	scr_recip=()
	while read -r reg; read -r scripts
	do
		cat $scripts > "$CSG_TMP_DIR/csg-${#scr_path[@]}.awk"
		scr_path+=("$CSG_TMP_DIR/csg-${#scr_path[@]}.awk")
		scr_recip+=("$(find $DESTINATION -type f -regex "$reg")")
	done < <($CSG_AWK '
	{
		# Remove first field
		$1=""; sub(FS, "")
		# Associate current file with regex
		if (awks[$0] == "") awks[$0] = FILENAME
		else                awks[$0] = awks[$0] " " FILENAME

		nextfile
	}
	END {
		for (reg in awks) {
			print reg
			print awks[reg]
		}
	}
	' $(find $AWKSCRIPTS -type f -name "[A-Z]*.awk"))

	overwriteLine "[Stage 1] Finding awk libraries"

	scr_libs=""
	while read -r file
	do
		scr_libs+=" -f $file "
	done < <(find $AWKSCRIPTS -type f -name "#*.awk")
fi

endTimer "[Stage 1] Done"

### Stage 2
### Transforming Markdown
startTimer "[Stage 2] Transforming Markdown to HTML"

transform-file() {
	local file="$1"
	local outf="${file%md}html"
	local scripts="$2"

	# Gets special information from the file
	local title="$($CSG_AWK -v titlef="$TITLEF" '
	/^# / {
		# Remove first field
		$1 = ""; sub(FS, "")
		# Output title
		sub(/.*/, titlef); print
		exit
	}' "$file")"
	local descr="$($CSG_AWK '
	/^[[:alpha:]]/ {
		startedGathering = 1
		# Take only anchor text
		gsub(/\]\([^)]*\)/, "")
		gsub(/\[/, "")
		# Append line
		if (desc == "") desc = $0
		else desc = desc " " $0
		# Trim line to 200 characters
		if (length(desc) > 200) {
			desc = substr(desc, 1, 197) "..."
			exit
		}
	}
	startedGathering && /^$/ { exit }
	END { print desc }' "$file")"
	local words="$($CSG_AWK '{total += NF} END{print total}' "$file")"
	local timestamps=($($CSG_AWK -v file="$file" '
	BEGIN { FS = "\t" }
	$1 == file {
		print $2
		exit
	}' "$file"))

	# Generate
	$CSG_MD_TO_HTML "$file" > "$outf"

	# Run custom awk scripts
	$CSG_AWK \
		-v title="$title" \
		-v description="$descr" \
		-v words="$words" \
		-v created="${timestamps[@]:0:3}" \
		-v edited="${timestamps[@]:4}" \
		$scr_libs $scripts -f "$CSG_TMP_DIR/csg-print.awk" \
		"$outf" > "$outf.tmp"
	mv "$outf.tmp" "$outf"

	# Create final file
	$CSG_AWK \
		-v title="$title" \
		-v description="$descr" '
	BEGIN { gsub(/&/, "\\\\&", title) }
	/\[DESCRIPTION\]/ {
		gsub(/\[DESCRIPTION\]/, description)
	}
	/\[TITLE\]/ {
		gsub(/\[TITLE\]/, title)
	}
	{print}' "$SOURCE/_header.html" > "$file"
	cat "$outf" "$SOURCE/_footer.html" >> "$file"
	mv "$file" "$outf"
}

echo '$0 != 0 {print}' > "$CSG_TMP_DIR/csg-print.awk"

while read -r file
do
	scripts=""
	for i in ${!scr_recip[@]}
	do
		[ "${scr_recip[$i]}" != "${scr_recip[$i]/${file%md}html/}" ] && scripts+=" -f ${scr_path[$i]} "
	done
	transform-file "$file" "$scripts" &
done < <(find "$DESTINATION" -type f -name "*.md")
wait
endTimer "[Stage 2] Done"
