#!/usr/bin/env bash
#clear
#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x

#echo "starting: $0 <LOG_LEVEL=$1>"

### new.method

private.states.init() # # initialises the stateMachine folder in $CONFIG_PATH 
{
  check dir $CONFIG_PATH/stateMachines not exists \
    call mkdir -p $CONFIG_PATH/stateMachines 
}

state.list.machines() # <?nameFilter> # lists all available stateMachines
{
  cd $CONFIG_PATH/stateMachines
  c2 files.completion $1 | line replace ".states.env"

  if [ -n "$1" ]; then shift; fi
  RETURN=$1
}


state.of() # <machine> <?method> # chooses the <machine> as current for all next commands and returns the state
{
  local machine=$1
  local stateID=${machine}_STATE_ID
  shift

  if [ "$machine" = "-" ]; then
    source $CONFIG_PATH/current.state.machine.env
  else
    if ! [ -f $CONFIG_PATH/stateMachines/${machine}.states.env ]; then
      error.log "state machine ${YELLOW}${machine}${RED} does not exist"
      exit 1
    fi

    source $CONFIG_PATH/stateMachines/${machine}.states.env
    local state=${!stateID}
    if [ -z "$state" ]; then
      warn.log "state not set"
      state=1
    fi
    local stateName="${machine}_STATES[${state}]"
    local stateList="${machine}_STATES[@]"
    local stateFile="$CONFIG_PATH/stateMachines/${machine}.states.env"

    debug.log "machine ${YELLOW}$machine ${CYAN}state is: ${WHITE}${!stateName}"
    export STATE_MACHINE_CURRENT=$machine
    private.state.update.current.machine
  fi

  if [ -n "$1" ]; then 
    local call=$1
    shift
    state.$call - "$@"
    shift
  else
    echo ${state}
  fi
  RETURN=$1
}




state.current() # <print> # load current state cache 
# and optionally prints it to the screen if <print> is not set
{
	source $CONFIG_PATH/current.state.machine.env
	if [ -z "$1" ]; then 
		cat $CONFIG_PATH/current.state.machine.env
	fi
}



state.parameter.completion.machine() {
  state.list.machines $1
}

state.parameter.completion.nameFilter() {
  state.list.machines $1
}

state.parameter.completion.print() {
  echo "silent"
}

state.parameter.completion.method() {
  c2 get.functions $OOSH_DIR/state | line find "#[ ]*<\?machine>" | line replace "^state\." | line replace "().*$" | line filter "machine\." | line filter "of"
}

state.list() # <?machine> <listOption:all> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env


  
  local stateFilter=$1
  if [ -n "$1" ]; then shift; fi  

  debug.log "machine=${machine}    stateFilter=${stateFilter}   1=$1"



  important.log "state machine ${YELLOW}${machine}${CYAN}_STATES selected.
   current state:
  " 
  
  console.log "${YELLOW}[${state}]\t= ${!stateName}
  "
  local stateList="${machine}_STATES[@]"

    private.loop.states \
      private.itterator.list $stateFilter

  echo
  let transitionStates=$countInternal-$count
  important.log "${machine}_STATES has $count states (and $transitionStates transition states)
  
  "

  shift
  RETURN=$1
}



state.stage() # <?machine> <state> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env
  
  local script=$1
  if [ -n "$1" ]; then shift; fi  

  let state++
  info.log "stage to ${state}"
  state.set $machine ${state}

  shift
  RETURN=$1
}

state.next() # <?machine> <state> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  
  local script=$1
  if [ -n "$1" ]; then 
    shift;
  else 
    script=state 
  fi  

  let state++
  info.log "is ${state} next of $machine"

  if state.find $machine ${state}; then
    source $CONFIG_PATH/current.state.machine.env
    info.log set values ${stateValue} = $state = $stateFound 
    if [ "$stateFound" -lt "$state" ]; then
      warn.log " State of ${machine} would be hard reset from: [${!stateID}] => [${stateFound}]"
    fi
    local stateName="${machine}_STATES[${stateFound}]"
    local stateValue="${!stateName}"
    important.log "Going to set state of ${machine} to: [${stateFound}] = ${stateValue}"
    if this.functionExists "$script.check"; then
      console.log   "Going to call:
      state check - ${stateValue} ${script}"
      $script.check - ${stateValue} ${script}
    else
      console.log   "Going to call:
      state check - this.call check.${stateValue} $(which $script)"
    fi
  else
    error.log "not found: $state = $stateFound = $stateResult"
  fi

  state.list


  shift
  RETURN=$1
}

