#!/bin/bash

#================================================================================
# Инициализация
#================================================================================

# Проверяем права суперпользователя
if [[ $EUID -ne 0 ]]; then
        echo -e "Please run the script as superuser."
        exit 1
fi

# Определяем местоположение скрипта
SCRIPT_PATH=$(dirname "$(readlink -f "$0")")
# Импортируем функции
source $SCRIPT_PATH/ini_reader

WAYDROID_SESSION_CONFIG_PATH='/etc/astra-mobile/astra-mobile-waydroid.ini'

# Интерфейс DBus
EVENTS_INTERFACE='ru.astralinux.events'
# Получаемый сигнал перезапуска контейнера wawdroid
SIGNAL_RESTART_WAYDROID_CONTAINER='waydroid_restart_container'
# Получаемый сигнал перезапуска контейнера и запуска приложения (первый аргумент - имя приложения)
SIGNAL_RESTART_WAYDROID_CONTAINER_AND_LAUNCH='waydroid_restart_container_and_launch'
# Получаемый сигнал установки параметров геометрии окна в конфигурационном файле
# SIGNAL_WAYDROID_CONFIG_SET_WINDOW_GEOMETRY='waydroid_config_set_window_geometry'
# Получаемый сигнал подключения пользоваетльских директорий
SIGNAL_BIND_USER_HOME_DIRS='waydroid_bind_user_home_dirs'

# Отправляемый сигнал запуска сессии waydroid
SIGNAL_WAYDROID_START_SESSION='waydroid_start_session'
# Отправляемый сигнал запуска сессии waydroid и запуска приложения
SIGNAL_WAYDROID_START_SESSION_AND_LAUNCH='waydroid_start_session_and_launch'


# WAYDROID_CONFIG_PATH='/var/lib/waydroid/waydroid_base.prop'


# Действие завершения чтения сигнала
ACTION_EXIT=0
# Действие чтение сигнала
ACTION_READ_SIGNAL=1
# Действие чтения аргументов сигнала
ACTION_READ_ARGS=2

#================================================================================
# Функции
#================================================================================
## killByPid
## @brief - Функция убъёт процесс и его подпроцессы по pid
## @param $1 - pid
function killByPid() {
    local PID=$1

    if ps -p $PID > /dev/null 2>&1; then
        for subPID in `ps -ef| awk '$3 == '${PID}' { print $2 }'`
        do
            kill -9 $subPID
        done
        kill -9 $PID
    fi
}

## killByPidFile
## @brief - Функция убъёт процесс по pid из файла
## @param $1 - Путь к файлу
function killByPidFile() {
    local PID_FILE_PATH="$1"

    if [ -f "$PID_FILE_PATH" ]; then
        local PID=$(cat "$PID_FILE_PATH")

        killByPid $PID
        rm "$PID_FILE_PATH"
    fi
}

## isWaydroidRestartSignal
## @brief - Функция проверит является ли строка сигналом перезапуска контейнера waydroid
## @param $1 - Проверяемая строка
## @return Вернёт признак получения сигнала перезапуска контейнера waydroid
function isWaydroidRestartSignal() {
    local SIGNAL="$1"
    [[ $line == *"member=$SIGNAL_RESTART_WAYDROID_CONTAINER"* ]]
}

## isWaydroidRestartAndLaunchSignal
## @brief - Функция проверит является ли строка сигналом перезапуска контейнера waydroid и запуска приложения
## @param $1 - Проверяемая строка
## @return Вернёт признак получения сигнала перезапуска контейнера waydroid и запуска приложения
function isWaydroidRestartAndLaunchSignal() {
    local SIGNAL="$1"
    [[ $line == *"member=$SIGNAL_RESTART_WAYDROID_CONTAINER_AND_LAUNCH"* ]]
}

## isWaydroidConfigSetWindowGeometrySignal
## @brief - Функция проверит является ли строка сигналом установки геометрии окна waydroid
## @param $1 - Проверяемая строка
## @return Вернёт признак получения сигналом установки геометрии окна waydroid
# function isWaydroidConfigSetWindowGeometrySignal() {
#     local SIGNAL="$1"
#     [[ "$SIGNAL" == *"member=$SIGNAL_WAYDROID_CONFIG_SET_WINDOW_GEOMETRY"* ]]
# }

