#!/bin/bash

declare COMMIT="$*";

declare -r PKGNAME="archdroid-icon-theme";
declare -r PKGNAME_GIT="archdroid-icon-theme-git";

declare -r PKGDIR="aur/${PKGNAME}";
declare -r PKGDIR_GIT="aur-git/${PKGNAME_GIT}";

declare -r A="Archdroid";
declare -r THEME_DEFAULT="${A}-Green/";

declare CHECKSUM_LOCAL;
declare LAST_COMMIT;
declare PKGVER;

# map `[color]isSuccessSame`
declare -Ar THEMES=(
    ["ArchBlue"]=1
    ["Blue"]=1
    ["BlueGrey"]=1
    ["BlueGreyDark"]=1
    ["Brown"]=1
    ["BrownDark"]=1
    ["Cyan"]=1
    ["DeepPurple"]=1
    # ["Green"]=1
    ["Grey"]=1
    ["Indigo"]=1
    ["KellyGreen"]=1
    ["LightBlue"]=1
    ["LightGreen"]=1
    ["Lime"]=1
    ["Pink"]=1
    ["Purple"]=1
    ["Shamrock"]=1
    ["Teal"]=1

    ["Amber"]=0
    ["DeepOrange"]=0
    ["DeepOrangeDark"]=0
    ["Orange"]=0
    ["Red"]=0
    ["Yellow"]=0
);

_main() {

    _gr23;

    _gprint "Update local files?" && _Yn && _Build;
    _gprint "Add a new commit?" && _Yn && _Commit;
    _gprint "Upload package to online repos?" && _Yn && _Upload;
};

# Update package locally.
_Build() {
    # pushd 1
    _q pushd "${PKGNAME}";

    # pushd 2
    _q pushd "${THEME_DEFAULT}";

    _glecho "Removing extra files...";
    _RmExtraFiles;
    echo "Done.";

    _glecho "Minifying svg files...";
    _Minify;
    echo "Done.";

    # popd 2
    _q popd;

    _glecho "Creating themes...";
    _CreateThemes;
    echo "Done.";

    _glecho "Colorizing themes...";
    _ColorizeThemes;
    echo "Done.";

    _glecho "Update theme caches...";
    _UpdateCache;
    echo "Done.";

    # popd 1
    _q popd;

    _glecho "Building archive...";
    _Package;
    echo "Done.";
};

# Remove all unnecessary and backup files from the base theme.
_RmExtraFiles() {

    local -a extra=(
        "scale"
        "index.theme.bak"
        "emblems/scalable/emblem-greenraccoon23.svg"
        "emblems/scalable/emblem-greenraccoon23-transparent.svg"
    );
    local -ar subdirs=(
        "actions"
        "animations"
        "apps"
        "categories"
        "devices"
        "emblems"
        "mimetypes"
        "places"
        "status"
        "stock/io"
    );
    local dir;
    local filepath;

    for dir in "${subdirs[@]}"; do
        extra+=("${dir}/scalable/bak");
        extra+=("${dir}/scaled");
    done;

    for filepath in "${extra[@]}"; do
        [ -e "${filepath}" ] || continue;
        _rm "${filepath}";
        _ifErr "Failed to remove '${filepath}'";
        echo "    Removed ${filepath}";
    done;
};

_Minify() {

    local cmd="svgcleaner";

    command -v "${cmd}" >/dev/null 2>&1;
    _ifErr "'${cmd}' is not installed";

    find . -type f -name "*.svg" -exec "${cmd}" {} {} &>/dev/null \;;
    _ifErr "Failed to minify images with '${cmd}'";
};

_CreateThemes() {

    local color;
    local name;

    for color in "${!THEMES[@]}"; do
        name="${A}-${color}";

        echo "  ${name}...";

        _cpHard "${THEME_DEFAULT}" "${name}";
        _ifErr "Failed to copy '${THEME_DEFAULT}' to '${name}'";

        _nameTheme "${name}";
        _ifErr "Failed to name theme '${name}'";
    done;
};

