#!/bin/bash
# Script to generate an HTML wallpaper catalog.
# Copyright (C) 2022 DaringCuteSeal (or.. my real name.. Cikitta).

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# Dependencies:
# find (findutils or other), ImageMagick

# Extra files required:
# config, styles.css, events.js, and previews.js

# A bit of explanation:
# This script parses the "config" file located in this
# directory to write all the categories existing.
# Then, it looks for any .info files found
# at the root of this project's directory (previous
# directory, relatively), parses each file, and
# writes elements to an HTML file.
# Lastly, it generates a previews.js file which
# Stores name of the wallpapers alongside its
# variants which will be used by events.js to
# attach event listeners.

# And why would I make this? Learning.

# Message functions
info(){
	echo -e "[i] $1"
}

work(){
	echo -en "[-] $1"
}

subwork(){
	echo -en " ⤷ [-] $1"
}

subinfo(){
	echo -e " ⤷ [i] $1"
}

print_done(){
	echo " done!"
}

warn(){
	echo -e "[!] $1"
}

# Function to write to the HTML file,
# with the specified level of indentation
write(){

	if [[ -z "$2" ]]
	then
		text="$1"
		echo -en "${text}" >> "$out_html"
	else
		text="$1"
		# Is there any better way to do this lol
		for z in `seq 1 $2`; do tabs+='\t'; done
		echo -en "${tabs}${text}" >> "$out_html"
		unset tabs
	fi
}


# Same as before but take input from stdin
write_stdin(){
	cat >> "$out_html" < /dev/stdin
}

# Same as before but this is for the events.js file
write_js(){
	if [[ -z "$2" ]]
	then
		text="$1"
		echo -en "${text}" >> "$out_previews"
	else
		text="$1"
		# Is there any better way to do this lol
		for z in `seq 1 $2`; do tabs+='\t'; done
		echo -en "${tabs}${text}" >> "$out_previews"
		unset tabs
	fi

}

# Same as before but use stdin...
write_js_stdin(){
	cat >> "$out_previews" < /dev/stdin
}

# Find all .info files. There shouldn't be any whitespace on the file path so this should work fine.
dir="${0%/*}"
infos=($(find "$dir/.." -name '.info'))

# Setup output directory
# If an argument was passed, treat that as the output directory.
if [[ -n "$1" ]]
then
	out_dir="$1"
else
	out_dir="out"
fi

mkdir -p "$out_dir" || exit $?

# Copy extra files
work "Copying files..."
cp "$dir/theme.css" "$dir/styles.css" "$dir/events.js" "$out_dir"
print_done

# Setup directory for the document output
doc_dir="$out_dir"
out_html="$doc_dir/index.html"
out_previews="$doc_dir/previews.js"

info "Writing document output to '$out_dir'"

# Setup trap
_trap(){
	warn "\n[!] SIGINT or SIGTERM received"
	exit 1
}
trap '_trap' SIGINT SIGTERM


# Write the HTML header
work "Writing HTML headers..."
cat > "$out_html" << EOF
<!doctype html>
<!-- Generated by Daringcuteseal's Wallpapers catalog generator -->
<!-- https://raw.githubusercontent.com/DaringCuteSeal/wallpapers/master/catalog/generate-catalog.sh -->

<html>
<head>
	<title>Wallpapers catalog</title>
	<link rel="stylesheet" href="styles.css">
	<link rel="stylesheet" href="theme.css">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta charset=utf-8>
</head>
<body>
	<p><a href="https://daringcuteseal.github.io">Home</a></p>
	<p>This is a catalog of my wallpeppers. You can also visit my <a href="https://github.com/DaringCuteSeal/wallpapers">GitHub repository</a> directly.</p>

	<p>
		<span>All categories: </span>
EOF
print_done

# Create the directory for previews
preview_dir="$out_dir/previews"
mkdir -p "$preview_dir" || exit $?
info "Writing previews to '$preview_dir'"

# Generate categories
source "$dir/config"
work "Generating navigation for categories..."