state.diagnose() { # # shows and lists the current state machine and its cache
  important.log "
  
   Current state machine and cache"
  state current print
  important.log "
  
   Current state machine declaration"
  state declaration
  important.log "
  
   Current state machine state"
  state list - #all
}

state.check() # <?machine> <allStates> <?script:state> # checks if the state can be set. 
# private.chcek.<state> needs to be implemented in <script> and return the next state as RESULT
# this can be done with create.result 0 "<nextState>"
#                    or create.result 1 "Error Message and reason"
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env
  
  local stageTo=$1
  if [ -n "$1" ]; then shift; fi  

  local script=$1
  if [ -n "$1" ]; then shift; fi

  RETURN=$1

  if state.find $machine ${stageTo}; then
    source $CONFIG_PATH/current.state.machine.env
    if [ "$script" = "$stateScript" ]; then
      info.log "stateScript=$stateScript"
    else
      debug.log "changed script from \"$script\" to \"$stateScript\""
      script="$stateScript"
    fi 
    info.log "check values ${stateValue} = $state, $stateFound = $stageTo
    
    "

    if [ $state -gt $stateFound ]; then
      create.result 0 "machine ${machine} already in state [$state] = ${stateValue}"
      success.log "$RESULT"
      return $(result)
    fi

    if [ -z "$script" ]; then
      if this.functionExists "private.check.$stageTo"; then
        #echo calling private.check.$stageTo $script $stageTo $stateFound
        important.log "
        
        checking $stageTo      state $stageTo $stateFound"
        
        if private.check.$stageTo state $stageTo $stateFound; then
          local msg=$RESULT
          state.set - $stateFound
          success.log "$msg"
        else
          error.log "$RESULT"
        fi
        return $(return)
      else
        echo "private.check.$stageTo not found..."
      fi
    else
      source $(which $script)
      if this.functionExists "private.check.$stageTo"; then
        #echo calling private.check.$stageTo $script $stageTo $stateFound
        important.log "
        
        checking $stageTo      state $stageTo $stateFound"
        #set -x
        
        if private.check.$stageTo $script $stageTo $stateFound; then
    #set -x
    #problem.log "all good"
          console.log "
          "
          if this.isNumber $RESULT && ! [ "$stateFound" = "$RESULT" ]; then
            warn.log "will overwrite stateFound: $stateFound with private.check.$stageTo RESULT=$RESULT"
            stateFound=$RESULT
          else
            local msg=$RESULT
          fi 

          state.set - $stateFound
          success.log "$msg"
        else
    #set -x
    #problem.log "not all good"
          error.log "did not go well: $? = $RETURN_VALUE $RESULT"
        fi

        return $(return)
      else
        echo "$script.check.$stageTo not found..."
      fi
    fi

  else
    error.log "not found: $state = $stateFound = $stateResult"
  fi

}

private.check.all.states.added() # must not have parameters # checks if the current machine cans switch to this state
{
  source $CONFIG_PATH/current.state.machine.env

  local script=$1
  if [ -n "$1" ]; then shift; fi  
  local stateValue=$1
  if [ -n "$1" ]; then shift; fi  
  local stageTo=$1
  if [ -n "$1" ]; then shift; fi  

  if [ $state -gt 3 ]; then
      create.result 0 "machine ${machine} already in state [$stageTo] = ${stateValue}"
      return $(result)
  else

    private.loop.states \
      private.itterator.check.all.states.added


    if [ "$RESULT" = "at least 1 function does not exist" ]; then
      error.log "$RESULT"
      return $(result)
    fi


    local nextCustomState=$(state.find $machine next.custom.state)
    stateFound=$stageTo
    if [ -n "$nextCustomState" ] ; then
      local stateID="${machine}_STATES[${nextCustomState}]"
      important.log "finalizing state machine
      renaming $stateID to 99"
      printf -v "${stateID}" '%s' "99"
      
      stateScript="$script"
      stateLast="$nextCustomState"

      private.state.machine.update

      create.result 0 "next.custom.state removed: $stateValue = $stageTo" "$1"
      local msg=$RESULT
      state.declaration
      success.log "$msg"
    else
          create.result 0 "next.custom.state already removed" "$1"
          success.log "$RESULT"
    fi
      

  fi
  
  return $(result)
}