_nameTheme() {
    local -r name="${1}";
    sed -i "s/Name=.*/Name=${name}/" "${name}/index.theme";
};

_ColorizeThemes() {

    local -r successTmp="#4caf51";
    local -r successDefault="green"; # #4CAF50
    local color;
    local isSuccessSame;
    local name;
    local success;

    for color in "${!THEMES[@]}"; do
        isSuccessSame="${THEMES[$color]}";
        name="${A}-${color}";
        success="${successDefault}";
        [ "${isSuccessSame}" -eq 1 ] && success="${color}";

        echo "  ${name}...";

        _colorize "green" "${color}" "${name}" "${name}";
        _ifErr "Failed to colorize '${name}'";

        _colorize '#4caf50' "${color}" "${name}" "${name}"; # todo: add `-i` flag to `svg-edit`
        _ifErr "Failed to colorize '${name}'";

        _colorize "${successTmp}" "${success}" "${name}" "${name}";
        _ifErr "Failed to colorize '${name}'";
    done;
};

# Run the `svg-edit` binary
#   to colorize all svg images under the specified directory.
# Change color $1 to color $2,
#   for all svg images under directory $3,
#   and place the edited images in directory $4.
_colorize() {
    local colOld="${1}";
    local colNew="${2}";
    local dirOld="${3}";
    local dirNew="${4}";

    ../svg-edit -r -Q -o "${colOld}" -n "${colNew}" "${dirOld}" "${dirNew}";
};

_UpdateCache() {

    local color;
    local name;

    for color in "${!THEMES[@]}"; do
        name="${A}-${color}";

        echo "  ${name}...";

        gtk-update-icon-cache -ftq "${name}";
        _ifErr "Failed to update icon cache for '${name}'";
    done;
};

# Make a highly compressed xz archive of the icon theme.
#   The xz archive is 10-15% the size of the uncompressed files.
_Package() {

    local xz="${PKGNAME}.tar.xz";

    [ -e "${xz}" ] && rm "${xz}";

    ./xzz "${PKGNAME}";
    _ifErr "Failed to compress '${PKGNAME}'";

    _Archive "${xz}" "bak";
    _ifErr "Failed to archive '${xz}'";
};

_Archive() {

    local src="${1}";
    local dst="${2}";

    local name="${src%%.*}";
    local ext="${src#*.}";

    dst="${dst}/${name}_$(date +%Y-%m-%d).${ext}";

    cp -f "${src}" "${dst}";
};

# Add a new commit for any repo changes.
# Don't push (yet).
_Commit() {
    _gitCommit;
    echo "Done.";
};

_gitCommit() {

    git add .;
    _ifErr "Failed to stage files for git";

    if [ -n "${COMMIT}" ]; then
        git commit -m "${COMMIT}";
    else
        git commit;
    fi;
    _ifErr "No commit received";
};

# Update and upload the package to both git and the AUR.
_Upload() {

    COMMIT="$(git log -n1 --pretty=format:'%s')";
    PKGVER=$(_gitVer);
    LAST_COMMIT=$(_lastCommit);
    CHECKSUM_LOCAL="$(md5sum "${PKGNAME}.tar.xz")";
    CHECKSUM_LOCAL="${CHECKSUM_LOCAL%  *}";

    _glecho "Updating remote repo...";
    _gitPush;
    echo "Done.";

    _glecho "Waiting 10 seconds for GitHub to update...";
    _pause 2;
    echo "Done.";

    _glecho "Updating '${PKGNAME}'...";
    _UpdateAur;
    echo "Done.";

    _glecho "Updating '${PKGNAME_GIT}'...";
    _UpdateAurGit;
    echo "Done.";
};

