#!/bin/sh
#
# Copyright (C) 2016 devolo AG
#

#implement config migration mechanism

. $MIGTEST/lib/migration/migration.sh

getCurrentFwVersion() {
    local version="$($UCI_TOOL get delos.delos.version 2>&1)"
    if [ -n "$version" -a -z "$(echo $version | grep "uci")" ];then
        echo "$version"
        return
    fi
    echo "version_not_found"
}


evaluateMigration() {
    local version=$(getCurrentFwVersion)
    local path=""
    if [ "$version" != "version_not_found" ]; then 
        if [ "$version" != "$CURRENT_CONFIG_VERSION" ]; then
            path="$(evaluatePath "$version" "$CURRENT_CONFIG_VERSION")"
            updateMigrationScripts $path
        else
            $LOG_TOOL "Migration: no migration necessary"
            return
        fi
    else
        version="2.0.0"
        path="$(evaluatePath "$version" "$CURRENT_CONFIG_VERSION")"
        updateMigrationScripts $path
    fi

    if [ -z "$path" ]; then
        echo "migration_not_possible"
        $LOG_TOOL "Migration: could not determine up/downgrade path"
    else
        $LOG_TOOL "Migration: migrate from $version to $CURRENT_CONFIG_VERSION" 
        echo "$path"
    fi
}

doMigration() {
    local path=$(evaluateMigration)
    if [ -n "$path" -a "$path" != "migration_not_possible" ]; then
        for step in $path; do
            local scripts=$(find $MIG_BASE/$step -maxdepth 1 -type f -exec basename {} \; |
                        grep -v "$step")
            for script in $scripts; do
                $LOG_TOOL "  call $step/$script"
                $MIG_BASE/$step/$script > /dev/null
                local retCode=$?
                if [ $retCode -ne 0 ]; then
                    echo "migration_not_possible"
                    $LOG_TOOL "Migration: error during migration"
                fi
            done
        done
        migrateVersion
    else
        echo "$path"
    fi
    forceCurrentMigrationScripts
}

migrateVersion() {
    local version=$(getCurrentFwVersion)
    if [ "$version" = "version_not_found" ]; then
        $UCI_TOOL set delos.delos=configuration #creates config configuration 'delos'
    fi
    $UCI_TOOL set delos.delos.version=$CURRENT_CONFIG_VERSION
    $UCI_TOOL commit
}

findPath() {
    local dest="$1"
    local path="$2"

    while true; do
        local newPath=$(getNewPath "$path")
        local unknownElements=""
        for newElem in $newPath; do
            if [ "$(extractTo "$newElem")" = "$dest" ]; then
                cleanupList "$path $newElem"
                return
            else
                if ! isCrossExchangedInList "$newElem" "$path"; then
                    if ! isDuplicate "$newElem" "$path"; then
                        unknownElements="$unknownElements $newElem"
                    fi
                fi
            fi
        done
        if [ -z "$unknownElements" ]; then
            cleanupList "$path"
            return
        fi

        #findPath "$dest" "$path $unknownElements"
	# tail recursion -> loop
        path="$path $unknownElements"
    done
}


cleanupList() {
    echo "$1" | sed -e 's/  */ /g'
}

isDuplicate() {
    local elem="$1"
    local list="$2"
    for item in $list; do
        if [ "$item" = "$elem" ]; then
            return 0
	fi
    done
    return 1
}

isCrossExchange() {
    local elem1="$1"
    local elem2="$2"
    local ef1="$(extractFrom "$elem1")"
    local et1="$(extractTo "$elem1")"
    local ef2="$(extractFrom "$elem2")"
    local et2="$(extractTo "$elem2")"

    if [ $ef1 = $et2 ]; then
        if [ $ef2 = $et1 ]; then
            return 0
        fi
    fi
    return 1
}

isCrossExchangedInList() {
    local elem="$1"
    local list="$2"
    for item in $list; do
        if isCrossExchange "$elem" "$item"; then
            return 0
        fi
    done
    return 1
}

extractFrom() {
    echo "${1%%To*}"
}

extractTo() {
    echo "${1#*To}"
}

getTo() {
    local to=$1
    for mig in $MIG_DIRS; do
        local tov=$(extractTo $mig)
        if [ "$fromv" = "$to" ]; then
            found="$found $mig"
        fi
    done
    echo $found
}
    
getFrom() {
    local from=$1
    for mig in $MIG_DIRS; do
        local fromv=$(extractFrom $mig)
        if [ "$fromv" = "$from" ]; then
            found="$found $mig"
        fi
    done
    echo $found
}

getNewPath() {
    local search="$1"
    local found=""
    for item in $search; do
        for mig in $MIG_DIRS; do
            if [ "$(extractFrom $mig)" = "$(extractTo $item)" ]; then
                found="$found $mig"
            fi
        done
    done
    echo $found
}

evaluatePath() {
    local from="$1"
    local to="$2"
    local simple="$from""To""$to"
    if [ "$from" = "$to" ]; then
        echo ""
        return
    elif [ -n "$(echo "$MIG_DIRS" | fgrep "$simple")" ]; then
        echo $simple
        return
    else
        local firstpath=$(getFrom $from)

        #assume upgrade first, assume related to ascending order
        a=$(echo "$firstpath" | awk -F' ' '{printf $2}')
        path1=$(findPath $to "$a")
        targetPath1=$(extractTo "$(echo $path1 | awk -F' ' '{print $NF}')");
        if [ "$targetPath1" = "$to" ]; then
            echo $path1
            return
        fi
 
        #downgrade
        b=$(echo "$firstpath" | awk -F' ' '{printf $1}')
        path2=$(findPath $to "$b")
        targetPath2=$(extractTo "$(echo $path2 | awk -F' ' '{print $NF}')");
        if [ "$targetPath2" = "$to" ]; then
            echo $path2
        fi
    fi
}

start() {
    case "$BOARD" in
    dlan-*|\
    dvl-*|\
    ew-*)
        doMigration
        ;;
    esac

    if [ -z "$MIGTEST" ];then
        # keep this file for the next boot
        exit 1
    fi
}

if [ -z "$MIGTEST" ];then
   start
fi