#!/bin/bash
#########################################################
#                                                       #
# This is BashStyle-NG                                  #
#                                                       #
# Licensed under GNU GENERAL PUBLIC LICENSE v3          #
#                                                       #
# Copyright Christopher Roy Bratušek                    #
#                                                       #
#########################################################

##############################
# Setup
##############################
shopt -s extglob
TOP_PID=$$

CWD=$(dirname "$(readlink -m "${BASH_SOURCE[0]}")")

MK_VERSION=3.0.0
source "${CWD}/.settings"

##############################
# Color Settings
##############################
set_colors () {
    RED="\033[01;31m"
    GREEN="\033[01;32m"
    YELLOW="\033[01;33m"
    BLUE="\033[01;34m"
    MAGENTA="\033[01;35m"
    CYAN="\033[01;36m"
    WHITE="\033[01;37m"

    case ${TERM} in
        *xterm*color )
            ORANGE="\033[01;38;5;202m"
            SILVER="\033[01;38;5;246m"
        ;;
        * )
            ORANGE=${YELLOW}
            SILVER=${WHITE}
        ;;
    esac
}

set_colors

##############################
# Screen messages
##############################
help_message () {
    echo -e "\n${GREEN}${APP_NAME} ${MAGENTA}v${APP_VERSION}${WHITE} /${YELLOW} Make v${MK_VERSION} ${CYAN}help
    \n${WHITE}Rules:"

    echo -e "   ${ORANGE}help${WHITE} *|${GREEN} Display this help message
    ${ORANGE}pot${WHITE} *|${GREEN} Generate .pot files
    ${ORANGE}po${WHITE} *|${GREEN} Update .po files
    ${ORANGE}info${WHITE} *|${GREEN} Generate Info documentation
    ${ORANGE}html${WHITE} *|${GREEN} Generate HTML documentation
    ${ORANGE}news${WHITE} *|${GREEN} Generate NEWS file
    ${ORANGE}build${WHITE} *|${GREEN} Build necessary files
    ${ORANGE}install${WHITE} *|${GREEN} Install ${APP_NAME}
    ${ORANGE}remove${WHITE} *|${GREEN} Remove ${APP_NAME}
    ${ORANGE}clean${WHITE} *|${GREEN} Clean build directory" | column -t -s \*
    echo
    tput sgr0

    exit 0
}

run_configure_message () {
    echo -e "\n${RED}You need to run './configure' first!\n"
}

run_make_build_message () {
    echo -e "\n${RED}You need to run './make build' first!\n"
}

check_root_message () {
    echo -e "\n${RED}You need to be root to ${1} ${APP_NAME}\n"
}

build_message () {
    echo -e "\n${WHITE}Building ${GREEN}${APP_NAME}${YELLOW} v${APP_VERSION} ${CYAN}${CODENAME}\n"
}

build_end_message () {
    echo -e "\n${WHITE}You may want to continue with 'sudo ./make install'.\n"
}

install_message () {
    echo -e "\n${GREEN}Installing ${BLUE}${APP_NAME}${YELLOW} v${APP_VERSION} ${CYAN}${CODENAME}\n"
}

remove_message () {
    echo -e "\n${RED}Removing ${BLUE}${APP_NAME}${YELLOW} v${APP_VERSION} ${CYAN}${CODENAME}\n"
}

clean_message () {
    echo -e "\n${RED}Cleaning Up ${BLUE}${APP_NAME}${YELLOW} v${APP_VERSION} ${CYAN}${CODENAME}\n"
}

post_install_message () {
    echo -e "\t${WHITE}+${BLUE} post-installation tasks"
}

thanks_message () {
    echo -e "\n${SILVER}Thanks for using ${GREEN}${APP_NAME}!\n"
}

##############################
# Load configure results
##############################