_gitVer() {
    ( set -o pipefail;
      git describe --long --tags 2>/dev/null | sed 's/\([^-]*-g\)/r\1/;s/-/./g' ||
        printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)";
    );
};

_gitPush() {
    git push origin master;
    _ifErr "Failed to push to github";
};

_pause() {

    local -i seconds="${1}";
    local -i i;

    for i in $(seq 1 "${seconds}"); do
        printf "\r  %d/%d" "${i}" "${seconds}";
        sleep 1;
    done;
    printf "\n";
};

_UpdateAur() {

    _q pushd "${PKGDIR}";

    _pkgbuildAur;

    ../../aur4 "${COMMIT}";
    _ifErr "Failed to update '${PKGNAME}'";

    _q popd;
};

_pkgbuildAur() {

    local -r repo="https://raw.githubusercontent.com/GreenRaccoon23/${PKGNAME}";
    local -r xz="${repo}/"${LAST_COMMIT}"/${PKGNAME}.tar.xz";
    local -r checksum=$(_md5sumRemote "${xz}");
    [ "${checksum}" != "${CHECKSUM_LOCAL}" ] && _err "Local and remote checksums do not match";

    sed -i "s/pkgver=.*/pkgver=${PKGVER}/" PKGBUILD;
    _ifErr "Failed to update pkgver for '${PKGNAME}'";

    sed -i "s/_commit=.*/_commit=\"${LAST_COMMIT}\"/" PKGBUILD;
    _ifErr "Failed to update _commit for '${PKGNAME}'";

    sed -i "s/md5sums=.*/md5sums=(\"${checksum}\")/" PKGBUILD;
    _ifErr "Failed to update md5sums for '${PKGNAME}'";
};

_md5sumRemote() {

    local remote="${1}";
    local httpStatus;
    local checksum;

    httpStatus="$(curl -LI "${remote}" 2>/dev/null | head -n 1 | cut -d$' ' -f2)";
    [ "${httpStatus}" != 200 ] && _err "'${remote}' does not exist";

    checksum=$(curl -s "${remote}" | md5sum);
    _ifErr "Failed to get md5sum of '${remote}'";

    echo "${checksum%  *}";
};

_lastCommit() {
    git log --pretty=format:'%H' | head -n 1;
};

_UpdateAurGit() {

    _q pushd "${PKGDIR_GIT}";

    _pkgbuildAurGit;

    ../../aur4 "${COMMIT}";
    _ifErr "Failed to update '${PKGNAME_GIT}'";

    _q popd;
};

_pkgbuildAurGit() {
    sed -i "s/pkgver=.*/pkgver=${PKGVER}/" PKGBUILD;
    _ifErr "Failed to update pkgver for '${PKGNAME_GIT}'";
};

_AurUpdate() {
    local -ar Aurs=(
        "aur/archdroid-icon-theme"
        "aur-git/archdroid-icon-theme-git"
    );

    local dir;
    for dir in "${Aurs[@]}"; do
        _q pushd "${dir}";
        ../../aur4 "$@";
        _q popd;
    done;
};

