#!/usr/bin/env bash
###
 # A helper/utility script to be imported by other scripts.
 #
 # Intended to hold very common functionality (that's surprisingly not built into bash) such as string upper/lower,
 # and checking current user value, and prompts of yes/no user input.
 ##


#region Global Utility Variables.

# Color Output.
text_reset="\033[0m"
text_black="\033[0;30m"
text_red="\033[0;31m"
text_green="\033[0;32m"
text_orange="\033[0;33m"
text_blue="\033[0;34m"
text_purple="\033[0;35m"
text_cyan="\033[1;36m"
text_yellow="\033[1;33m"
text_white="\033[1;37m"

# Function Return Variables.
return_value=""
file_name=""
file_extension=""

#endregion Global Utility Variables


#region Directory Functions

###
 # Normalizes the location of the terminal to directory of utils.sh file.
 #
 # The point is so that the execution of a script will handle the same, regardless of terminal directory location at
 # script start. Ex: User can start script at either their home folder, or project root, (or any other directory) and
 # relative directory handling will still function the same in either case.
 #
 # Automatically called on script import.
 ##
function normalize_terminal () {
    cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
}


###
 # Gets absolute path of passed location.
 ##
function get_absolute_path () {

    # Check number of passed function args.
    if [[ ${#} == 1 ]]
    then
        # Expected number of args passed. Continue.

        # Check location type.
        if [[ -f ${1} ]]
        then
            # Handle for file.
            return_value="$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"

        elif  [[ -d ${1} ]]
        then
            # Handle for directory.

            # Extra logic to properly handle values of "./" and "../".
            local current_dir="$(pwd)"
            cd ${1}

            # Then call this to have consistent symlink handling as files.
            return_value="$(cd "$(dirname "$(pwd)")"; pwd -P)/$(basename "$(pwd)")"

            # Change back to original location once value is set.
            cd ${current_dir}
        else
            echo -e "${text_red}Passed value ( ${1} ) is not a valid file or directory.${text_reset}"
            exit 1
        fi

    # Handle for too many args.
    elif [[ ${#} > 1 ]]
    then
        echo -e "${text_red}Too many args passed. Expected one arg, received ${#}.${text_reset}"
        exit 1

    # Handle for too few args.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}


###
 # Returns name of current directory.
 # If arg is passed, then returns base name of directory path, or parent directory of file path.
 ##
function get_directory_name () {

    # Check number of passed function args.
    if [[ ${#} == 0 ]]
    then
        # No args passed. Handle for current directory.
        return_value=$(pwd)
        return_value=${return_value##*/}

    # Handle for one arg.
    elif [[ ${#} == 1 ]]
    then

        # Check location type.
        if [[ -f ${1} ]]
        then
            # Handle for file.
            get_absolute_path ${1}
            return_value=${return_value%/*}
            return_value=${return_value##*/}

        elif [[ -d ${1} ]]
        then
            # Handle for directory.
            get_absolute_path ${1}
            return_value=${return_value##*/}

        else
            echo -e "${text_red}Passed value ( ${1} ) is not a valid file or directory.${text_reset}"
            exit 1
        fi

    # Handle for too many args.
    else
        echo -e "${text_red}Too many args passed. Expected one arg, received ${#}.${text_reset}"
        exit 1
    fi
}


###
 # Parses passed file, getting base file name and file extension.
 ##
function parse_file_name () {

    # Check number of passed function args.
    if [[ ${#} == 1 ]]
    then
        # Expected number of args passed. Continue.
        if [[ -f ${1} ]]
        then
            # Handle for file.
            get_absolute_path ${1}
            return_value=${return_value##*/}

            file_name=""
            file_extension=""
            _recurse_file_extension ${return_value}
        else
            echo -e "${text_red}Passed value ( ${1} ) is not a valid file.${text_reset}"
            exit 1
        fi

    # Handle for too many args.
    elif [[ ${#} > 1 ]]
    then
        echo -e "${text_red}Too many args passed. Expected one arg, received ${#}.${text_reset}"
        exit 1

    # Handle for too few args.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}


###
 # Recursive helper function for parse_file_name().
 # Determines base file name and full file extension.
 ##
function _recurse_file_extension () {
    local passed_value=${1}
    local parsed_extension=${passed_value##*.}

    # Check if file extension was found. Occurs when variables are not identical.
    if [[ ${parsed_extension} != ${passed_value} ]]
    then
        # Extension found. Iterate once more.
        file_name=${passed_value%.${parsed_extension}}

        # Handle if global var is currently empty or not.
        if [[ ${file_extension} == "" ]]
        then
            file_extension=".${parsed_extension}"
        else
            file_extension=".${parsed_extension}${file_extension}"
        fi

        # Call recursive function once more.
        _recurse_file_extension ${file_name}
    fi
}


#endregion Directory Functions


#region User Check Functions

###
 # Checks if current username matches passed value.
 # In particular, is used to check if user is sudo/root user.
 ##
function check_is_user () {

    # Check number of passed function args.
    if [[ ${#} == 1 ]]
    then
        # Expected number of args passed. Continue.
        local username=$USER
        local check_user=$1

        # Determine user to check for.
        to_lower ${check_user}
        if [[ "${return_value}" == "root" || "${return_value}" == "sudo" ]]
        then
            # Special logic for checking if "sudo"/"root" user.
            if [[ "$EUID" != 0 ]]
            then
                echo -e "${text_red}Sudo permissions required. Please run as root.${text_reset}"
                exit
            fi
        else
            # Standard logic for all other user checks.
            if [[ "${username}" != "${check_user}" ]]
            then
                echo -e "${text_red}User check (${check_user}) failed. Current user is ${username}.${text_reset}"
                exit 1
            fi
        fi

    # Handle for too many args.
    elif [[ ${#} > 1 ]]
    then
        echo -e "${text_red}Too many args passed. Expected one arg, received ${#}.${text_reset}"
        exit 1

    # Handle for too few args.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}


###
 # Checks if current username does not match passed value.
 # In particular, is used to check if user is not sudo/root user.
 ##
function check_is_not_user () {

    # Check number of passed function args.
    if [[ ${#} == 1 ]]
    then
        # Expected number of args passed. Continue.
        local username=$USER
        local check_user=$1

        # Determine user to check for.
        to_lower ${check_user}
        if [[ "${return_value}" == "root" || "${return_value}" == "sudo" ]]
        then
            # Special logic for checking if "sudo"/"root" user.
            if [[ "$EUID" == 0 ]]
            then
                echo -e "${text_red}Standard permissions required. Please run as non-root user.${text_reset}"
                exit
            fi
        else
            # Standard logic for all other user checks.
            if [[ "${username}" == "${check_user}" ]]
            then
                echo -e "${text_red}Not-user check (${check_user}) failed. Current user is ${username}.${text_reset}"
                exit 1
            fi
        fi

    # Handle for too many args.
    elif [[ ${#} > 1 ]]
    then
        echo -e "${text_red}Too many args passed. Expected one arg, received ${#}.${text_reset}"
        exit 1

    # Handle for too few args.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}

#endregion User Check Functions


#region Text Manipulation Functions

###
 # Converts one or more passed args to uppercase characters.
 ##
function to_upper () {

    # Check number of passed function args.
    if [[ ${#} > 0 ]]
    then
        # At least one arg passed. Loop through each one.
        return_value=()
        for arg in $@
        do
            return_value+=( $(echo "${arg}" | tr '[:lower:]' '[:upper:]') )
        done

    # No args passed.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}


###
 # Convers one or more passed args to lowercase characters.
 ##
function to_lower () {

    # Check number of passed function args.
    if [[ ${#} > 0 ]]
    then
        # At least one arg passed. Loop through each one.
        return_value=()
        for arg in ${@}
        do
            return_value+=( $(echo "${arg}" | tr '[:upper:]' '[:lower:]') )
        done

    # No args passed.
    else
        echo -e "${text_red}Too few args passed. Expected one arg, received 0.${text_reset}"
        exit 1
    fi
}

#endregion Text Manipulation Functions


###
 # Prints out all available text colors provided by this script.
 ##
function display_text_colors () {
    echo ""
    echo "Displaying all available text colors:"
    echo -e "   ${text_black}Black${text_reset}"
    echo -e "   ${text_red}Red${text_reset}"
    echo -e "   ${text_green}Green${text_reset}"
    echo -e "   ${text_orange}Orange${text_reset}"
    echo -e "   ${text_blue}Blue${text_reset}"
    echo -e "   ${text_purple}Purple${text_reset}"
    echo -e "   ${text_cyan}Cyan${text_reset}"
    echo -e "   ${text_yellow}Yellow${text_reset}"
    echo -e "   ${text_white}White${text_reset}"
    echo ""
}


# Functions to call on script import.
normalize_terminal