#!/usr/bin/env bash

# =============================================================================
# convert_levels.sh
# -----------------------------------------------------------------------------
# convert Krissz BD style cave directories to R'n'D style level set directories
# =============================================================================

DEBUG="0"

ORIG_BASE_DIR="caves"
ORIG_DIR="$ORIG_BASE_DIR"

CONV_BASE_DIR="levels"
CONV_MAIN_DIR="Krissz_Boulder_Dash"
CONV_DIR="$CONV_BASE_DIR/$CONV_MAIN_DIR"

MESSAGES_DIR="messages/txt"

MAIN_LEVELSET_NAME="Boulder Dash (Krissz Engine)"
MAIN_LEVELSET_AUTHOR="Various Authors"

CMD_KRISSZ2RND="./krissz2rnd.py"

GFX_SET="gfx_krissz_boulder_dash"
SND_SET="snd_krissz_boulder_dash"
MUS_SET="mus_krissz_boulder_dash"

SKIP_DIR="$ORIG_DIR/Krissz"

HELP_FILES="helpanim.conf helptext.conf"

SQL_FILENAME="convert_levels.sql"
SQL_CREATE="0"

DATESTAMP=`date "+%Y-%m-%d"`
TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"`

NUM_LEVELS_TOTAL=0
NUM_LEVELSETS_TOTAL=0

declare -A levelsets


# -----------------------------------------------------------------------------
# functions
# -----------------------------------------------------------------------------

cleanup_filename ()
{
    ENTRY=$1

    ENTRY=`echo "$ENTRY" | sed -e "s%/./%/%g"`
    ENTRY=`echo "$ENTRY" | sed -e "s/[^A-Za-z0-9/-]/_/g"`
    ENTRY=`echo "$ENTRY" | sed -e "s/__*/_/g"`
    ENTRY=`echo "$ENTRY" | sed -e "s/_$//g"`

    echo "$ENTRY"
}

cleanup_levelset_subdir ()
{
    ENTRY=$1

    ENTRY=`echo "$ENTRY" | tr 'A-Z' 'a-z'`
    ENTRY=`echo "$ENTRY" | sed -e "s/[^a-z0-9]/_/g"`
    ENTRY=`echo "$ENTRY" | sed -e "s/_s_/s_/g"`
    ENTRY="kbd_$ENTRY"

    echo $(cleanup_filename "$ENTRY")
}

cleanup_text_from_filename ()
{
    ENTRY=$1

    ENTRY=`echo "$ENTRY" | tr '_' ' ' | sed -e "s/ s /'s /g"`

    echo "$ENTRY"
}

create_level_group_conf ()
{
    local LEVEL_DIR=$1

    local CONF_FILE="$LEVEL_DIR/levelinfo.conf"

    local NAME=`basename "$LEVEL_DIR"`
    local AUTHOR=`echo "$LEVEL_DIR" | sed -e "s%$CONV_DIR/\([^/]*\).*%\1%"`

    NAME=$(cleanup_text_from_filename "$NAME")
    AUTHOR=$(cleanup_text_from_filename "$AUTHOR")

    if [ "$LEVEL_DIR" = "$CONV_DIR" ]; then
	NAME=$MAIN_LEVELSET_NAME
	AUTHOR=$MAIN_LEVELSET_AUTHOR
    fi

    if [ "$AUTHOR" = "" ]; then
	echo "ERROR: Cannot determine author for directory '$LEVEL_DIR'!"

	exit 10
    fi

    echo "name:                           $NAME"		>  "$CONF_FILE"
    echo "author:                         $AUTHOR"		>> "$CONF_FILE"
    echo ""							>> "$CONF_FILE"
    echo "latest_engine:                  true"			>> "$CONF_FILE"
    echo "level_group:                    true"			>> "$CONF_FILE"
}