[[ $# -eq 0 ]] && help_message

case ${1} in
    pot | po | build | install | remove )
        if [[ ! -f "${CWD}/.configure_results" ]]; then
            run_configure_message
            kill -s TERM "${TOP_PID}"
        else    source "${CWD}/.configure_results"
        fi
    ;;
esac

##############################
# Filelist: clean
##############################
CLEAN_FILES=(data/bashstyle data/bashstyle-config-helper
     ui/bashstyle.ui.h rc/bashstyle-rc i18n/??/*.mo i18n/*.pot
     .configure_results .make/build_done ui/#bashstyle.ui#
     ui/bashstyle.ui~ doc/bashstyle.info doc/*.gz .build_done)

CLEAN_DIRS=(doc/html)

##############################
# Filelist: install
##############################
shopt -s nullglob

DATA_FILES=(
    "${CWD}/data/bashstyle-ng.ini:${DATADIR}"
    "${CWD}/data/bashstyle-ng.desktop:${DESKTOPDIR}"
    "${CWD}/rc/bashstyle-rc:${DATADIR}/rc"
)

for ui in "${CWD}/ui"/*.py "${CWD}/ui"/*.ui; do
    DATA_FILES+=("${ui}:${DATADIR}/ui")
done

for rc in "${CWD}/rc"/*_* ; do
    DATA_FILES+=("${rc}:${DATADIR}/rc")
done

for html in "${CWD}/doc/html"/*.html; do
    DOC_FILES+=("${html}:${DOCDIR}")
done

for screenshot in "${CWD}/doc/screenshots"/*.png; do
    DOC_FILES+=("${screenshot}:${SCREENSHOTDIR}")
done

MAN_FILES=("${CWD}/doc/bashstyle.1:${MANDIR}")

for lang in "${APP_LANGUAGES}"; do
    LOCALE_FILES+=(
        "${CWD}/i18n/${lang}/bashstyle.mo:${LOCALEDIR}/${lang}/LC_MESSAGES"
        "${CWD}/i18n/${lang}/bashstyle-rc.mo:${LOCALEDIR}/${lang}/LC_MESSAGES"
    )
done

BIN_FILES=(
    "${CWD}/data/bashstyle:${BINDIR}"
    "${CWD}/data/bashstyle-config-helper:${BINDIR}"
)

for util in "${CWD}/utils"/*; do
    BIN_FILES+=("${util}:${BINDIR}")
done

for icon in "${CWD}/data/icons"/*.png; do
    ICON_FILES+=("${icon}:${ICONDIR}")
done

PC_FILES=()

shopt -u nullglob

##############################
# Filelist: remove
##############################
shopt -s nullglob

for lang in ${APP_LANGUAGES}; do
    LOCALE_REMOVE+=(
        "${LOCALEDIR}/${lang}/bashstyle.mo"
        "${LOCALEDIR}/${lang}/bashstyle-rc.mo"
    )
done

for util in "${CWD}/utils"/*; do
    BIN_REMOVE+=("${BINDIR}/${util##*/}")
done

for icon in "${CWD}/data/icons"/*.png; do
    ICON_REMOVE+=("${ICONDIR}/${icon##*/}")
done

REMOVE_FILES=(
    "${LOCALE_REMOVE[@]}"
    "${BINDIR}/bashstyle"
    "${BINDIR}/bashstyle-config-helper"
    "${BIN_REMOVE[@]}"
    "${ICON_REMOVE[@]}"
    "${MANDIR}/bashstyle.1"
    "${DESKTOPDIR}/bashstyle-ng.desktop"
    "${DATADIR}"
    "${DOCDIR}"
)

shopt -u nullglob

##############################
# Checks
##############################
check_built () {
    if [[ ! -f "${CWD}/.build_done" ]]; then
        run_make_build_message
        kill -s TERM "${TOP_PID}"
    fi
}

check_root () {
    if (( EUID != 0 )); then
        if [ -n "${DPKG_MAINTSCRIPT_PACKAGE}" ] || [ -n "${DEB_BUILD_ARCH}" ]; then
            return 0
        else
            check_root_message "${1}"
            kill -s TERM "${TOP_PID}"
        fi
    fi
}

##############################
# Build Actions
##############################
build_news () {
    echo -e "\t${WHITE}+${CYAN} NEWS file"

    makeinfo --no-validate --no-headers "${CWD}/doc/news.texi" > NEWS || kill -s TERM "${TOP_PID}"
}

