#!/bin/bash

SED=sed

#special case for build in ubuntu using bomi ppa
PKG_CONFIG_PATH=/opt/ffmpeg-bomi/lib/pkgconfig:/opt/libass-bomi/lib/pkgconfig:${PKG_CONFIG_PATH}

export PKG_CONFIG_PATH="`pwd`/build/lib/pkgconfig:$PKG_CONFIG_PATH"

arguments="$@"

has_arg() {
    [ -n "`echo $arguments | grep "$1"`" ]
}

qtsdk=
kern=`uname -s`
njobs=
mpv_args=
os=
win=
mkspec=
if [ "$kern" = "Darwin" ]; then
    os="osx"
    mpv_args="$mpv_args --enable-coreaudio --enable-vda-hwaccel" #
    njobs=`sysctl hw.ncpu | awk '{print $2}'`
    mkspec=macx-clang
    echo "configure for OS X..."
elif [ "$kern" = "Linux" ]; then
    os="linux"
    mpv_args="$mpv_args --enable-alsa --enable-oss-audio"
    njobs=$(nproc)
    echo "configure for Linux..."
elif [[ "$kern" = MINGW* ]]; then
    os="win"
    mpv_args="$mpv_args --enable-dsound --enable-wasapi --enable-dxva2-hwaccel"
    njobs=$(nproc)
    mkspec=win32-g++
	if [[ "$kern" = MINGW64* ]]; then
        win=64
	elif [[ "$kern" = MINGW32* ]]; then
        win=32
	else
        echo "Not supported!"
        exit
	fi
    echo "configure for Windows ${win}bit..."
else
    echo "Not supported!"
    exit
fi

argument_line=
option_line=
key_max_cols=22

parse_for_key() {
    local key=`echo $1 | cut -d "=" -sf1`
    if [ -z "$key" ]; then
        echo $1
    else
        echo $key
    fi
}
parse_for_value() {
    echo `echo $1 | cut -d "=" -sf2`
}

get_option_field() {
    echo `echo $option_line | cut -d "|" -sf $1`
}

get_option_name() {
    echo $(parse_for_key $(get_option_field $f_key))
}

get_feature_name() {
    local name=$1
    if ! [ $name ]; then name=$(get_option_name); fi 
    echo `echo $name | cut -d '-' -sf 4`
}

loop_options() {
    while read line; do
        option_line=$line
        "${@:2}"
    done <<-heredoc
        $1
heredoc
}