private.itterator.check.all.states.added() { # <currentName> <currentValue> <currentID> <stateID> #
  #check.debug.level 6

  #problem.log "private.itterator.check.all.states.added $@"

  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 
  # if [ -z "$currentID" ]; then
  #   problem.log "no currentID: -$currentValue- -$currentName- :$@:"
  #   exit
  # fi  

        local name="undefined"
        if [ $currentID -lt 6 ]; then
          name="private.check.${currentValue}"
          if this.functionExists $name; then
            debug.log "$function exists"
          else
            create.result 0 "at least 1 function does not exist" "$1"
            error.log "function ${CYAN}$name${RED} is missing in $script"
          fi
        fi
      

}

private.check.started() {
    source $CONFIG_PATH/current.state.machine.env

  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 

  if [ $state -gt 4 ]; then
      create.result 0 "machine ${machine} already in state [$stageTo] = ${stateValue}"
      return $(result)
  else
      
    if [ -z "$stateScript" ]; then
        create.result 1 "stateScript not set!" "$1"
        state.current print
        error.log "$RESULT"
        return $(result)
      fi

      source $( which $stateScript )

      private.loop.states \
        private.itterator.check.started

      if [ "$RESULT" = "at least 1 function does not exist" ]; then

        error.log "$RESULT"
        important.log "to continue, implement the required private.check methods and use
        
        state machine.start - ${YELLOW}<stateScript>${CYAN}

        ${GREEN}where ${YELLOW}<stateScript>${GREEN} is the script that implements the private.check methods and handels the transitions 
        "
        create.result 1 "please implement the functions listed above in script: $stateScript"
        return $(result)
      fi

      if [ -n "$stateScript" ]; then
        create.result 0 "stateScript is: $stateScript" "$1"
        #source $CONFIG_PATH/current.state.machine.env
        #state current print
        success.log "$RESULT"
      fi
  fi
  
  return $(result)

}

private.itterator.check.started() { # <currentName> <currentValue> <currentID> <stateID> #
  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 

            local name="undefined"
            info.log "private.itterator.check.started: $currentID"
            if [ $currentID -gt 10 ]; then
              name="private.check.${currentValue}"
              if this.functionExists $name; then
                debug.log "$function exists"
              else
                create.result 0 "at least 1 function does not exist" "$1"
                error.log "function ${CYAN}$name${RED} is missing in script: ${CYAN}$script"
              fi
              
            # else
            #   console.log "$script.check.${!currentName}"
            fi

}

state.machine.start() # <?machine> <script> # checks if the state can be set
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  local script=$1
  if [ -n "$1" ]; then shift; fi  

  if private.check.started $script; then
    state.set - 4
  else
    error.log "could not start machine $machine: \n$RESULT"
  fi
}

private.loop.states() # <iteratorFunction> <listOption:all> # itterates all states and calls on each the itterator function. stops the iterration on non-null return value 
{
  local itteratorFunction=$1
  if [ -n "$1" ]; then shift; fi

  local stateFilter=$1
  if [ -n "$1" ]; then shift; fi

  let i=0
  let count=0
  let countInternal=0
  for index in "${!stateList}"; do
    local currentName="${machine}_STATES[$i]"
    debug.log looping ${currentName}  at $index loop $i

    if this.isNumber ${!currentName}; then
      debug.log "skipping ${!currentName}"
      local next=${!currentName}
      i=$next-1
    else 
      let count++
      local colorMod=""
      # if [ "$i" -eq "${state}" ]; then
      #   colorMod=${CYAN}
      # fi
      if [ "$state" -lt "$i" ] || [ "$stateFilter" = "all" ]; then
        $itteratorFunction "$currentName" "${!currentName}" "$i" "$@"
      fi
    fi
    let i++
    let countInternal++
  done
}