## isWaydroidBindUserHomeDirsSignal
## @brief - Функция проверит является ли строка сигналом подключения пользовательских директорий
## @param $1 - Проверяемая строка
## @return Вернёт признак получения сигналом подключения пользовательских директорий
function isWaydroidBindUserHomeDirsSignal() {
    local SIGNAL="$1"
    [[ "$SIGNAL" == *"member=$SIGNAL_BIND_USER_HOME_DIRS"* ]]
}

## getArg
## @brief - Функция извлечёт значение аргумента DBus
## @param $1 - Аргумент в формате DBus
## @return Вернёт значение аргумента
function getArg() {
    local ARG_LINE="$1"
    local out_arg=''

    local regex='string "(.*?)"'
    # Если строка включает соответствие шаблону
    if [[ $line =~ $regex ]]; then
        # Читаем строку
        out_arg="${BASH_REMATCH[1]}"
    else
        # Читаем нечто отличное от строки
        local regex='^.* (.*)'
        if [[ $line =~ $regex ]]; then
            out_arg="${BASH_REMATCH[1]}"
        fi
    fi

    echo "$out_arg"
}

## waitSignal
## @brief - Функция ожидающая сигнал DBus
## @param $1 - Возвращаемое имя сигнала
## @param $2 - Возвращаемый список аргументов сигнала
## @return Вернёт имя полученного сигнала
function waitSignal() {
    declare -n OUT_SIGNAL_NAME=$1
    declare -n OUT_ARGS=$2

    local action=$ACTION_READ_SIGNAL
    local args_count=0
    # Построчно читаем данные с DBus
    while IFS= read -ru3 line || [ -n "$line" ]; do
        case $action in
        # Режим ожидания сигнала
        $ACTION_READ_SIGNAL)
            if $(isWaydroidRestartAndLaunchSignal "$line"); then
                OUT_SIGNAL_NAME="$SIGNAL_RESTART_WAYDROID_CONTAINER_AND_LAUNCH"
                args_count=1
                action=$ACTION_READ_ARGS
            elif $(isWaydroidRestartSignal "$line"); then
                OUT_SIGNAL_NAME="$SIGNAL_RESTART_WAYDROID_CONTAINER"
                args_count=0
                action=$ACTION_EXIT;
#             elif $(isWaydroidConfigSetWindowGeometrySignal "$line"); then
#                 OUT_SIGNAL_NAME="$SIGNAL_WAYDROID_CONFIG_SET_WINDOW_GEOMETRY"
#                 args_count=2
#                 action=$ACTION_READ_ARGS
            elif $(isWaydroidBindUserHomeDirsSignal "$line"); then
                OUT_SIGNAL_NAME="$SIGNAL_BIND_USER_HOME_DIRS"
                args_count=2
                action=$ACTION_READ_ARGS
            fi

            # Если ни один из сигналов то продолжим чтение
            ;;
        # Режим чтения аргументов сигнала
        $ACTION_READ_ARGS)
            OUT_ARGS[${#OUT_ARGS[*]}]=$(getArg "$line")
            args_count=$((args_count-1))
            if [ $args_count -le 0 ]; then action=$ACTION_EXIT; fi
            ;;
        # Что-то пошло не так
        *)
            action=$ACTION_EXIT;
            ;;
        esac

        # Завершаем чтение
        if [ "$action" = "$ACTION_EXIT" ]; then
            break;
        fi
    done 3< <(
        dbus-monitor --system "interface=$EVENTS_INTERFACE"
    )
}

## waydroidRestartContainer
## @brief - Функция перезапустит контейнер waydroid
function waydroidRestartContainer() {
    waydroid session stop
    systemctl restart waydroid-container
#     echo `date` > /tmp/waydroid-session
}

## waydroidStartSession
## @brief - Функция запустит сессию waydroid
function waydroidStartSession() {
    dbus-send --system --type=signal / $EVENTS_INTERFACE.$SIGNAL_WAYDROID_START_SESSION
}

## waydroidStartSessionAndLaunchApp
## @brief - Функция запустит сессию waydroid
function waydroidStartSessionAndLaunchApp() {
    local APP_NAME="$1"
    dbus-send --system --type=signal / $EVENTS_INTERFACE.$SIGNAL_WAYDROID_START_SESSION_AND_LAUNCH string:"$APP_NAME"
}

