#!/bin/bash

ScriptFile=$(readlink -f "${BASH_SOURCE[0]}")
ScriptDir=$(dirname "${ScriptFile}")

UseGit=1
Verbose=0
CMakeModules=""
CMakeModulesForced=""
Operations=()

function Log()
{
    printf "$@\n"
}

function Verbose()
{
    if [[ $Verbose -eq 1 ]]; then
        Log "$@"
    fi
}

function Error()
{
    >&2 printf "$@\n"
}

function Panic()
{
    Error "$@"
    exit 1
}

function PrintHelp()
{
    printf "This is a tool to create a new project group or projects inside an exsisting group.

Parameters:

    -g|--group <directory>
        Create a new project group at the given directory.

    -l|--library <name> <directory>
        Create a new library project with the given name at the given directory.

    -e|--executable <name ><directory>
        Create a new executable project with the given name at the given directory.

    -m|--modules <remote>
    -M|--force-modules <remote>
        Add the CMake Modules from the given remote repository as submodule of the new project.

    -n|--nogit
        Does not initialize a new git repository when creating a new project group.

    -v|--verbose
        Print extra debug output.

    -?|-h|--help
        Print this help.
"
}

function Copy()
{
    srcDir="$1"
    dstDir="$2"
    file="$3"
    oldName="$4"
    newName="$5"

    tmpSrc="$srcDir$file"
    tmpDst="$dstDir$file"
    if [[ -n "$oldName$newName" ]]; then
        tmpDst=${tmpDst//$oldName/$newName}
    fi
    tmpDir=$(dirname $tmpDst)

    Verbose "    Copy   .$file to $tmpDst"

    mkdir -p "$tmpDir" \
        || Panic "Unable to create directory: $tmpDir!"
    cp "$tmpSrc" "$tmpDst" \
        || Panic "Unable to copy file: $tmpSrc > $tmpDst!"
    if [[ -n "$oldName$newName" ]]; then
        oldUpper=$(echo $oldName | awk -F: '{ print toupper($1) }')
        newUpper=$(echo $newName | awk -F: '{ print toupper($1) }')
        sed -i -e "s/$oldName/$newName/g" "$tmpDst" \
            || Panic "Unable to replace names!"
        sed -i -e "s/$oldUpper/$newUpper/g" "$tmpDst" \
            || Panic "Unable to replace names!"
    fi
}

function CreateGroup()
{
    dir="$1"
    Log "\nCreate Project Group: $dir"

    # Create directory
    Log "  Create directory: $dir"
    mkdir -p "$dir" \
        || Panic "Unable to create project group directory: $dir!"

    # Create git repository
    Log "  Create git repository"
    if [[ $UseGit -eq 1 ]]; then
        git -C $dir init \
            || Panic "Git init failed!"

        # Add cmake modules
        Log "  Add git submodule for CMake modules"
        if [[ -n "$CMakeModules" ]]; then
            git -C $dir submodule add $CMakeModulesForced "$CMakeModules" "$dir/cmake/modules" \
                || Panic "Git submodule add failed!"
        fi
    fi

    # Copy files
    Log "  Copy files"
    srcDir="$ScriptDir"
    for file in $(find $srcDir -type f); do
        if      [[ $file == $ScriptFile ]] \
            ||  [[ $file == $srcDir/build/* ]] \
            ||  [[ $file == $srcDir/.git/* ]] \
            ||  [[ $file == $srcDir/.gitmodules ]] \
            ||  [[ $file == $srcDir/.vscode/* ]] \
            ||  [[ $file == $srcDir/projects/* ]] \
            ||  [[ $file == $srcDir/cmake/modules/* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        elif    [[ $UseGit -eq 0 ]] \
            &&  [[ $file == $srcDir/.git* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        else
            Copy "$srcDir" "$dir" "${file/$srcDir/}"
        fi
    done
}

function CreateLibrary()
{
    name="$1"
    dir="$2"
    Log "\nCreate Library: $1 $2"

    # Create directory
    Log "  Create directory: $dir"
    mkdir -p "$dir" \
        || Panic "Unable to create directory: $dir!"

    # Create git repository
    Log "  Create git repository"
    if [[ $UseGit -eq 1 ]]; then
        git -C $dir init \
            || Panic "Git init failed!"

        # Add cmake modules
        Log "  Add git submodule for CMake modules"
        if [[ -n "$CMakeModules" ]]; then
            git -C $dir submodule add $CMakeModulesForced "$CMakeModules" "$dir/cmake/modules" \
                || Panic "Git submodule add failed!"
        fi
    fi

    # Copy files
    Log "  Copy files"
    srcDir="$ScriptDir/projects/libhelloworld"
    for file in $(find $srcDir -type f); do
        if      [[ $file == $srcDir/build/* ]] \
            ||  [[ $file == $srcDir/cmake/modules/* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        elif    [[ $UseGit -eq 0 ]] \
            &&  [[ $file == $srcDir/.git* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        else
            Copy "$srcDir" "$dir" "${file/$srcDir/}" "libhelloworld" "$name"
        fi
    done
}

function CreateExecutable()
{
    name="$1"
    dir="$2"
    Log "\nCreate Executable: $1 $2"

    # Create directory
    Log "  Create directory: $dir"
    mkdir -p "$dir" \
        || Panic "Unable to create directory: $dir!"

    # Create git repository
    Log "  Create git repository"
    if [[ $UseGit -eq 1 ]]; then
        git -C $dir init \
            || Panic "Git init failed!"

        # Add cmake modules
        Log "  Add git submodule for CMake modules"
        if [[ -n "$CMakeModules" ]]; then
            git -C $dir submodule add $CMakeModulesForced "$CMakeModules" "$dir/cmake/modules" \
                || Panic "Git submodule add failed!"
        fi
    fi

    # Copy files
    Log "  Copy files"
    srcDir="$ScriptDir/projects/helloworld"
    for file in $(find $srcDir -type f); do
        if      [[ $file == $srcDir/build/* ]] \
            ||  [[ $file == $srcDir/cmake/modules/* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        elif    [[ $UseGit -eq 0 ]] \
            &&  [[ $file == $srcDir/.git* ]]
        then
            relFile=.${file/$srcDir/}
            Verbose "    Ignore $relFile"
        else
            Copy "$srcDir" "$dir" "${file/$srcDir/}" "helloworld" "$name"
        fi
    done
}

# Parse arguments
while [ $# -gt 0 ]; do
    case $1 in
        "-g" | "--group" )
            if [ $# -lt 2 ]; then
                Panic "Parameter $1 expects exactly one parameter!"
            fi
            tmp=$(readlink -m "$2")
            Operations+=("grp:$tmp")
            shift
            ;;

        "-l" | "--library" )
            if [ $# -lt 3 ]; then
                Panic "Parameter $1 expects exactly two parameter!"
            fi
            tmp=$(readlink -m "$3")
            Operations+=("lib:$2:$tmp")
            shift
            shift
            ;;

        "-e" | "--executable" )
            if [ $# -lt 3 ]; then
                Panic "Parameter $1 expects exactly two parameter!"
            fi
            tmp=$(readlink -m "$3")
            Operations+=("exe:$2:$tmp")
            shift
            shift
            ;;

        "-m" | "--modules" )
            if [ $# -lt 2 ]; then
                Panic "Parameter $1 expects exactly one parameter!"
            fi
            CMakeModules="$2"
            shift
            ;;

        "-M" | "--force-modules" )
            if [ $# -lt 2 ]; then
                Panic "Parameter $1 expects exactly one parameter!"
            fi
            CMakeModules="$2"
            CMakeModulesForced="--force"
            shift
            ;;

        "-n" | "--nogit" )
            UseGit=0
            ;;

        "-v" | "--verbose" )
            Verbose=1
            ;;

        "-h" | "-?" | "--help" )
            PrintHelp
            exit 0
            ;;

        * )
            Panic "Invalid or unknown parameter: $1"
            ;;
    esac
    shift
done

# Execute operations
for data in "${Operations[@]}"; do
    op=$(echo $data | awk -F: '{ print $1 }')
    case $op in
        grp)
            dir=$(echo $data | awk -F: '{ print $2 }')
            CreateGroup "$dir"
            ;;

        lib)
            name=$(echo $data | awk -F: '{ print $2 }')
            dir=$(echo $data | awk -F: '{ print $3 }')
            CreateLibrary "$name" "$dir"
            ;;

        exe)
            name=$(echo $data | awk -F: '{ print $2 }')
            dir=$(echo $data | awk -F: '{ print $3 }')
            CreateExecutable "$name" "$dir"
            ;;

        *)
            Panic "Invalid or unknown operation: $op"
            ;;
    esac
done