state.find() # <?machine> <allStates> <alwaysReturnId> # returns the state id for a name
# if <alwaysReturnId> is empty, then it returns "stateName: state" for a nuber and would autotransition
# if <alwaysReturnId> is e.g. "id", then it always returns an id, if that id exists in the state machine
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  
  local stateName=$1
  if [ -n "$1" ]; then 
    shift; 
  else
    create.result 1 "no ${YELLOW}<state>${RED} provided!" 
    error.log "$RESULT"
    return $(result)
  fi  

  local alwaysReturnId=$1
  if [ -n "$1" ]; then shift; fi  

  if this.isNumber $stateName;then
    local stateFound=${stateName}
    local stateName="${machine}_STATES[${stateName}]"
    stateValue=${!stateName}
    if [ -z "$stateValue" ]; then 
      stateFound=0; 
    else 
      ## TDOD maybe this is a while loop
      if this.isNumber ${!stateName}; then 
        if [ -z "$alwaysReturnId" ]; then
          important.log "found transition state: ${stateFound} => ${!stateName}"
          stateFound=${!stateName}
          stateName="${machine}_STATES[${stateFound}]"
        fi
      fi
      if [ -z "$alwaysReturnId" ]; then
        echo ${!stateName}: ${stateFound}
      else        
        echo $stateFound
      fi
    fi
  else

  create.result 1 "0" # initalize as state not found

    private.loop.states \
      private.itterator.find all
    
    stateFound="$RESULT"
  fi

  shift
  RETURN=$1
  

  if [ $stateFound -eq 0 ]; then
    error.log "State '$stateName' not found!"
    return 1
  fi

  private.state.update.current.machine
  debug.log found ${stateName} = $stateFound $stateValue
  return 0
}

private.parameter.completion.alwaysReturnId() {
  echo "id"
  echo "\'\'"
}

private.itterator.find() {  # <currentName> <currentValue> <currentID> <rest> #
  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 

  if [ "${!currentName}" = "$stateName" ]; then
    echo "$currentID"
    stateFound=$currentID
    create.result 1 "$stateFound" 
    return $(result)
  else
    stateFound=0
  fi
  return 0
}

state.rename() # <?machine> <allStates> <newStateName:> <print:> # rename a state of the <machine>
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  if ! private.check.setup rename; then return 1; fi

  local stateToRename=$1
  if [ -n "$1" ]; then 
    shift; 
  else
    error.log "no ${YELLOW}<state>${RED} to rename provided!"
    return 1
  fi 

  local newStateName=$1
  if [ -n "$1" ]; then 
    shift; 
  else
    error.log "no ${YELLOW}<newStateName>${RED} provided!"
    return 1
  fi 


  local print=$1
  if [ -n "$print" ]; then 
    shift; 
    echo going to $print
  fi  

  local stateToRename=$( state.find $machine $stateToRename id )
  if this.isNumber ${stateToRename}; then
    important.log "found state [${stateToRename}] => ${stateValue}"
  else
  	stateToRename=$( echo $stateToRename | line split ":" | line unquote | line "select" 2 )
  fi
  source $CONFIG_PATH/current.state.machine.env

  local stateID="${machine}_STATES[${stateToRename}]"
  printf -v "${stateID}" '%s' "${newStateName}"

  private.state.machine.update

  if [ -n "$print" ]; then
    state.declaration
  fi


  shift
  RETURN=$1
}

private.check.setup() { # <?action:add> # returns error 1 if state is not equal to setup 
  if [ -z "$state" ]; then
      source $CONFIG_PATH/current.state.machine.env
  fi

  if [ $state -eq 1 ]; then 
    state.stage $machine; 
    source $CONFIG_PATH/current.state.machine.env
  fi
  if [ $state -gt 2 ]; then
    local action=$1
    if [ -n "$action" ]; then shift; else action="add"; fi

    error.log "cannot $action state!"
    error.log "state machine ${CYAN}$machine${RED} is not in state: ${CYAN}[2] = setup${RED}  
    but is in state: ${CYAN}$state
    "
    important.log "
    you could hard reset the machine $machine to state 2 with

    state of $machine set 2
    "
    return 1
  fi
  return 0
}


state.add() # <?machine> <newStateName> <print> # adds a state to the machine, which needs to be in state 'setup' for that
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  if ! private.check.setup; then return 1; fi
  
  local newStateName=$1
  if [ -n "$1" ]; then 
    shift; 
  else
    error.log "no ${YELLOW}<newStateName>${RED} provided!"
    return 1
  fi  

  local print=$1
  if [ -z "$print" ]; then 
    shift; 
    echo going to $print
  fi  

  echo add ${newStateName}
  local state=$( state.find $machine next.custom.state )
  local stateID="${machine}_STATES[${state}]"
  
  ## TODO check security
  printf -v "${stateID}" '%s' "${newStateName}"
  # eval ${stateID}=${newStateName}
  
  if this.isNumber ${newStateName}; then
    important.log "adding transition state [${state}] => ${newStateName}"
    state=${newStateName}
  else
    let state++
  fi
  local stateID="${machine}_STATES[${state}]"
  if [ -n "${!stateID}" ]; then
    if [ "${!stateID}" = "99" ]; then
      eval ${stateID}="next.custom.state"
    else
      warn.log "canot overwrite existing state ${stateID}=${!stateID}"
    fi
  else 
    printf -v "${stateID}" '%s' "next.custom.state"
  fi
  private.state.machine.update

  if [ -z "$print" ]; then
    state.declaration
  fi


  shift
  RETURN=$1
}