## waydroidConfigSetWindowGeometry
## @brief - Функция запустит сессию waydroid
# function waydroidConfigSetWindowGeometry() {
#     local WIDTH="$1"
#     local HEIGHT="$2"
#
#     if [ ! -d "$(dirname $WAYDROID_CONFIG_PATH)" ]; then mkdir -p "$(dirname $WAYDROID_CONFIG_PATH)"; fi
#     if [ ! -f "$WAYDROID_CONFIG_PATH" ]; then touch "$WAYDROID_CONFIG_PATH"; fi
#
#     if grep -q 'persist.waydroid.width' "$WAYDROID_CONFIG_PATH"; then
#         sed -i "s/^persist.waydroid.width=.*/persist.waydroid.width=$WIDTH/g" "$WAYDROID_CONFIG_PATH"
#     else
#         echo "persist.waydroid.width=$WIDTH" >> "$WAYDROID_CONFIG_PATH"
#     fi
#
#     if grep -q 'persist.waydroid.height' "$WAYDROID_CONFIG_PATH"; then
#         sed -i "s/^persist.waydroid.height=.*/persist.waydroid.height=$HEIGHT/g" "$WAYDROID_CONFIG_PATH"
#     else
#         echo "persist.waydroid.height=$HEIGHT" >> "$WAYDROID_CONFIG_PATH"
#     fi
# }

function isWaydroidFSAutoMount() {
    local autoMount=$(iniGetValue "FileSystem" 'autoMountHomeDir' 'true' "$WAYDROID_SESSION_CONFIG_PATH")
    [ "$autoMount" == "true" ]

}

## inotifyAction
## @brief - Функция, обрабатывающая изменения файлов в пользовательской директории waydroid 
## @param $1 - Путь к файлу
function inotifyAction() {
    local filePath="$1"

#    echo "$filePath"
    chmod o+rwx "$filePath"
}

## inotifyRun
## @brief - Функция запустит inotify для пользовательской директории waydroid
## @param $1 - Путь к отслеживаемой директории
function inotifyRun() {
    local WATCH_DIR="$1"

    IFS='
    '
    # Отслеживаем закрытие файлов после записи
    # Получаем вывод в нужном нам формате
    inotifywait -e close_write --format '%e|%w|%f' -m -r "$WATCH_DIR" |\
    (
    while read
    do
        local regex='^([^|]+)\|([^|]+)\|([^|]+)$'

        if [[ $REPLY =~ $regex ]]; then
            local needInotify=0

            for event in $(echo "${BASH_REMATCH[1]}" | sed 's/,/ /g'); do
                case "$event" in
                'CREATE' | 'MODIFY' | 'MOVE' | 'CLOSE_WRITE')
                    needInotify=1
                ;;
#                *)
#                    echo "$event ignored"
#                ;;
                esac
            done

            if [ $needInotify -eq 1 ]; then
                local path="${BASH_REMATCH[2]}"
                local filename="${BASH_REMATCH[3]}"

                inotifyAction "$path/$filename"
            fi
        fi
    done
    )
}


## readyToMount
## @brief - Функция проверит, готова ли fs waydroid к монтированию пользовательских директорий
function readyToMount() {
    if systemctl is-active waydroid-container > /dev/null; then
        [[ -n $(waydroid shell mount | grep '/mnt/user/0/emulated/0/Android/data') ]]
    else
        [[ 1 -eq 0 ]]
    fi
}

## checkIsMount
## @brief - Функция проверит, примонтирован ли указанный путь
## @param $1 - Проверяемый путь
function checkIsMount() {
    mount | awk -v mountedpath="$1" '{if ($3 == mountedpath) { exit 0}} ENDFILE{exit -1}'
    [ $? == 0 ]
}

## bindDir
## @brief - Функция сбиндит указанные директории
## @param $1 - Монтируемая директория
## @param $2 - Директория назначения
function bindDir() {
    local SOURCE="$1"
    local DEST="$2"

    if [[ -d "$SOURCE" && -d "$DEST" ]]; then
        while $(checkIsMount "$DEST"); do umount "$DEST"; done
        mount --bind "$SOURCE" "$DEST"
        chmod o+rwx "$DEST"
    fi
}