build_readme () {
    echo -e "\t${WHITE}+${CYAN} README file"

    makeinfo -I "${CWD}/doc" --html --no-split --no-headers - -o README.tmp <<< "@settitle BashStyle-NG
    $(cat "${CWD}/doc/userdoc_introduction.texi")" || kill -s TERM "${TOP_PID}"
    pandoc -f html -t gfm README.tmp -o README.md || kill -s TERM "${TOP_PID}"
    sed -e "s,src=\"screenshots,src=\"doc/screenshots,g" -i README.md
    rm -f README.tmp
}

build_doc_info () {
    echo -e "\t${WHITE}+${CYAN} Info documentation"
    makeinfo -I "${CWD}/doc/" "${CWD}/doc/userdoc.texi" -o "${CWD}/doc/bashstyle.info" || kill -s TERM "${TOP_PID}"
}

build_doc_html () {
    echo -e "\t${WHITE}+${CYAN} HTML documentation"
    makeinfo -I "${CWD}/doc/" --html "${CWD}/doc/userdoc.texi" -o "${CWD}/doc/html" || kill -s TERM "${TOP_PID}"
}

gzip_man () {
    echo -e "\t${WHITE}+${CYAN} compressing manpages"
    for manpage in "${MAN_FILES[@]}"; do
        src_file="${manpage%%:*}"
        gzip -c "$src_file" > "${src_file}.gz" || kill -s TERM "${TOP_PID}"
    done
}

generate_pot () {
    echo -e "\t${WHITE}+${CYAN} translation templates"
    echo -e "\t${WHITE}  *${YELLOW} bashstyle.pot"
    intltool-extract --type=gettext/glade "ui/bashstyle.ui" >/dev/null
    xgettext -L python --from-code=utf-8 --keyword=_ --keyword=N_ \
        --output="${CWD}/i18n/bashstyle.pot" \
        "${CWD}/ui"/*.py "${CWD}/ui/bashstyle.ui.h" >/dev/null \
        || kill -s TERM "${TOP_PID}"

    echo -e "\t${WHITE}  *${YELLOW} bashstyle-rc.pot"
    shopt -s nullglob
    rc_sources=(
        "${CWD}/rc/bashstyle-rc"
        "${CWD}/rc"/settings_*
        "${CWD}"/utils/*
        "${CWD}/rc"/function_*
    )
    shopt -u nullglob

    if (( ${#rc_sources[@]} > 0 )); then
        xgettext -o "${CWD}/i18n/bashstyle-rc.pot" -L shell --from-code=utf-8 \
            "${rc_sources[@]}" 2>/dev/null || kill -s TERM "${TOP_PID}"
    fi
}

update_po () {
    if [[ ! -f ${CWD}/i18n/bashstyle.pot || ! -f ${CWD}/i18n/bashstyle-rc.pot ]]; then
        echo -e "\n${RED}You need to run './make pot' first!\n"
        kill -s TERM "${TOP_PID}"
    fi

    echo -e "\t${WHITE}+${CYAN} translations"

    for lang in ${APP_LANGUAGES}; do
        echo -e "\t${WHITE} *${MAGENTA} ${lang}"

        msgmerge -q -o "i18n/${lang}/bashstyle.po" "i18n/${lang}/bashstyle.po" \
            "i18n/bashstyle.pot" >/dev/null || kill -s TERM "${TOP_PID}"

        msgmerge -q -o "i18n/${lang}/bashstyle-rc.po" "i18n/${lang}/bashstyle-rc.po" \
            "i18n/bashstyle-rc.pot" >/dev/null || kill -s TERM "${TOP_PID}"
    done
}

generate_mo () {
    echo -e "\t${WHITE}+${CYAN} translations"
    local lang

    for lang in ${APP_LANGUAGES}; do
        echo -e "\t${WHITE} *${MAGENTA} ${lang}"

        msgfmt --output-file="${CWD}/i18n/${lang}/bashstyle.mo" \
            "${CWD}/i18n/${lang}/bashstyle.po" || kill -s TERM "${TOP_PID}"

        msgfmt --output-file="${CWD}/i18n/${lang}/bashstyle-rc.mo" \
            "${CWD}/i18n/${lang}/bashstyle-rc.po" || kill -s TERM "${TOP_PID}"
    done
}

##############################
# Install Actions
##############################
post_install () {
    if (( DISABLE_POSTINSTALL != 1 )); then
        post_install_message
        gtk4-update-icon-cache -q -f "${PREFIX}/share/icons/hicolor"
    fi
}

post_remove () {
    if (( DISABLE_POSTINSTALL != 1 )); then
        gtk4-update-icon-cache -q -f "${PREFIX}/share/icons/hicolor"
    fi
}

installdirs_create ()
{
    echo -e "\t${WHITE}+${MAGENTA} directories"
    mkdir -p "${DESTDIR}/${DATADIR}"
    for directory in "${DATADIR_LIST[@]}"; do
        mkdir -p "${DESTDIR}/${DATADIR}/${directory}"
    done

    mkdir -p "${DESTDIR}/${LOCALEDIR}"
    for directory in "${LOCALEDIR_LIST[@]}"; do
        mkdir -p "${DESTDIR}/${LOCALEDIR}/${directory}"
    done

    mkdir -p "${DESTDIR}/${BINDIR}" "${DESTDIR}/${ICONDIR}" \
            "${DESTDIR}/${PCDIR}" "${DESTDIR}/${DESKTOPDIR}" \
            "${DESTDIR}/${MANDIR}" "${DESTDIR}/${DOCDIR}/screenshots"
}

inst ()
{
    local mode="${1}"
    local src_file="${2%%:*}"
    local dest_dir="${2#*:}"
    local filename="${src_file##*/}"

    case ${mode} in
        bin ) install -m755 "${src_file}" "${DESTDIR}${dest_dir}/${filename}" ;;
        man ) install -m644 "${src_file}.gz" "${DESTDIR}${dest_dir}/${filename}.gz" ;;
        *   ) install -m644 "${src_file}" "${DESTDIR}${dest_dir}/${filename}" ;;
    esac
}