state.set() # <?machine> <state> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  
  local stateValue=$1
  if [ -n "$1" ]; then shift; fi  



  info.log set ${stateValue} of $machine

  if state.find $machine ${stateValue}; then
    state.current silent
    info.log set values ${stateValue} = $state = $stateFound 
    if [ "$stateFound" -lt "$state" ]; then
      warn.log " State of ${machine} will be hard reset from: [${!stateID}] => [${stateFound}]"
    fi
    declare -x ${machine}_STATE_ID=${stateFound}
    private.state.machine.update
    source $CONFIG_PATH/current.state.machine.env

    important.log "Set state of ${machine} to: [${stateFound}] = ${stateValue}"
  else
    error.log "not found: $state = $stateFound = $stateResult"
  fi


  shift
  RETURN=$1
}


private.itterator.list() { # <currentName> <currentValue> <currentID> <stateID> #
  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 

    if [ "$currentID" -eq "${state}" ]; then
      colorMod=${CYAN}
    fi
    console.log "${colorMod}[$currentID]\t= ${currentValue}"
    create.result 0 "[$currentID]\t= ${currentValue}"
}


state.machine.exists() # <machine> # creates a stateMachine # be aware that the Mac OSX filesystem is case insensitive
{
  #set -x 

  local aMachine=$1
  if [ -z "$aMachine" ] || [ "$aMachine" = "-" ]; then
    if [ -z "$machine" ]; then
      source $CONFIG_PATH/current.state.machine.env
    fi
    important.log "using state machine ${YELLOW}${machine}"
  else
    shift; 
    machine="$aMachine"
  fi
  
  local fileExistsCaseSensitive="$( find "$CONFIG_PATH/stateMachines/" -maxdepth 1 -type f -name "${machine}.states.env" )"

  # TODO this is case insensitive on case insensitive filesystems like on Mac OSX default 
  # if [ -f "$CONFIG_PATH/stateMachines/${machine}.states.env" ]; then
  if [ -n "$fileExistsCaseSensitive" ]; then 
    local state=$( state.of ${machine} )
    create.result 0 "state machine \"${machine}\" exists" "$1"
  else
    create.result 1 "state machine \"${machine}\" does not exist" "$1"
    #error.log $RESULT
  fi

  return $(result)
}


state.machine.create() # <machine> <?script> # creates a stateMachine
# the optional <?script> holds the private.check.state method implementations to execute the state transitions of the machine
{
  local machine=$1
  if [ -n "$1" ]; then shift; fi  

  local script=$1
  if [ -n "$1" ]; then shift; fi  

  check file $CONFIG_PATH/stateMachines/${machine}.states.env not exists \
    call state machine.init $machine $script
  state.of $machine
}

state.machine.init() { # <machine> <?script> # inititalizes an existing stateMachine
  local machine=$1
  if [ -n "$1" ]; then shift; fi  

  local script=$1
  if [ -n "$1" ]; then shift; fi  
  declare -xag ${machine}_STATES='(\
    [0]="not.installed" \
    [1]="initialized" \
    [2]="setup" \
    [3]="all.states.added" \
    [4]="started" \
    [5]=11 \
    [6]=to.be.deleted \
    [11]="next.custom.state" \
    [12]=99 \
    [99]="finished" \
    [100]=6
    )' 
  
  declare -x ${machine}_STATE_ID=1 
  declare -x ${machine}_CUSTOM_SCRIPT=$script
  private.state.machine.update
}


private.state.machine.update() {
  {
    declare -a | line find ${machine}_STATES | line replace ' \[' ' \\-SPLIT-[' | line split '-SPLIT-' | line unquote
    local stateID=${machine}_STATE_ID

    local state=${!stateID}
    if [ -z "$state" ]; then
      error.log "State broken!  reseting to 1"
      state=1
    fi

    echo ${stateID}=${state}
    
    stateID=${machine}_CUSTOM_SCRIPT
    echo ${stateID}=${!stateID}
  } >$CONFIG_PATH/stateMachines/${machine}.states.env
  
  local stateName="${machine}_STATES[${state}]"
  local stateValue="${!stateName}"
  private.state.update.current.machine
}