## makeAndBindDirDCIM
## @brief - Функция создаст и подключит DCIM директории камеры waydroid
## @param $1 - Домашняя директория пользователя
## @param $2 - Директория данных waydroid
function makeAndBindDirDCIM() {
    local USER_HOME_DIR="$1"
    local WAYDROID_DATA_DIR="$2"

    local dcimSourceDir="$USER_HOME_DIR/Изображения/DCIM"
    local dcimDestDir="$WAYDROID_DATA_DIR/media/0/DCIM"

    local cameraSourceDir="$dcimSourceDir/Camera"
    local cameraDestDir="$dcimDestDir/Camera"

    if [ ! -d "$cameraSourceDir" ]; then
        mkdir -p "$cameraSourceDir"

        local userHomeUser=$(stat -c "%U" "$USER_HOME_DIR")
        local userHomeGroup=$(stat -c "%G" "$USER_HOME_DIR")

        chown -R $userHomeUser:$userHomeGroup "$dcimSourceDir"
    fi

    if [ ! -d "$cameraDestDir" ]; then
        mkdir -p "$cameraDestDir"

        local userHomeUser=$(stat -c "%U" "$WAYDROID_DATA_DIR/media/0")
        local userHomeGroup=$(stat -c "%G" "$WAYDROID_DATA_DIR/media/0")

        chown -R $userHomeUser:$userHomeGroup "$dcimDestDir"
    fi

    bindDir "$cameraSourceDir" "$cameraDestDir"
}

## waitAndBindUserDirs
## @brief - Функция дождётся fs waydroid подключит директории пользователей
## @param $1 - Домашняя директория пользователя
## @param $2 - Директория данных waydroid
function waitAndBindUserDirs() {
    local USER_HOME_DIR="$1"
    local WAYDROID_DATA_DIR="$2"

    chmod o+rwx "$WAYDROID_DATA_DIR"
    chmod o+rwx "$WAYDROID_DATA_DIR/media"
    chmod o+rwx "$WAYDROID_DATA_DIR/media/0"

    local try=30
    while [[ $try -ge 0 ]]
    do
        if $(readyToMount); then
            bindDir "$USER_HOME_DIR/Документы" "$WAYDROID_DATA_DIR/media/0/Documents"
            bindDir "$USER_HOME_DIR/Загрузки" "$WAYDROID_DATA_DIR/media/0/Download"
            bindDir "$USER_HOME_DIR/Музыка" "$WAYDROID_DATA_DIR/media/0/Music"
            bindDir "$USER_HOME_DIR/Изображения" "$WAYDROID_DATA_DIR/media/0/Pictures"
            bindDir "$USER_HOME_DIR/Видео" "$WAYDROID_DATA_DIR/media/0/Movies"

            makeAndBindDirDCIM "$USER_HOME_DIR" "$WAYDROID_DATA_DIR"

            break
        fi

        ((try=try-1))
        sleep 1;
    done

    killByPidFile '/tmp/waydroidinotify.pid'
    inotifyRun "$WAYDROID_DATA_DIR/media/0" &
    echo $! > '/tmp/waydroidinotify.pid'
}

## waydroidBindUserDirs
## @brief - Функция подключит директории пользователей
## @param $1 - Домашняя директория пользователя
## @param $2 - Директория данных waydroid
function waydroidBindUserDirs() {
    local USER_HOME_DIR="$1"
    local WAYDROID_DATA_DIR="$2"

    killByPidFile '/tmp/waydroidmountuserdir.pid'

    if $(isWaydroidFSAutoMount); then
        waitAndBindUserDirs "$USER_HOME_DIR" "$WAYDROID_DATA_DIR" &
        echo $! > '/tmp/waydroidmountuserdir.pid'
    fi
}

## main
## @brief - Первичная функция
function main() {
    while [ 1 ]
    do
        local signal=''
        local args=()
        # Ожидаем сигнал
        waitSignal signal args

        if [ "$signal" = "$SIGNAL_RESTART_WAYDROID_CONTAINER" ]; then
            # Выполняем перезапуск контейнера waydroid
            waydroidRestartContainer
            # Запускаем сессию
            waydroidStartSession
        elif [ "$signal" = "$SIGNAL_RESTART_WAYDROID_CONTAINER_AND_LAUNCH" ]; then
            # Выполняем перезапуск контейнера waydroid
            waydroidRestartContainer
            # Запускаем сессию и приложение
            waydroidStartSessionAndLaunchApp "${args[0]}"
        elif [ "$signal" = "$SIGNAL_WAYDROID_CONFIG_SET_WINDOW_GEOMETRY" ]; then
            # Выполняем изменение геометрии окна в конфигурационном файле
            waydroidConfigSetWindowGeometry "${args[0]}" "${args[1]}"
        elif [ "$signal" = "$SIGNAL_BIND_USER_HOME_DIRS" ]; then
            # Выполняем подключение пользовательских директорий
            waydroidBindUserDirs "${args[0]}" "${args[1]}"
        fi
    done
}

#================================================================================
main
exit 0
#================================================================================
