#!/usr/bin/env bash

# set -x

loop.start()
{
  This=$(command -v $0)
  this=$(basename $This)
  #if ! [ "$(type -t log.init)" = "function" ]; then

  #fi

  if [ "$this" = "loop" ]; then
    #echo "starting ${BASH_SOURCE[0]##*/}"
    source this
  else
      if [ "$this" = "log" ]; then
        source $OOSH_DIR/log
      fi
    debug.log "sourcing ${BASH_SOURCE[0]##*/}"
    return 0
  fi

  #check.debug.level 6
  #while [ -n $1 ]; do
    debug.log "start 1: -$1-"
    case $1 in
      list)
        shift
        loop.list "$@"
        ;;
      usage)
        shift
        loop.usage "$@"
        ;;        
      silent)
        shift
        RETURN=$1
        return 0
        ;;
      *)
        loop.this "$@"
    esac
    shift
    debug.log "loop reult $RESULT"
  #done

}

loop.usage()
{
            echo "usage: loop list <?seperator:":"> <?command:"echo "> <?item> <?moreItems>
       loop list : <?option:silent>
       loop list listname <?command:echo > <?option:log> <?item...>
                   eg: loop \$PATH : print
                       loop list PATH print

            commands are
                array:  converts to an array
                add:    appends the new item       
                put:    preppends the new item       
                rm:     removes the item      
                find:   stops at the item as last item
                r:      replaces the seperator by item as a new seperator       
                +:      concatenates items

                env:    lists the environments variables values that are named in the list
                set:    sets the items \$* values to the variables named in the list
                clear:  clears environment variables named in the list

                silent: just loops the list and sets $$firstItem and $$lastItem and results with $$list 

                print:  logs a line per list entry
                array   pipes the array value (e.g. loop list ENUM_LOG_LEVEL array)

            CAREFULL with these commands
                test:   shows how call would call commands
                call:   executes what was generated in with the test command    


            options are
                log     print the result list
                save    savetes the list to a file e.g. loop list PATH put 1 save list.result.file.name reuslt
                result  only in combination with save  and saves the full result (see above)
                pipe    pass the list to the next command (e.g. loop \$HOSTNAME . add localhost pipe | cat )
                and     chanis futher commands on the result and the same seperator  (e.g loop \$HOSTNAME . add local and add host log)         
        "

}

loop.this() {
    local list="$1"
    shift
    local seperator="$1"
    shift
    local command="$1"
    shift
    local item=$1
    shift
    local option=$1
    shift
    local nextCommand="$@"


    


    debug.log " function ${FUNCNAME[0]}(seperator $seperator, command: $command, item: $item, list: $list, option: $option)"
    local length=0
    local firstItem=""
    local lastItem=""
    local reverse=""
    #local option="silent"
    local result=""
    local save2file=""

    if [ -z "$list" ]; then
        loop.usage
    else


        if [ "$command" = "put" ]; then
            result=$item
        fi
        if [ "$command" = "push" ]; then
            result=$item
        fi

        if [ "$command" = "find" ]; then
            found=""
        fi

        if [ "$command" = "array" ]; then
            result="("
            item=" "
            command="r"
            final="array"
            if [ -z "$option" ]; then
              option=pipe
            fi
        fi
        firstItem=""
        lastItem=""
        local i=0
        for current in ${list//$seperator/ }; do
            ((i++))
            if [ "$firstItem" = "" ]; then
                firstItem=$current
            fi

            if [ -z "$command" ]; then
                command=silent
                item=x
            fi

            case $command in
                rm)
                    debug.log "...remove..."
                    if [ "$current" = "$item" ]; then
                        continue
                    fi

                    if [ "$result" = "$first" ]; then
                        result=$result$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                find)
                    debug.log "...find..."
                    if [ "$current" = "$item" ]; then
                        found=$current
                        break
                    fi

                    if [ "$result" = "$first" ]; then
                        result=$result$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                +)
                    debug.log "...concat..."
                    if [ "$result" = "$first" ]; then
                        result=$result$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                r)
                    debug.log "...replace..."
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$item$current
                    fi
                    ;;
                add)
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                put)
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                push)
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                test)
                    #echo "printf \"$item\n\"" $current
                    echo $item $current ">>"$option
                    ;;
                call)
                    $item $current >>$option
                    ;;
                env)
                    echo "$current=${!current}"
                    ;;
                set)
                    export $current=$1
                    shift
                    ;;
                clear)
                    export $current=""
                    shift
                    ;;
                silent)
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                print)
                    console.log "$item$current"
                    if [ "$result" = "" ]; then
                        result=$current
                    else
                        result=$result$seperator$current
                    fi
                    ;;
                reverse)
                    debug.log "$current           and $reverse"
                    reverse=$current$seperator$reverse
                    ;;
                and)
                    shift
                    option=$1
                    echo "and $@"
                    ;;
                *)
                    echo "do not know ${FUNCNAME[0]} command: $command"
            esac
            
        done
        if [ "$command" = "add" ]; then
            result=$result$seperator$item
        fi
        result=$result$last
        if [ "$final" = "array" ]; then
          result=$result" )"
        fi
        export list=$result
        lastItem=$current
        length=$i

        if [ "$command" = "reverse" ]; then
            debug.log "reverse: $reverse"
            list=$reverse
            save2file=$option
            option=$item
        fi
        
    fi
    debug.log "firstItem: $firstItem"
    debug.log "lastItem: $lastItem"
    debug.log "length: $length"

    debug.log "command    : $command"
    debug.log "item       : $item"
    debug.log "option     :  $option"
    debug.log "save2file  :  $save2file"
    debug.log "nextCommand:  $nextCommand"

    if [ "$command" = "find" ]; then
        
        if [ "$found" = "" ]; then
            if [ ! "$option" = "silent" ]; then
                warn.log "could not find: $item"
            fi
            return 1
        else
            if [ ! "$option" = "silent" ]; then
                console.log "$length"
            fi
            export RESULT=$length
            return 0
        fi

    fi

    export RESULT=$list
    if [ "$option" = "pipe" ]; then
        echo "$RESULT"
    fi
    
    if ! [ "$command" = "silent" ]; then
        if [ -z "$option" ] && ! [ "$command" = "print" ]; then
            option="log"
        fi
    else
        save2file=$option
        option=$item
    fi

    if [ "$option" = "log" ]; then
        console.log "