private.state.update.current.machine() {
  local stateID=${machine}_STATE_ID
  local stateName="${machine}_STATES[${!stateID}]"
  export STATE_MACHINE_CURRENT=$machine
  {
    echo machine=$machine

    echo stateID=$stateID
    echo state=${!stateID}

    echo stateName="${machine}_STATES[${state}]"
    echo stateValue=${!stateName}

    echo stateFound=$stateFound
    echo stateLast=$stateLast

    stateName=${machine}_CUSTOM_SCRIPT
    stateScript=${!stateName}
    if [ -z "stateScript" ]; then stateScript=state; fi
    echo stateScript=${stateScript}

    echo stateList=$stateList
    echo stateFile=$stateFile

    echo source $stateFile
  } >$CONFIG_PATH/current.state.machine.env  
}


state.parameter.completion.state() {
  debug.log "parameter.completion.state: $@"
  local stateFilter=$1
  if [ -n "$1" ]; then shift; fi  
  source $CONFIG_PATH/current.state.machine.env

  debug.log "machine=${machine}    stateFilter=${stateFilter}   1=$1  stateList=${!stateList}"

  private.loop.states \
  private.itterator.completion.state

  echo
  let transitionStates=$countInternal-$count
  debug.log "${machine}_STATES has $count states (and $transitionStates transition states)
  
  "

  shift
  RETURN=$1
}

state.parameter.completion.allStates() {
  debug.log "parameter.completion.state: $@"
  local stateFilter=$1
  if [ -n "$1" ]; then shift; fi  
  source $CONFIG_PATH/current.state.machine.env

  debug.log "machine=${machine}    stateFilter=${stateFilter}   1=$1  stateList=${!stateList}"

  private.loop.states \
  private.itterator.completion.state all

  echo
  let transitionStates=$countInternal-$count
  debug.log "${machine}_STATES has $count states (and $transitionStates transition states)
  
  "

  shift
  RETURN=$1
}


private.itterator.completion.state() { # <currentName> <currentValue> <currentID> <stateID> #
  local currentName=$1
  shift  
  local currentValue=$1
  shift
  local currentID=$1
  shift 

  echo "${currentValue}"
}

state.machine.edit() # <machine> # creates a stateMachine
{
  local machine=$1
  if [ -z "$1" ]; then state.current; fi
  if [ "$1" = "-" ]; then state.current; fi
  oo cmd vim
  vim $CONFIG_PATH/stateMachines/${machine}.states.env
}

state.edit() # <?machine> # creates a stateMachine
{
  state.machine.edit "$@"
}

state.machine.declaration() # <?machine> # shows the declaration of a stateMachine
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env
  oo cmd vim
  cat $CONFIG_PATH/stateMachines/${machine}.states.env
}

state.declaration() # <?machine> # shows the declaration of a stateMachine
{
  state.machine.declaration "$@"
}

state.machine.delete() # <machine> # deletes a stateMachine without any warning
{
  local machine=$1
  if [ -z "$1" ]; then 
    error.log "no ${YELLOW}<machine>${RED} provided!"
    return 1 
  fi
  oo cmd vim
  if state.machine.exists ${machine}; then
    rm $CONFIG_PATH/stateMachines/${machine}.states.env
  else
    error.log "state machine ${YELLOW}${machine}${RED} does not exist!"
    return 1
  fi
  
  return 0
}


state.name() # <?machine> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env

  echo ${!stateName}
}

state.id() # <?machine> #
{
  local aMachine=$1
  if state.machine.exists "$aMachine"; then shift; fi 
  source $CONFIG_PATH/current.state.machine.env


  echo ${state}
}

state.usage()
{
  local this=${0##*/}
  echo "You started" 
  echo "$0

  state allows you to create and handle multiple state machines

  Usage:
  $this: command   Parameter and Description"
  this.help
  echo "
  
  Examples
    $this list
    $this init
    state of SETUP_SERVER    add myNewState
    state rename - 52 next.custom.state print
    state next
  "

  state.list
}

state.start()
{
  #echo "sourcing init"
  source this
  private.states.init

  # if [ -z "$1" ]; then
  #   status.discover "$@"
  #   return 0
  # fi

  this.start "$@"
}

state.start "$@"