print_help_option_one() {
    local key=$(get_option_field $f_key)
    if [ -z "$key" ]; then continue; fi
    local def=$(get_option_field $f_def)
    if [ -z "$def" ]; then 
        printf "  %-${key_max_cols}s %s\n" $key "$(get_option_field $f_help)"
    else
        printf "  %-${key_max_cols}s %s [%s]\n" $key "$(get_option_field $f_help)" "$(get_option_field $f_def)"
    fi
}
print_help_options() {
    printf "$1:\n"
    loop_options "$2" print_help_option_one
    printf "\n"
}
set_option_key_max_cols_one() {
    local key=$(get_option_field $f_key)
    if [ -z "$key" ]; then continue; fi
    if [ $key_max_cols -lt ${#key} ]; then key_max_cols=${#key}; fi
}
print_help() {
    printf "Usage: $0 [OPTIONS]...\n\n"

    loop_options "$options" set_option_key_max_cols_one

    print_help_options "Configuration" "$config_opts"
    print_help_options "Installation directories" "$install_opts"
    print_help_options "Optional features" "$feature_opts"
    exit 0
}


########################################################################################################
########################################################################################################


f_key=1
f_help=2
f_def=3
f_pkg=4

parallel=$njobs
release=
cc=gcc
cxx=g++
qmake=autodetect
lrelease=autodetect
macdeployqt=
defaultskin=

mo() {
    local value=$(eval echo \$$1)
}

config_opts="""
--help|display this help and exit
--cc=COMPILER|C compiler (corresponding C++ compiler will be detected)|$cc
--win=ARCH|32 for 32bit or 64 for 64bit(only Windows)|$win
--qtsdk=QTSDK|directory for Qt SDK|
--qmake=QMAKE|qmake executable|$qmake
--lrelease=LRELEASE|lrelease executable|$lrelease
--mkspec=MKSPEC|make spec for qmake|$mkspec
--macdeployqt=MACDEPLOYQT|macdeployqt executable|QTSDK/bin/macdeployqt
--parallel=JOBS|count of parallel jobs|autodetect:$njobs
--release|optimize for release
--developer|configure for developers
--defaultskin=SKIN|set SKIN as default skin|
"""

config=

detect_qt5() {
    test -n "$(LC_MESSAGES=C "$1" -version 2> /dev/null | grep "version 5.")"
}

check_qt5_or_exit() {
    local var=$1
    local value=$(eval echo \$$var)
    local found=""
    printf "checking for $var ... "
    if [ "$value" = autodetect ]; then
        for q in "$var" "$var-qt5"; do
        if detect_qt5 $q; then
            found=$q
            break
        fi
        done
    elif detect_qt5 "$value"; then
        found="$value"
    fi
    if [ -z "$found" ]; then
        echo "no"
        echo "'$value' failed."
        exit
    else
        declare -g "$var=$found"
        echo "$found"
    fi
}

check_cc() {
    test -n "$("$cc" -dM -E -x c /dev/null 2> /dev/null | grep "$1")"
}

setup_build() {
    if [ -n "$qtsdk" ]; then
        qmake=$qtsdk/bin/qmake
        lrelease=$qtsdk/bin/lrelease
        macdeployqt=$qtsdk/bin/macdeployqt
    fi

    local mk=
    printf "checking for cc ... "
    if check_cc __clang__; then
        mk=linux-clang
        cxx=$(echo $cc | sed 's/clang/clang++/g')
    elif check_cc __GNUC__; then
        mk=linux-g++
        cxx=$(echo $cc | sed 's/gcc/g++/g')
    else
        echo "no"
        echo "'$cc' is not supported."
        exit
    fi
    echo "$cc"

    check_qt5_or_exit qmake
    check_qt5_or_exit lrelease

    if [ -z "$mkspec" ]; then mkspec=$mk; fi
    echo "checking for mkspec ... $mkspec"
    qmake="$qmake -spec $mkspec"
}

prefix=/usr/local
bindir=
datadir=
compdir=
mandir=
icondir=
appdir=
actiondir=
skindir=
importdir=

install_opts="""
--prefix=PREFIX|prefix directory for installation|$prefix
--bindir=BINDIR|directory for executables|PREFIX/bin
--datadir=DATADIR|directory for architecture-indepentent files|PREFIX/share
--compdir=COMPDIR|directory for bash completion files|DATADIR/bash-completion/completions
--mandir=MANDIR|directory for man pages|DATADIR/man
--icondir=ICONDIR|directory for application icons|DATADIR/icons/hicolor
--appdir=APPDIR|directory for application launchers|DATADIR/applications
--actiondir=ACTIONDIR|directory for action launchers|DATADIR/apps/solid/actions
--skindir=SKINDIR|directory for skin files|DATADIR/bomi/skins
--transdir=TRANSDIR|directory for translation files|DATADIR/bomi/translations
--importdir=IMPORTDIR|directory for QML files|DATADIR/bomi/imports
"""

setup_dirs() {
    if [ -z "$prefix"    ]; then exit; fi
    if [ -z "$bindir"    ]; then    bindir=$prefix/bin;                          fi
    if [ -z "$datadir"   ]; then   datadir=$prefix/share;                        fi
    if [ -z "$compdir"   ]; then   compdir=$datadir/bash-completion/completions; fi
    if [ -z "$mandir"    ]; then   mandir=$datadir/man;                          fi
    if [ -z "$icondir"   ]; then   icondir=$datadir/icons/hicolor;               fi
    if [ -z "$appdir"    ]; then    appdir=$datadir/applications;                fi
    if [ -z "$actiondir" ]; then actiondir=$datadir/apps/solid/actions;          fi
    if [ -z "$skindir"   ]; then   skindir=$datadir/bomi/skins;                  fi
    if [ -z "$transdir"  ]; then  transdir=$datadir/bomi/translations;           fi
    if [ -z "$importdir" ]; then importdir=$datadir/bomi/imports;                fi
}

jack=autodetect
pulseaudio=autodetect
cdda=autodetect
systemd=autodetect
samba=autodetect
vdpau=autodetect
vaapi=autodetect

mf() { # make_feature
    local value=$(eval echo \$$1)
    local opt="disable"
    if [ $value = "disable" ]; then opt="enable"
    elif [ $value = "enable" ]; then opt="disable"; fi
    local pkg=$3
    if [ -z "$pkg" ]; then pkg=$1; fi
    echo "--$opt-$1|$2|$value|$pkg"
}

feature_opts="""
$(mf jack "enable JACK support")
$(mf pulseaudio "enable PulseAudio support" "libpulse")
$(mf cdda "enable CDDA support" "libcdio_paranoia libcdio libcdio_cdda")
$(mf samba "enable playing through samba" "smbclient")
$(mf systemd "enable systemd integration" "libsystemd")
$(mf vdpau "enable VDPAU support for harware acceleration" "vdpau")
$(mf vaapi "enable VA-API support for harware acceleration" "libva libva-glx libva-x11")
"""

add_mpv() {
    mpv_args="$mpv_args --$1-$2"
}
setup_features() {
    add_mpv $jack jack
    add_mpv $pulseaudio pulse
    add_mpv $cdda cdda
    add_mpv $samba libsmbclient
    add_mpv $vdpau vdpau
    add_mpv $vdpau vdpau-gl-x11
    add_mpv $vaapi vaapi
    add_mpv $vaapi vaapi-glx
}

options="""
$config_opts
$install_opts
$feature_opts
"""

check_valid_option() {
    arg=$1
    local ok
    local value
    local var
    local key=$(parse_for_key $arg)
    if [ $key = "--help" ]; then print_help; fi
    
    if [ `echo "$key" | grep "^\-\-enable\|disable\-"` ]; then
        while read line; do
            option_line=$line
            local name=$(get_option_name)
            if [ -z "$name" ]; then continue; fi
            if [ $(get_feature_name $key) = $(get_feature_name $name) ]; then
                var=$(echo "$key" | grep "\-\-enable\|disable\-" | sed -E 's/^--(enable|disable)-([a-zA-Z0-9]+)$/\2/g')
                value=$(echo "$key" | grep "\-\-enable\|disable\-" | sed -E 's/^--(enable|disable)-([a-zA-Z0-9]+)$/\1/g')
                ok="ok"
                break;
            fi
        done <<-heredoc
            $feature_opts
heredoc
    else
        while read line; do
            option_line=$line
            local name=$(get_option_name)
            if [ -z $name ]; then continue; fi
            if [ $key = $name ]; then
                var=$(echo "$key" | sed -E 's/^--(.+)$/\1/g')
                value=$(parse_for_value "$arg")
                local ph=$(parse_for_value $(get_option_field $f_key))
                if [ -n "$ph" ]; then
                    if [ -z "$value" ]; then break; fi
                    ok="ok"
                else
                    if [ -n "$value" ]; then break; fi
                    value="yes"
                    ok="ok"
                fi
            fi
        done <<-heredoc
            $config_opts
            $install_opts
heredoc
    fi
    if [ -n "$ok" ]; then
        declare -g "$var=$value"
        true
    else
        echo "'$arg' is not a vaild option."
        print_help
        false
    fi
}

for arg in "$@"; do
    check_valid_option "$arg"
done


########################################################################################################
########################################################################################################


cflags=
libs=

has_pkg() {
    if `pkg-config --exists $1`; then
        true
    else
        false
    fi
}

err_pkg=
check_pkg() {
    err_pkg=""
    printf "Checking for $1 ... "

    local pkgs
    if [ "$#" = 1 ]; then
        if has_pkg "$1"; then
            pkgs="$1"
        else
            err_pkg="$1"
        fi
    else
        for pkg in "${@:2}"; do
            if has_pkg "$pkg"; then
                pkgs="$pkgs $pkg"
            else
                err_pkg="$pkg"
                break
            fi
        done
    fi
    
    if [ -z "$err_pkg" ]; then
        cflags="$cflags `pkg-config --cflags $pkgs`"
        libs="$libs `pkg-config --libs $pkgs`"
        printf "yes\n"
        true
    else
        printf "no\n"
        false
    fi
}

check_pkg_or_exit() {
    if ! check_pkg "$@"; then
        printf "'$err_pkg' package was not found.\n"
        exit
    fi
    true
}

if [ "$os" = "win" ]; then
    export PKG_CONFIG_PATH="/mingw$win/lib/pkgconfig:${PKG_CONFIG_PATH}"
    export PATH="/mingw$win/bin:${PATH}"
    qtsdk="/mingw$win/qt5-static"
fi

if has_arg "developer"; then
    if [ "$os" = "linux" ]; then
        jack=enable
        pulseaudio=enable
        cdda=enable
        vdpau=enable
        vaapi=enable
    elif [ "$os" = "osx" ]; then
        qtsdk=/usr/local/opt/qt5
        macdeployqt=macdeployqt
        qmake=qmake
        export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libass-ct/lib/pkgconfig:${PKG_CONFIG_PATH}"
    fi
    skindir=$(pwd)/src/bomi/skins
    importdir=$(pwd)/src/bomi/imports
    transdir=$(pwd)/src/bomi/translations
fi

check_pkg_or_exit "ffmpeg >= 2.4" "libavformat >= 56.01.0" "libavutil >= 54.02.0" "libavcodec >= 56.1.0" "libswscale >= 2.1.3" "libswresample" "libavfilter"
check_pkg_or_exit "libass >= 0.12.1"
check_pkg_or_exit "dvdread"
check_pkg_or_exit "dvdnav"
check_pkg_or_exit "libbluray"
#check_pkg_or_exit "icu-uc"
check_pkg_or_exit "chardet"
if [ $os = "linux" ]; then
    check_pkg_or_exit glib "glib-2.0" "gobject-2.0"
    check_pkg_or_exit xcb "xcb" "xcb-icccm" "xcb-screensaver" "xcb-randr" "xcb-xtest" "x11"
    check_pkg_or_exit "alsa"
fi

confhpp="src/bomi/configure.hpp"
rm -f "$confhpp"
touch "$confhpp"

add_define() {
    local var=$(echo $1 | tr "[:lower:]" "[:upper:]")
    echo "#define $var $2" >> "$confhpp"
}

check_feature_one() {
    local var=$(get_feature_name)
    local pkg=$(get_option_field $f_pkg)
    local value=$(eval echo \$$var)
    if [ -z $var ]; then continue; fi
    if [ $value = enable ]; then
        check_pkg_or_exit "$pkg"
    elif [ $value = autodetect ]; then
        if check_pkg "$pkg"; then
            value="enable"
            eval $var="enable"
        else
            value="disable"
            eval $var="disable"
        fi
    fi
    if [ $value = enable ]; then
    add_define HAVE_$var 1
    else
    add_define HAVE_$var 0
    fi
}

loop_options "$feature_opts" check_feature_one

setup_dirs
setup_features
setup_build

add_define BOMI_SKINS_PATH "\"$skindir\""
add_define BOMI_IMPORTS_PATH "\"$importdir\""
add_define BOMI_DEFAULT_SKIN "\"$defaultskin\""
add_define BOMI_TRANSLATIONS_PATH "\"$transdir\""
if has_arg release ; then
    add_define BOMI_RELEASE 1
else
    add_define BOMI_RELEASE 0
fi

parse_file() {
    cp $1.in $1
    local var
    local sed="sed -i"
    if [ "$os" = "osx" ]; then sed="sed -i .conf.bk -e"; fi
    for token in "${@:2}"; do
    var=$(eval echo \$$token)
    $sed 's#@'"$token"'@#'"$var"'#g' $1
    done
}

rootdir=`pwd`

cc=$(which $cc)
cxx=$(which $cxx)

parse_file "Makefile" os qmake lrelease PATH PKG_CONFIG_PATH prefix bindir datadir compdir mandir icondir appdir actiondir \
    transdir skindir importdir parallel qtsdk macdeployqt
parse_file "build-mpv" cc mpv_args parallel os njobs PKG_CONFIG_PATH PATH

if [ "$os" = "win" ]; then
    cc=$(echo $cc | sed 's#/mingw#C:/msys64/mingw#g')
    cxx=$(echo $cxx | sed 's#/mingw#C:/msys64/mingw#g')
fi

parse_file "src/bomi/configure.pro" cc cxx config libs cflags rootdir
if [ "$os" = "win" ]; then
    sed -i 's#'"$(pwd)"'#../..#g' "src/bomi/configure.pro"
fi

chmod +x build-mpv

printf "\nbomi has been configured successfully!\n\n"