install_bsng () {
    echo -e "\t${WHITE}+${YELLOW} data files"
    for file in "${DATA_FILES[@]}" "${LOCALE_FILES[@]}" \
        "${PC_FILES[@]}" "${ICON_FILES[@]}"; do
        inst data "${file}"
    done

    echo -e "\t${WHITE}+${GREEN} executable files"
    for file in "${BIN_FILES[@]}"; do
        inst bin "${file}"
    done

    echo -e "\t${WHITE}+${CYAN} documentation and manual pages"
    for file in "${DOC_FILES[@]}"; do
        inst doc "${file}"
    done

    for file in "${MAN_FILES[@]}"; do
        inst man "${file}"
    done
}

remove_bsng () {
    echo -e "\t${WHITE}+${RED} all files"
    for file in "${REMOVE_FILES[@]}"; do
        rm -rf "${file}"
    done
}

##############################
# Tasks
##############################
make_build () {
    build_message
    generate_mo
    build_doc_html
    gzip_man
    build_end_message
    touch "${CWD}/.build_done"
}

make_install () {
    check_built
    check_root "install"
    install_message
    installdirs_create
    install_bsng
    post_install
    thanks_message
}

make_remove () {
    check_root "remove"
    remove_message
    remove_bsng
    post_remove
}

make_clean () {
    clean_message
    for file in "${CLEAN_FILES[@]}"; do
        rm -f "${file}"
    done

    for dir in "${CLEAN_DIRS[@]}"; do
        rm -rf "${dir}"
    done
}

##############################
# Main Loop
##############################
for opt in "${@}"; do
    case ${opt} in
        clean )     make_clean ;;
        pot )       generate_pot ;;
        po )        update_po ;;
        build )     make_build ;;
        install )   make_install ;;
        remove )    make_remove ;;
        news )      build_news ;;
        readme )    build_readme ;;
        info )      build_doc_info ;;
        html )      build_doc_html ;;
        * )         help_message ;;
    esac
    shift
done

tput sgr0