log list:"

        echo "  list=$list" 
        echo "  firstItem=$firstItem" 
        echo "  lastItem=$lastItem" 
        echo "  length=$length"
    fi


    if [ "$option" = "save" ]; then
        if [ -z "$save2file" ]; then
            save2file=$1
        fi
        if [ -z "$save2file" ]; then
            save2file="$CONFIG_PATH/result.env"
        fi
        echo "$list 
        save to: $save2file"
        echo "$list" >$save2file
        nextCommand=""
        option=$3
    fi

    debug.log "option is here: $option"
    if [ "$option" = "result" ]; then
        if [ -z "$save2file" ]; then
            save2file=$1
        fi
        if [ -z "$save2file" ]; then
            save2file="$CONFIG_PATH/result.env"
        fi
        pwd
        echo "$list
        save results to: $save2file"
        echo "list=$list" >$save2file
        echo "firstItem=$firstItem" >>$save2file
        echo "lastItem=$lastItem" >>$save2file
        echo "length=$length" >>$save2file
        nextCommand=""
    fi

    if [ -n "$nextCommand" ]; then
        debug.log "call loop $list $seperator $nextCommand"
        loop.this $list $seperator $nextCommand
    fi

}

loop.list() {
    listname=$1
    shift
    command="$1"
    shift
    item=$*

    if [ -z "$command" ]; then
        command=print
    fi


    debug.log " function ${FUNCNAME[0]}(listname $listname, command: $command, item: $item, list: $list)"
    length=0
    firstItem=""
    lastItem=""

    if [ -z "$listname" ]; then
        echo "usage: <?eamd test> ${FUNCNAME[0]} listname <?command:"echo "> <?item> <?options>
            eg: ${FUNCNAME[0]} PATH 
            commands are
                add:    appends the new item       
                put:    preppends the new item       
                rm:     removes the item      
                find:   stops at the item as last item
                r;      replaces the seperator by item as a new seperator       
                +:      concatenates items

                silent: just loops the list and sets $$firstItem and $$lastItem and results with $$list 
                
            CAREFULL with these commands
                test:   shows how call would call commands
                call:   executes what was generated in with the test command   

            Options
                silent      no output
                log         logs the result to the console
                save        saves the list to <?filename:$CONFIG_PATH/result.env>
                result      saves the full result to <?filename:$CONFIG_PATH/result.env>      
        "

    else
        debug.log "loop ${!listname} : $command $*"
        loop.this ${!listname} : $command $*
    fi
}


loop.start "$@"