create_level_set_conf ()
{
    local DIR=$1
    local LEVEL_DIR=$2
    local LEVELSET=$3
    local NAME=$4
    local AUTHOR=$5

    local LEVELSET_BASENAME=$(cleanup_filename "$LEVELSET")

    local CAVE_FILE="$LEVEL_DIR/$LEVELSET_BASENAME.bd"
    local CONF_FILE="$LEVEL_DIR/levelinfo.conf"

    local NAME_SORTING=""
    local YEAR=`grep Date "$CAVE_FILE" | sort | tail -1 | sed -e "s/Date=\(....\).*/\1/"`

    NUM_LEVELS=`ls "$DIR"/*.html "$DIR"/*.map 2> /dev/null | wc -l | sed -e "s/^ *//"`

    NUM_LEVELS_TOTAL=$((NUM_LEVELS_TOTAL + NUM_LEVELS))
    NUM_LEVELSETS_TOTAL=$((NUM_LEVELSETS_TOTAL + 1))

    FIRST_LEVEL=1

    echo "name:                           $NAME"		>  "$CONF_FILE"

    if [ "$NAME_SORTING" != "" ]; then
	echo "name_sorting:                   $NAME_SORTING"	>> "$CONF_FILE"
    fi

    echo "author:                         $AUTHOR"		>> "$CONF_FILE"

    if [ "$YEAR" != "" ]; then
	echo "year:                           $YEAR"		>> "$CONF_FILE"
    fi

    if [ "$NUM_LEVELS" = "" ]; then
	echo "ERROR: Cannot determine number of levels for level set '$LEVELSET'!"

	exit 10
    fi

    echo ""							>> "$CONF_FILE"
    echo "levels:                         $NUM_LEVELS"		>> "$CONF_FILE"
    echo "first_level:                    $FIRST_LEVEL"		>> "$CONF_FILE"
    echo ""							>> "$CONF_FILE"
    echo "bd_use_krissz_engine:           true"			>> "$CONF_FILE"
    echo "bd_initial_lives:               1"			>> "$CONF_FILE"
    echo "bd_maximum_lives:               1"			>> "$CONF_FILE"
    echo "bd_bonus_life_score:            0"			>> "$CONF_FILE"
    echo ""							>> "$CONF_FILE"
    echo "handicap:                       off"			>> "$CONF_FILE"

    if [ "$BUILD_COMPLETE" != "0" ]; then
        echo ""							>> "$CONF_FILE"
        echo "graphics_set:                   $GFX_SET"		>> "$CONF_FILE"
        echo "sounds_set:                     $SND_SET"		>> "$CONF_FILE"
        echo "music_set:                      $MUS_SET"		>> "$CONF_FILE"
    fi

    if [ "$SQL_CREATE" = "1" ]; then
	if [ "$NAME_SORTING" = "" ]; then
	    NAME_SORTING=$NAME
	fi

	echo "INSERT INTO levelsets VALUES (NULL, \"$LEVELSET\", \"$LEVELSET\", \"$NAME\", \"$NAME_SORTING\", \"$NAME\", \"$AUTHOR\", $NUM_LEVELS, $FIRST_LEVEL, 1, \"$DATESTAMP 00:00:00\", NULL);" >> "$SQL_FILENAME"

    fi
}

convert_caveset ()
{
    local DIR=$1
    local INDENT=$2

    local PREFIX="$INDENT-"
    INDENT="  $INDENT"

    local LEVELSET=`basename "$DIR"`

    if [ "$LEVELSET" = "" ]; then
	echo "ERROR: No valid level set identifier found for caveset directory '$DIR'!"

	exit 10
    fi

    if [ "${levelsets[$LEVELSET]}" != "" ]; then
	echo "ERROR: Level set identifier '$LEVELSET' already used!"

	exit 10
    fi

    levelsets[$LEVELSET]=1

    local LEVELSET_SUBDIR=$(cleanup_levelset_subdir "$LEVELSET")
    local ORIG_SUBDIR=`echo "$DIR" | sed -e "s/^$ORIG_BASE_DIR\///"`
    local ORIG_PARENTDIR=`dirname "$ORIG_SUBDIR"`
    local CONV_SUBDIR="$CONV_DIR/$ORIG_PARENTDIR/$LEVELSET_SUBDIR"

    CONV_SUBDIR=$(cleanup_filename "$CONV_SUBDIR")

    local NAME=`echo "$DIR" | sed -e "s/.*\/\([^\/]*\)/\1/"`
    local AUTHOR=`echo "$DIR" | sed -e "s/$ORIG_BASE_DIR\///" | sed -e "s/\/.*//"`

    NAME=$(cleanup_text_from_filename "$NAME")
    AUTHOR=$(cleanup_text_from_filename "$AUTHOR")

    echo "$PREFIX creating level set directory '$CONV_SUBDIR' ..."

    mkdir -p "$CONV_SUBDIR"

    # sort cave files according to numbers in file names
    SORT_CAVES="--sort-caves"

    # but do not sort single caves
    if `echo "$CONV_SUBDIR" | egrep -q "_single_caves$"`; then
        SORT_CAVES=""
    fi

    # rename cave files using normalized cave names
    RENAME_FILES="--rename-files"

    # only used for debugging purposes
    DUMP=""
    if [ "$DEBUG" == "1" ]; then
        DUMP="--dump-data"
    fi

    $CMD_KRISSZ2RND "$DIR" "$CONV_SUBDIR" "$NAME" "$AUTHOR" "$SORT_CAVES" "$RENAME_FILES" "$DUMP" --use-prefix --messages "$MESSAGES_DIR"

    if [ "$?" != "0" ]; then
	echo "ERROR: Converting levels failed!"

	exit 10
    fi

    create_level_set_conf "$DIR" "$CONV_SUBDIR" "$LEVELSET" "$NAME" "$AUTHOR"
}