# The j temporary variable is used to determine
# whether we need to add the bullet
# or not, since the last category don't
# need a bullet.
# and yes this is a bit dumb, fix this and make a PR if you want.
j=0
write "" 3
for i in "${!categories[@]}"
do
	write "<a href=\"#${i}\">${categories[$i]}</a>"
	j=$(($j+1))
	if [[ $j -lt ${#categories[@]} ]]
	then
		write " &bull; "
	fi
done
unset j

write_stdin << EOF

	</p>
EOF

print_done

# Exit when a command fails
set -e

# Loop through every single wallpaper
for (( i=0; i<${#infos[@]}; i++ ))
do
	# Declare the variants as an associative array
	declare -A variants

	# Source the info file
	source "${infos[$i]}"

	work "Working on '$name'\n"

	subinfo "Generating wallpaper previews..."

	# Create preview images for every variant
	for j in "${!variants[@]}"
	do
		# Get the file name based on the variant
		filename="${variants[$j]}"

		if [[ -e "$out_dir/previews/$parsable_name-${filename%*.*}-preview.webp" ]]
		then
			subinfo "Preview for $filename already exists, skipping..."
		else
			# Generate the preview image

			subwork "Generating preview for $filename... "
			convert "$dir/../$category/$parsable_name/$filename" -resize 590x331 -background none -gravity center -extent 590x331 "$out_dir/previews/$parsable_name-${filename%*.*}-preview.webp"

			print_done
		fi

	done

	# Add current wallpaper index to its corresponding category
	# GOD CAN I HAVE 2 DIMENSIONAL ARRAYS?
	eval "category_$category+=($i)"
	subinfo "Added '$name' to category '${categories[$category]}'"

	# Unset previous variables
	# These are hard-coded!
	unset name category variants filename

done

set +e

# XXX huh.. correct? idk i my grammar broke. fix later
info "Generating HTML previews..."

declare -A variants
for i in "${!categories[@]}"
do
	category_name="${categories[$i]}"
	category_now="$i"
	work "Working on '$category_name'\n"

	# Write a "section".. or whatever it's called
	write "<h1 id="$category_now">$category_name</h1>\n" 1

	# Write description
	category_desc="$(eval "echo \"\${description_${category_now}}\"")"
	if [[ -z "$category_desc" ]]
	then
		write "<p><i>(no description provided)</i></p>\n" 1
	else
		write "<p>$category_desc</p>\n" 1
	fi

	# I went here after working on
	# the JavaScript code after a couple
	# days and I hate non-object-oriented
	# programming. Gah.
	# anyways,
	# Now write the actual previews for all
	# the wallpapers

	category_counts="$(eval "echo \"\${#category_$category_now[@]}\"")"
	
	if [[ $category_counts -gt 0 ]]
	then

		indexes="$(eval "echo \${category_$category_now[@]}")"

		for k in $indexes
		do
			source "${infos[$k]}"

			write_stdin << EOF
	<div id="$parsable_name" class="wall-preview">
		<div class="img-box">
EOF
			for l in "${!variants[@]}"
			do
				write "<img class=\"preview-img-$parsable_name\" src=\"previews/$parsable_name-${variants[$l]%*.*}-preview.webp\" alt=\"$name ($l)\" title=\"$name ($l)\">\n" 3

			done

			write "</div>\n" 2

			write_stdin << EOF
		<div class="info-box">
			<p>
			<b>Name:</b> $name<br>
			<b>Description:</b> $desc<br>
			<b>Variants:</b>
EOF
			for l in "${!variants[@]}"
			do
				write "<button class=\"$parsable_name-vars\">$l</button>\n" 4
			done

			write "<br>\n" 4

			write "<button id=\"$parsable_name-download\" class=\"download-btn\">Download Variant</button>" 4
			write "\n</p>\n"

			write_stdin << EOF
			<p>
			<a href="https://github.com/DaringCuteSeal/wallpapers/tree/main/$category/$parsable_name/">GitHub Page</a>
			<br>
			<a class="copy" href="#$parsable_name">Link back to here (click to copy)</a>
			</p>
		</div>
	</div>
EOF
		
		subinfo "Wrote '$name'"
		done
	else
		info "There aren't any wallpapers for category '$category_now'"
		write "<p>There aren't any wallpapers for this category.</p>\n\n" 1
	fi

	unset parsable_name category category_name category_desc 
	j=$(($j+1))
done
	
# Write the script tag and end the document
work "Ending document..."
write_stdin << EOF
	<script src="previews.js"></script>
	<script src="events.js"></script>
</body>
</html>
EOF
print_done

# Generate the previews.js data that
# will be used by events.js
vars_str(){
	echo -n "["
	k=0
	for j in "${!variants[@]}"
	do
		echo -n "'$j'"
		k=$(($k+1))
		if [[ $k -lt ${#variants[@]} ]]
		then
			echo -n ", "
		fi
	done
	echo -n "]"
	unset k
}

filenames_str(){
	echo -n "["
	k=0
	for j in "${variants[@]}"
	do
		echo -n "'$j'"
		k=$(($k+1))
		if [[ $k -lt ${#variants[@]} ]]
		then
			echo -n ", "
		fi
	done
	echo -n "]"
	unset k
}

work "Generating previews JSON..." # and yes it isn't JSON but hey it's called "JavaScript Object Notation" so...
cat > "$out_previews" <<< "var previews = ["


m=0
for (( i=0; i<${#infos[@]}; i++ ))
do
	source "${infos[$i]}"

	write_js_stdin << EOF
	{
		'name': '$parsable_name',
		'category': '$category',
EOF

	m=$(($m+1))
	write_js "'variants': $(vars_str),\n" 2

	write_js "'variants_filename': $(filenames_str)\n" 2
	write_js "}" 1

	if [[ $m -lt ${#infos[@]} ]]
	then
		write_js ",\n"
	fi
done
write_js "\n]"

print_done