# Set console color.
_c() {
    tput sgr0;
    (($# == 0)) && return 0;

    local -A Codes=(
        ["black"]="0" ["red"]="1" ["green"]="2" ["yellow"]="3"
        ["blue"]="4" ["magenta"]="5" ["cyan"]="6" ["white"]="7"
        ["bk"]="0" ["r"]="1" ["g"]="2" ["y"]="3"
        ["bu"]="4" ["m"]="5" ["c"]="6" ["w"]="7"
    );

    local k c;
    for k in "${!Codes[@]}"; do
        if [[ "${k}" != "${1}" ]]; then
            continue;
        fi;
        c="${Codes["$k"]}";
    done;

    [ "${c}" ] && tput setaf "${c}";
};

# Set bold console color.
_C() {
    (($# > 0)) && _c "${1}";
    tput bold;
};

# Reset console color to normal.
_u() {
    tput sgr0;
};

# Print any number of messages in bold green.
_gecho() {
    _C green
    for line; do
        echo "${line}";
    done;
    _u;
};

# Print a message in bold green WITHOUT appending a new line.
_gprint() {
    _C green
    printf "%s" "$*";
    _u;
};

# Print a line break.
# Optionally, run a command first in order to colorize it.
_line() {
    if (($# > 0)); then
        eval "$@";
    fi;

    printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' =;

    if (($# > 0)); then
        _u;
    fi;
};

# Print a bold white line break,
#   followed by any number of messages in bold green.
_glecho() {
    _line _C white;

    _C green;
    local m;
    for m; do
        echo "${m}";
    done;

    _u;
};

# Print any number of messages, indenting each by two spaces.
_specho() {
    local m;
    for m; do
        printf '  ';
        echo "${m}";
    done;
};

# Print green raccoon ASCII image.
_gr23() {
    local -ar raccoon=(
        '         ///////                             //////'
        '       /////   ///                         //     /// '
        '      ///   ##### //                      //  #####  //'
        '     //  ########## //                    /    ######  /'
        '    ///  ########### /    //////////////////////  ####  /'
        '    ///  #########    ////////////////////////////  #   //'
        '     ///    #  //////////////////////////////////////  //'
        '            /////////////////////////////////////////'
        '          /////////////////////////////////////////////'
        '        //////////////////////  /////////////  |||     /'
        '      /////////////////     ||||   ////////  ||||||||||'
        '     ////////////////  |||||||||||  //////  ||   ||||||||'
        '    //////////////   |||||||   ||||  //////  || ||||||||||'
        '   ////////////// ||||||||||  |||||  ///////  ||||||||||||'
        '  ////////////   |||||||||||||||||  ///////////  |||||||||'
        ' ////////////  ||||||||||||||||||  ////////////// ||||||||'
        '    ////////  ||||||||||||||||||| ////////////////  |||||'
        '    /////// |||||||||||||||||||  ////////    $$$  // ||'
        '       ///  ||||||||||||||||||  //////// $$$$$$$  ///'
        '           ||||||||||||||||||  ///////////       ///'
        '              ||||||||||||||  ////////////////////'
        '                      ||||||  ///////////////////'
        '                                     ////////'
    );

    _gecho "${raccoon[@]}";
};

# Run a command silently.
_q() {
    eval "$@" >/dev/null;
};

_err() {
    local msg="${1}";
    local code="${2}";
    [ -z "${code}" ] && code=1;
    _c red;
    >&2 echo "${1}";
    _u;
    exit "${code}";
};

_ifErr() {
    local msg="${1}";
    [ $? -ne 0 ] && _err "${msg}" $?;
};

# Ask user to answer a "yes or no" question.
# Analyse the user's answer, with NO as the default.
_yN() {
    local ans;
    read -p "$* [y/N]: " ans;

    case "${ans}" in [yY] | [yY][eE][sS])
        return 0;;
    esac;
    return 1;
};

# Ask user to answer a "yes or no" question.
# Analyse the user's answer, with YES as the default.
_Yn() {
    local ans;
    read -p "$* [Y/n]: " ans;

    case "${ans}" in [nN] | [nN][oO])
        return 1;;
    esac;
    return 0;
};

# Trim the suffix of a string.
_trSfx() {
    echo "${1%${2}*}";
};

# Trim the prefix of a string.
_trPfx() {
    echo "${1#*${2}}";
};

# Remove file or directory if it exists.
_rm() {
    local filepath="${1}";
    if [ -d "${filepath}" ]; then
        rm -R "${filepath}";
    elif [ -e "${filepath}" ]; then
        rm "${filepath}";
    else
        return 0;
    fi;
};

_cpHard() {

    local orig="${1}";
    local copy="${2}";

    [ -d "${copy}" ] && _rm "${copy}";

    cp -a "${orig}" "${copy}";
};

_main;