process_caveset ()
{
    local DIR=$1
    local INDENT=$2

    local PREFIX="$INDENT-"
    INDENT="  $INDENT"

    local BASENAME=`basename "$DIR"`

    echo "$PREFIX processing caveset directory '$BASENAME' ..."

    convert_caveset "$DIR" "$INDENT"
}

process_directory ()
{
    local DIR=$1
    local INDENT=$2

    local PREFIX="$INDENT-"
    INDENT="  $INDENT"

    if [ "$BUILD_COMPLETE" = "0" -a "$DIR" = "$SKIP_DIR" ]; then
        echo "$PREFIX skipping caves directory '$DIR' ..."

        return
    fi

    echo "$PREFIX processing caves directory '$DIR' ..."

    # check for sub-directories

    CAVE_DIRS_FOUND=0

    for i in "$DIR"/*; do
	local ENTRY="$i"

	if [ -d "$ENTRY" ]; then
	    process_directory "$ENTRY" "$INDENT"

            CAVE_DIRS_FOUND=1
	fi
    done

    # check for cave files

    CAVE_FILES_FOUND=0

    for i in "$DIR"/*; do
	local ENTRY="$i"

	if `echo "$ENTRY" | egrep -q "\.(html|map)$"`; then
	    process_caveset "$DIR" "$INDENT"

            CAVE_FILES_FOUND=1

            # do not process this directory anymore
            break
	fi
    done

    if [ "$CAVE_DIRS_FOUND" = "1" -a "$CAVE_FILES_FOUND" = "1" ]; then
	echo "ERROR: Cannot process both cave directories and cave files in '$DIR'!"

	exit 10
    fi

    if [ "$DIR" != "$ORIG_BASE_DIR" ]; then
	local SUBDIR=`echo "$DIR" | sed -e "s/^$ORIG_BASE_DIR\///"`
	local CONV_SUBDIR="$CONV_DIR/$SUBDIR"
	local BASENAME_DIR=`basename "$DIR"`

        if [ -d "$CONV_SUBDIR" ]; then
	    create_level_group_conf "$CONV_SUBDIR"
        fi
    fi
}

check_cave_codes ()
{
    local DIR=$1

    declare -A CAVE_CODE_HASH
    declare -A CAVE_CODE_HASH_WARNED

    SAME_CAVE_CODE_FOUND=0

    CAVE_CODES=`find "$DIR/" | egrep "\.(html|map)$" | sed -e "s%.*/%%" | awk -F\. '{ print $2 }'`

    for i in $CAVE_CODES; do
        if [ "${CAVE_CODE_HASH[$i]}" != "" -a "${CAVE_CODE_HASH_WARNED[$i]}" = "" ]; then
            echo "ERROR: Cave code '$i' found in the following cave filenames:"
            find "$DIR/" | grep "$i" | sed -e "s%//%/%" | sed -e "s/^/- /"

            CAVE_CODE_HASH_WARNED[$i]=1
            SAME_CAVE_CODE_FOUND=1
        else
            CAVE_CODE_HASH[$i]=1
        fi
    done

    if [ "$SAME_CAVE_CODE_FOUND" = "1" ]; then
        echo "ERROR: Some cave codes found more than once!"

        exit 10
    fi
}

copy_help_files ()
{
    echo "- copying help files for info screen ..."

    for i in $HELP_FILES; do
        cp -a "$i" "$CONV_DIR"
    done
}


# -----------------------------------------------------------------------------
# main
# -----------------------------------------------------------------------------

if [ ! -d "$ORIG_BASE_DIR" ]; then
    echo "ERROR: Source directory '$ORIG_BASE_DIR' does not exist!"

    exit 10
fi

if [ -d "$CONV_BASE_DIR" ]; then
    echo "ERROR: Target directory '$CONV_BASE_DIR' already exists!"

    exit 10
fi

if [ "$SQL_CREATE" = "1" ]; then
    rm "$SQL_FILENAME"
fi

mkdir -p "$CONV_DIR"

echo "Converting Krissz BD caves to R'n'D level sets ..."

copy_help_files

create_level_group_conf "$CONV_DIR"

process_directory "$ORIG_DIR" ""

echo "Checking cave codes in filenames ..."

check_cave_codes "$ORIG_DIR"

echo "$NUM_LEVELS_TOTAL levels in $NUM_LEVELSETS_TOTAL level sets converted."

echo "Done."

exit 0
