#!/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>"

# Cross-platform sed helper for first-match replacement
# BSD sed (macOS) doesn't support GNU's 0,/pattern/ syntax
# Uses perl which is available on both platforms
private.oo.sed.first() {
  local pattern="$1"
  local replacement="$2"
  local file="$3"
  # Escape special chars in replacement for perl
  local escaped_replacement=$(printf '%s' "$replacement" | sed 's/[&/\]/\\&/g')
  perl -i -pe "s/\Q${pattern}\E/${escaped_replacement}/ && (\$done = 1) unless \$done" "$file"
}

oo.deinstall() { # # deinstall oosh and clean leftover configurations
  problem.log "DEINSTALL OOSH: are you sure?  continue with by typing 'c'"
  cp $OOSH_DIR/init/oosh $HOME/install.oosh
  rm -Rf $HOME/oosh
  rm -Rf $HOME/config
  rm $HOME/.once
  rm $HOME/.bashrc
  mv $HOME/.bashrc.bak.without.completion $HOME/.bashrc
  clear
  echo "reinstall with: install.oosh"
}

oo.new() # <newClassName> # creates a new script that acts as a oo class with completion
{
  if [ -n "$1" ]; then
    info.log "oosh in $OOSH_DIR"
    cd $OOSH_DIR
    cat ./templates/code/new_script | sed 's/new_script/'"$1"'/' >./$1
    chmod +x ./$1
    success.log "created oo script $1"
    console.log "to enable completion on the new command, type

    reconfigure"

    oo.new.test "$1"

  else
    warn.log "usage: oo new filename
    
    please specify a filename"
    return 1
  fi
}

oo.new.test() # <newClassName> # creates a new script that acts as a oo class with completion
{
  if [ -n "$1" ]; then
    info.log "oosh in $OOSH_DIR"

    cd $OOSH_DIR/test
    cat ./../templates/code/new_script_test | sed 's/new_script/'"$1"'/' > test.$1
    chmod +x ./test.$1
    success.log "created test script test.$1"

  else
    warn.log "usage: oo new.test filename
    
    please specify a filename"
    return 1
  fi
}

oo.new.method()   # <new.method> <new_script.new_method> # creates a new method in the script new_script
# this is an higly interactive command
{
  local name="$1"
  if [ -z "$name" ]; then
    error.log "No parameter provided."
    return 1
  fi
  local new_script=$(echo $name | cut -d. -f1)
  local new_method=$(echo $name | cut -d. -f2)
  
  if [ -z "$new_method" ]; then
    warn.log "check if the parameter contains a ."
    error.lgo "no method name in: $name:"
    return 2
  fi
  console.log "
  command: $new_script
  method : $new_method
  "

  if check file $OOSH_DIR/$new_script exists fix error.log "$OOSH_DIR/$new_script does not exist"
  then
    local tweaked_method=$(cat $OOSH_DIR/templates/code/new_method | sed 's/new_script/'"$new_script"'/' | sed 's/new_method/'"$new_method"'/')
    local replace_text="### new.method"

    replace within "$OOSH_DIR/$new_script" "$replace_text" by "$tweaked_method"


    local replace_name_desc="      ----      --------------------------"
    local new_name_desc="      ----      --------------------------
      ----      --------------------------"

    replace within "$OOSH_DIR/$new_script.new" "$replace_name_desc" by "$new_name_desc"

    private.oo.sed.first "----" "$new_method" "$OOSH_DIR/$new_script.new"

    local descript_parameter
    echo "A short description and Parameter(s) for method" $new_method "of" $new_script": "
    read descript_parameter
    echo "$descript_parameter"

    private.oo.sed.first "--------------------------" "$descript_parameter" "$OOSH_DIR/$new_script.new"

    replace commit "$OOSH_DIR/$new_script"

    replace cleanup "$OOSH_DIR/$new_script"

    success.log "created oo new method in script $1"
    
  fi

  if check file $OOSH_DIR/test/test.$new_script exists fix error.log "$OOSH_DIR/test/test.$new_script does not exist"
  then
    local tweaked_test_method=$(cat $OOSH_DIR/templates/code/new_method_test | sed 's/new_script/'"$new_script"'/' | sed 's/new_method/'"$new_method"'/')
    local replace_test_text="### test.method"

    replace within "$OOSH_DIR/test/test.$new_script" "$replace_test_text" by "$tweaked_test_method"

    local test_description
    echo "Give a short description of the test" $new_method "of script" $new_script": "
    read test_description
    echo "$test_description"

    private.oo.sed.first "test_description" "$test_description" "$OOSH_DIR/test/test.$new_script.new"

    local test_parameter
    echo "Give the parameters for test" $new_method "of script" $new_script": "
    read test_parameter
    echo "$test_parameter"

    private.oo.sed.first "new_argument(s)" "$test_parameter" "$OOSH_DIR/test/test.$new_script.new"

    local test_expect
    echo "What to expect of test" $new_method "of script" $new_script": "
    read test_expect
    echo "$test_expect"

    private.oo.sed.first "new_expect" "$test_expect" "$OOSH_DIR/test/test.$new_script.new"
    
    replace commit "$OOSH_DIR/test/test.$new_script"

    replace cleanup "$OOSH_DIR/test/test.$new_script"

    success.log "created new test for method $1"
    
  fi

}



oo.commit() # <?mode:force> # commits latest changes to the oosh environment and publishes them.
{
  cd $OOSH_DIR

  local branch=$( git branch | line find "\*" )
  console.log "git branch is: $branch"
  if [ "$branch" = "* dev" ] || [ "$1" = "force" ]; then
    rm *\:
    git add *
    git commit
    git push
  else
    error.log "not on the dev branch"
    console.log "switch branch with
   
    oo mode.dev
    
    "
  fi
}

oo.update() # # updates oosh environment and pulls latest changes from github.
{
  cd $OOSH_DIR
  git pull
}

oo.remote.update() { # <sshConfigHost> # updates the oosh environment on <sshConfigHost>
  local sshConfigHost="$1"
  if [ -n "$1" ]; then
    shift
  else
    error.log "no sshConfigHost was specified"
    return 1
  fi
  ossh exec "$sshConfigHost" "oo update"
}
oo.remote.update.completion() {
  ossh config.get.completion
}

oo.release() { # # RELEASES and merges dev to prod. NEVER merge main to dev
  oo.commit
  git checkout main
  git merge dev
  git push
  export OOSH_MODE="released"
  config save oosh OOSH
}

oo.mode.base.get() # # returns the OOSH components base directory
{
  local base="$OOSH_COMPONENTS_DIR"
  if [ -z "$base" ]; then
    base="/Users/Shared/Workspaces/AI/Claude/components/OOSH"
  fi
  echo "$base"
}

oo.mode.base.set() # <path> # set and persist the OOSH components base directory
{
  local path="$1"
  if [ -z "$path" ]; then
    error.log "Usage: oo mode.base.set <path>"
    return 1
  fi
  if [ ! -d "$path" ]; then
    error.log "Directory not found: $path"
    return 1
  fi
  export OOSH_COMPONENTS_DIR="$path"
  config save oosh OOSH
  console.log "Base set to: $path"
}

oo.mode.list() # # list available branches with git status
{
  local base
  base=$(oo.mode.base.get)
  local dir
  for dir in "$base"/*/; do
    [ -d "$dir" ] || continue
    local branchName
    branchName=$(basename "$dir")
    [[ "$branchName" == .* ]] && continue
    local status=""
    if [ -d "$dir/.git" ] || [ -f "$dir/.git" ]; then
      status=$(cd "$dir" && git status --short --branch 2>/dev/null | head -1)
    fi
    printf "  %-20s %s\n" "$branchName" "$status"
  done
}

oo.mode() # <?branch> # switch oosh to a branch worktree, or show current mode
{
  local WORKTREE_BASE
  WORKTREE_BASE=$(oo.mode.base.get)
  local OOSH_LINK="$HOME/oosh"
  local branch="$1"

  local current_target
  current_target=$(readlink "$OOSH_LINK" 2>/dev/null)

  if [ -z "$branch" ]; then
    # No argument: show current worktree status
    local current_name
    current_name=$(basename "$current_target")
    console.log "Mode: $current_name"
    console.log "Path: $current_target"
    if [ -d "$current_target" ]; then
      (cd "$current_target" && git status --short --branch 2>/dev/null)
    fi
    return 0
  fi

  # Switch to named branch
  local target_dir="$WORKTREE_BASE/$branch"

  if [ ! -d "$target_dir" ]; then
    console.log "Directory '$branch' not found. Checking remote branches..."
    local remote_branch
    remote_branch=$(cd "$current_target" && git branch -r 2>/dev/null | sed 's/^ *//' | grep -v 'HEAD' | grep -i "${branch//\./.*}" | head -1)
    if [ -n "$remote_branch" ]; then
      console.log "Creating worktree for $remote_branch..."
      (cd "$current_target" && git worktree add -B "${remote_branch#origin/}" "$WORKTREE_BASE/$branch" "$remote_branch")
    else
      error.log "No remote branch matching '$branch' found"
      create.result 1 "branch not found"
      return $(result)
    fi
  fi

  # Switch symlink
  if [ -L "$OOSH_LINK" ]; then
    rm "$OOSH_LINK"
  elif [ -d "$OOSH_LINK" ]; then
    error.log "$OOSH_LINK is a real directory, not a symlink — refusing to switch"
    create.result 1 "not a symlink"
    return $(result)
  fi
  ln -s "$target_dir" "$OOSH_LINK"

  console.log "Switched to: $branch"
  console.log "$OOSH_LINK -> $target_dir"
  export OOSH_MODE="$branch"
  export OOSH_DIR="$target_dir"
  create.result 0 "$branch"
  return $(result)
}
oo.mode.completion.branch() {
  ls -d "$(oo.mode.base.get)"/*/ 2>/dev/null \
    | xargs -I{} basename {} \
    | grep -v '^\.'
}

oo.checkout() # <version> # clone and switch to a remote branch in the components base directory
{
  local version="$1"

  if [ -z "$version" ]; then
    error.log "Usage: oo checkout <version>"
    return 1
  fi

  # Get base directory
  local base
  base=$(oo.mode.base.get)
  if [ -z "$base" ] || [ ! -d "$base" ]; then
    error.log "No OOSH components base set. Run: oo mode.base.set <path>"
    return 1
  fi

  # Get repo URL from current oosh git repo
  local repo_url
  repo_url=$(git -C "$OOSH_DIR" remote get-url origin 2>/dev/null)
  if [ -z "$repo_url" ]; then
    error.log "Cannot determine git remote URL from $OOSH_DIR"
    return 1
  fi

  # Derive directory name: strip prefixes like test/, use dots for remaining slashes
  local dirname="$version"
  dirname="${dirname#test/}"
  dirname="${dirname#feature/}"
  dirname="${dirname#bugfix/}"
  dirname=$(echo "$dirname" | tr '/' '.')

  local target_dir="$base/$dirname"

  if [ -d "$target_dir" ]; then
    # Directory exists — check if it's a git repo and pull
    if [ -d "$target_dir/.git" ] || [ -f "$target_dir/.git" ]; then
      info.log "Directory exists, pulling: $target_dir"
      if git -C "$target_dir" pull 2>/dev/null; then
        success.log "Pulled $version in $target_dir"
        create.result 0 "$target_dir"
        return $(result)
      else
        error.log "git pull failed in $target_dir"
        return 1
      fi
    else
      error.log "Directory exists but is not a git repo: $target_dir"
      return 1
    fi
  else
    # Clone new
    info.log "Cloning $version into $target_dir"
    if git clone "$repo_url" -b "$version" "$target_dir" 2>/dev/null; then
      success.log "Cloned $version to $target_dir"
      create.result 0 "$target_dir"
      return $(result)
    else
      error.log "git clone failed for branch '$version'"
      # Clean up partial clone
      rm -rf "$target_dir" 2>/dev/null
      return 1
    fi
  fi
}
oo.checkout.completion.version() {
  git -C "$OOSH_DIR" ls-remote --heads origin 2>/dev/null | sed 's|.*refs/heads/||'
}

oo.use() # <branch> <command> [args...] # run a command from a specific branch without switching
{
  local branch="$1"
  shift
  local command="$1"
  shift

  if [ -z "$branch" ] || [ -z "$command" ]; then
    error.log "Usage: oo use <branch> <command> [args...]"
    create.result 1 "missing branch or command"
    return $(result)
  fi

  local WORKTREE_BASE
  WORKTREE_BASE=$(oo.mode.base.get)
  local branch_dir="$WORKTREE_BASE/$branch"

  if [ ! -d "$branch_dir" ]; then
    error.log "Branch directory '$branch' not found in $WORKTREE_BASE"
    create.result 1 "branch not found"
    return $(result)
  fi

  if [ ! -f "$branch_dir/$command" ]; then
    error.log "Command '$command' not found in branch '$branch'"
    create.result 1 "command not found"
    return $(result)
  fi

  # Export logging stubs so target branch bootstrap can call them.
  # Older branches call important.log/console.log during this.init before
  # log is fully loaded — without these exports, "command not found" errors occur.
  # IMPORTANT: Do NOT export info.log — it's used as bootstrap guard in log line 78.
  # If info.log exists, log skips sourcing this, which breaks the target branch.
  { export -f console.log important.log warn.log error.log \
             debug.log success.log silent.log stop.log seq.puml.log; } 2>/dev/null

  # Execute from target branch with overridden OOSH_DIR
  OOSH_DIR="$branch_dir" "$branch_dir/$command" "$@"
}
oo.use.completion.branch() {
  ls -d "$(oo.mode.base.get)"/*/ 2>/dev/null \
    | xargs -I{} basename {} \
    | grep -v '^\.'
}
oo.use.completion.command() {
  # In completion context, $1 is $cur (word being completed), not the branch.
  # The branch value was already parsed into PARAM_branch in current.method.env.
  source "$CONFIG_PATH/current.method.env" 2>/dev/null
  local branch="$PARAM_branch"
  local branch_dir="$(oo.mode.base.get)/$branch"
  if [ -d "$branch_dir" ]; then
    ls "$branch_dir" 2>/dev/null | grep -v '^\.' | grep -v '\.md$'
  fi
}

oo.branches.check() # <featureBranchPrefix> <baseBranch> <startCommit> # show state of branches
{
  local featureBranchPrefix=$1
  shift
  local R=remotes/origin
  local baseBranch=$R/$1
  shift
  local startCommit=$1

  if [ -z $featureBranchPrefix ]; then
    error.log "No featureBranchPrefix given"
    exit 1
  fi
  if [ -z $baseBranch ]; then
    error.log "No baseBranch given"
    exit 1
  fi
  if [ -z $startCommit ]; then
    error.log "No startCommit given"
    exit 1
  fi

  # config
  padding1=".............................................................................."
  padding2="                                          "

  console.log
  console.log "==========================================================================="
  console.log "Update local repository (fetch --prune to remove all deleted branches)"
  git fetch --prune
  console.log "First commit for branches:"
  console.log `git show $startCommit`

  console.log
  console.log "==========================================================================="
  console.log "Check all relevant branches:"
  branches=`git branch -a --contains $startCommit | grep $R | grep -v $R/HEAD`
  for bl in $branches
  do
      b=`echo $bl | sed "s;$R/;;"`
      case "$b" in
      dev/neom|test/neom|master|dev|main|prod/WODA)
          ;;
      N1-104-embed-viewport-in-woda-metaverse-app|N1-356-create-persistent-structr-implementation-of-all-persistent-classes|feature/N1-424-cavrnus-component-styling|feature/neom/broken-startup-good-structrObjectLoad)
          console.log
          console.log ONHOLD: $b
          ;;
      *)
          NAME=`git log -1 --pretty=format:"%cn <%ce>" $bl`
          AGO=`git log -1 --pretty=format:"%cr" $bl`
          console.log
          console.log $b
          console.log "--> https://bitbucket.org/donges/eamd.ucp/branch/$b"
          console.log "    "`printf "%s%s - %s\n" "$NAME" "${padding2:${#NAME}}" "${AGO}"`

          # old, not deleted
          LONGAGO=`echo $AGO | grep -v day | grep -v hour | grep -v minute | grep -v second`
          if [[ -n "$LONGAGO" ]]; then
              error.log "Branch is old (Last commit ${LONGAGO})."
          fi

          # check name: ${featureBranchPrefix}
          BRANCH_START=${b::`echo -n ${featureBranchPrefix} | wc -c`}
          if [[ "${BRANCH_START}" != ${featureBranchPrefix} ]]; then
              error.log "Branch name must start with ${featureBranchPrefix} (not: ${BRANCH_START}...)."
          fi

          # check name: N1-<no>
          JIRA_NUMBER=`echo -n $b | grep -e "N1-[0-9][0-9][0-9]"`
          if [[ -z ${JIRA_NUMBER} ]]; then
              error.log "Branch name must contain a JIRA issue number."
          fi

          # merged and not deleted?
          MY_COMMIT=`git log -1 --pretty=format:"%H" $bl`
          COMMON_COMMIT=`git merge-base $bl $baseBranch`
          if [[ "$MY_COMMIT" == "$COMMON_COMMIT" ]]; then
              error.log "Branch is merged but not deleted."
          else
              console.log "Here are the changes compared to branch: $R/dev/neom"
              console.log "$(git diff --stat $R/dev/neom...$bl)"
          fi

          ;;
      esac
  done
}

oo.state() # # initializes the state machine or shows the current state if already initialized
{
  local machine=SETUP_SERVER


  if state machine.exists ${machine}; then
    state of ${machine} list all
    source $CONFIG_PATH/current.state.machine.env
    if [ $state -lt 4 ]; then
      state machine.start - oo
    fi
  else
      debug.log "initalize ${machine}"
      private.init.state.machine ${machine}
  fi
}

private.init.state.machine() # <machine> # creates the state machine
{
  local machine=$1
  console.log "initialising state machine: ${machine}"
  
  source $OOSH_DIR/state

  state.machine.create ${machine} oo
  state.add remote.install.started               silent 
  state.add local.install.started                silent 
  state.add priviledges.checked                  silent 
  state.add 20                                   silent 
  state.add user.rights.only                     silent
  state.add user.installation.done               silent
  state.add user.mode.release                    silent
  state.add user.mode.dev                        silent
  state.add 30                                   silent  
  state.add root.rights                          silent 
  state.add root.shared.dev.folder.created       silent 
  state.add root.dev.keys.installed              silent 
  state.add root.installation.done               silent 
  state.add 40                                   silent 
  state.add user.shared.dev.folder.linked        silent 
  state.add user.state.machine.synced.with.root  silent 
  state.add 50                                   silent 
  state.add headless.setup.started               silent 
  state.add headless.setup.finished              silent 
  state.add 60                                   silent 
  state.add once.setup.started                   silent 
  state.add once.setup.finished                  silent 

  state.next
  state.machine.start oo
  state.next # remote.install.started
  state.next # root.rights
  state.list

          console.log "
        
        additional state next: root.shared.dev.folder.created
        === START =======================

        "


        state next # root.shared.dev.folder.created

        console.log "
        
        additional state next
        === DONE =======================

        "
  #state.next # root.shared.dev.folder.created

  #state.add - does.not.work
}

private.check.remote.install.started() {
  if [ -n "$SSH_CONFIG_FROM_REMOTE" ]; then
    success.log "
    
    Remote installation started from  : $SSH_CONFIG_FROM_REMOTE
    Remote name used for this machine±: $SSH_CONFIG_NAME_USED_FOR_LOCAL
    "
    create.result 0 12 $1
  else
    warn.log "SSH_CONFIG_FROM_REMOTE not set. No remote installation detected"
    success.log "remote.install.started: continue with local install"
    create.result 0 12 $1
  fi
  return $(result)
}

private.check.local.install.started() {
  if [ -f "$OOSH_DIR/this" ]; then
    create.result 0 "$OOSH_DIR/this exists"
  else
    create.result 1 "$OOSH_DIR/this does not exist"
  fi
}

private.check.priviledges.checked() # # RESULT will be the follow up state
{
  if [ "$USER" = "root" ]; then
    create.result 0 "30"
  else
    create.result 1 "user privilidges"
    if private.test.sudo.priviledges; then
      # RESULT will be the follow up state: [30]="root.rights""
      create.result 0 "30"
    else
      # RESULT will be the follow up state: [20]="user.rights.only"
      create.result 1 "20"
    fi
  fi

}

private.test.sudo.priviledges() {
  if [ -f ~/.sudo_as_admin_successful ]; then
    create.result 0 "sudo privilidges active"
    return $(result)
  else
    if [ -n "$SUDO" ]; then
      $SUDO touch ~/.sudo_as_admin_successful
      if [ -f ~/.sudo_as_admin_successful ]; then
          rm ~/.sudo_as_admin_successful
          create.result 0 "sudo privilidges by password"
          return $(result)
      fi
    fi
  fi

  if [ "$HOME" = "/root" ];then
          create.result 0 "sudo privilidges not required because USER is ROOT"
          return $(result)
  fi
  
  create.result 1 "no sudo privilidges"
  return $(result)
}

private.check.user.rights.only() {
  source state
  state.check SETUP_SERVER priviledges.checked oo
  if [ "$RESULT" = "20" ]; then
    create.result 0 "20"
    return $(result)
  fi
  if [ "$RESULT" = "30" ]; then
    create.result 0 "30"
    return $(result)
  fi
  create.result 1 "Something went wrong! \n$RESULT"
  return $(result)
}

private.check.user.installation.done() {
  if [ -d $HOME/oosh ]; then
    create.result 0 "$HOME/oosh exists"
  else
    create.result 1 "$HOME/oosh does not exist"
  fi
}

private.check.user.mode.release() {
  if [ "$OOSH_MODE" = "released" ]; then
    create.result 0 "OOSH_MODE=$OOSH_MODE"
  else
    create.result 1 "not in mode released!   OOSH_MODE=$OOSH_MODE"
  fi
  return $(result)
}

private.check.user.mode.dev() {
  if [ "$OOSH_MODE" = "dev" ]; then
    create.result 0 "OOSH_MODE=$OOSH_MODE"
  else
    create.result 1 "not in mode: dev!   OOSH_MODE=$OOSH_MODE"
    console.log "
    
    you can switch there manualy with
    
    oo mode.dev
    "
  fi
  return $(result)
}

private.check.root.rights() {
  source state
  state.check SETUP_SERVER priviledges.checked oo
  if [ "$RESULT" = "20" ]; then
    create.result 1 "21"
    return $(result)
  fi
  if [ "$RESULT" = "30" ]; then
    create.result 0 "30"
    return $(result)
  fi
  create.result 1 "Something went wrong! \n$RESULT"
  return $(result)
}


private.check.root.shared.dev.folder.created() {
  #check.debug.level 6
  #source user

  user get home
  if [ -z "$USER" ]; then
    warn.log "no user set"
    USER=$(user get name)
    console.log "fixed user: $USER"
  fi
  
  if [ ! "$USER" = "root" ]; then
    local currentHome="$( user get home $USER )"
    # this.absolutePath "$currentHome/.."
    # debug.log "absolutePath of \"$currentHome\..\": $RESULT"
    local dir="$( user get basehome $USER )"
    console.log "dir=$dir"
    local currentUser=$( echo $currentHome | line replace.sedquoted "$dir/")
    console.log "currentUser=$currentUser"

    error.log "This state can only be executed by root
    
    please provide your sudo password to install oosh into root"
    if (sudo ~/oosh/init/oosh mode user user.$USER $OOSH_SSH_CONFIG_HOST dev); then
      # after root installation back as user
      config list
      sudo chown -R developking:dev "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
      sudo chmod -R g+w "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
      user group.add $paramerUser dev
      source $CONFIG

      console.log "updated config in user $USER:"
      config list      
      mv $currentHome/oosh $currentHome/oosh.http
      ln -s "$OOSH_DIR" oosh

      private.install.dev.configs
      RETURN_VALUE=0
    else
      RETURN_VALUE=$?
      error.log "could not install root as user $USER: $(errno $RETURN_VALUE)"
    fi


    create.result "$RETURN_VALUE" "installed root form user $user" "$1"
    return $(result)
  fi
  
  #set -x


  local devHome="$( user get home developking )"
  if [ -z "$devHome" ]; then
    user create developking
    user group.add dev developking
    devHome="$( user get home developking )"
  fi
  # echo  "absolutePath of \"$devHome\..\"..."
  # this.absolutePath "$devHome/.."
  # debug.log "absolutePath of \"$devHome\..\": $RESULT"
  local dir="$( user get basehome developking )"
  console.log "dir=$dir"
  
  #return 2
  
  if [ -d "$dir/shared/dev" ];then
    success.log "$dir/shared/dev exists"
    create.result 0 "root.shared.dev.folder.created" $1
  else
    console.log "creating $dir/shared/dev"
    mkdir -p "$dir/shared/dev/Workspaces"
    mkdir -p "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh"
    mkdir -p "$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh"

    $SUDO user group.add dev $USER
    #cp -r $HOME/oosh "$dir/shared/dev/."
    
    
    $SUDO chown -R developking:dev "$dir/shared/dev/"
    #find "$dir/shared/dev/oosh" -type d -print0 | xargs -0 chmod 2775
    #find "$dir/shared/dev/oosh" -type f -print0 | xargs -0 chmod +grwx


    cd "$dir/developking/"
    oo.cmd wget
    oo.cmd tree
    #tree -a -L 2 /root/

    if [ ! -d /root/.ssh ]; then
      warn.log "root not initialized as an ssh user"
      ssh-keygen -t rsa -q -f "/root/.ssh/id_rsa" -N ""
      user ssh.create.folders
        {
      echo "
Host WODA.test
 User root
 Port 22
 HostName 178.254.18.182
 IdentityFile ~/.ssh/id_rsa

Host WODA.dev.root
 User root
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_rsa
 
Host WODA.dev
 User developking
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_rsa
      "

      } >~/.ssh/config      
    fi
    
    export DEVELOPKING_SOURCE_SERVER=test.wo-da.de

    wget -r -np --cut-dirs=9 -R "index.html*" "https://${DEVELOPKING_SOURCE_SERVER}/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/NewUserStuff/scripts/templates/developking.ssh"
    RETURN_VALUE=$?
    if ! [ "$RETURN_VALUE" = "0" ]; then 
      error.log "while downloading developking.ssh"
      return $RETURN_VALUE; 
    fi
    #tree -a -L 2 /root/

    chown -R developking:dev "$dir/developking/${DEVELOPKING_SOURCE_SERVER}/developking.ssh"
    mv "$dir/developking/${DEVELOPKING_SOURCE_SERVER}/developking.ssh" "$dir/developking/.ssh"
    rm -rf "$dir/developking/${DEVELOPKING_SOURCE_SERVER}"

    private.install.dev.configs


    cd "$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh"
    git clone 2cuGitHub:Cerulean-Circle-GmbH/once.sh.git main
    RETURN_VALUE=$?
    if ! [ "$RETURN_VALUE" = "0" ]; then return $RETURN_VALUE; fi

    if [ ! -z ${OOSH_INSTALL_SOURCE} ] && [ -d ${OOSH_INSTALL_SOURCE} ]; then
      important.log "<oo> Install oosh from ${OOSH_INSTALL_SOURCE}"
      mkdir -p dev
      rsync -a ${OOSH_INSTALL_SOURCE}/ dev/
    else
      important.log "<oo> Install oosh from 2cuGitHub:Cerulean-Circle-GmbH/once.sh.git"
      git clone 2cuGitHub:Cerulean-Circle-GmbH/once.sh.git dev
      RETURN_VALUE=$?
      if ! [ "$RETURN_VALUE" = "0" ]; then return $RETURN_VALUE; fi
      cd dev
      if [ -z ${OOSH_BRANCH} ]; then
        OOSH_BRANCH=dev
      fi
      important.log "<oo> Install oosh with branch ${OOSH_BRANCH}"
      git checkout -t origin/${OOSH_BRANCH}
    fi



    # ln -s "$dir/shared/dev/oosh"
    # chown -h developking:dev "oosh"


    console.log "before config copy:
    SSH_CONFIG_NAME_USED_FOR_LOCAL
    $SSH_CONFIG_NAME_USED_FOR_LOCAL"

    local paramerUser="$( echo $SSH_CONFIG_NAME_USED_FOR_LOCAL | line replace 'user.' )"
    local currentHome="$( user get home $paramerUser )"
    info.log "paramerUser=$paramerUser"



    local currentUserDir=$( echo $currentHome | line replace.sedquoted "$dir/")
    info.log "currentUserDir=$currentUserDir"

    if [ -n "$paramerUser" ]; then
      currentHome="$dir/$currentUserDir"
    fi


    local currentConfig="$currentHome/config"
    info.log "currentConfig=$currentConfig"

    mkdir -p "$currentHome/.ssh/ids/"
    cp -r "$devHome/.ssh" "$currentHome/.ssh/ids/ssh.developking"

  set -x
    # link root config to sharedConfig
    cp -r "/root/config" "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
    rm -rf "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig/stateMachines"
    cp -r "$currentConfig/stateMachines" "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
    
    # link user config to sharedConfig
    mv "$currentConfig" "$currentConfig.initial"
    ln -s "$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig" "$currentConfig"
    chown -h $paramerUser:dev "$currentConfig"
    chown -R $paramerUser:dev "$dir/shared"
    git config --global --add safe.directory "$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh/dev"

    # TODO: This should be removed to only use /root/oosh in the PATH
    export PATH="$( echo $PATH | line replace.sedquoted "/root/oosh" "$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh/dev" )"

    #mv /root/config /root/config.initial
    cp -r config.initial/stateMachines/ config
  set +x



    export CONFIG="$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig/user.env"
    export CONFIG_FILE="user.env"
    export CONFIG_PATH="$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
    export OOSH_DIR="$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh/dev"
    export OOSH_MODE="dev"

    console.log "PATH=$PATH"
    console.log "CONFIG=$CONFIG"
    config save 
    
  
  set -x
    cd /root
    ln -s "$CONFIG_PATH" config
    chown -R developking:dev "$CONFIG_PATH"
    
    # Remove initial oosh version and link to shared oosh
    rm -rf oosh
    ln -s "$OOSH_DIR" oosh

    # Remove initial init script version and link to shared init script
    rm -rf init
    ln -s oosh/init init

    ls -la "$dir/shared/dev"
    tree -L 2 /home/shared
    ls -la /root


  set +x
    create.result 0 "root.shared.dev.folder.created" $1
  fi

  

  #check.debug.level 3
  return $(result)
}

private.check.root.dev.keys.installed() {
  return 0
}
private.check.root.installation.done() {
  return 0
}

private.check.user.shared.dev.folder.linked() {
  local devHome="$( user get home developking )"
  if [ -z "$devHome" ]; then
    error.log "user developking does not yet exist"
    return 2
  fi
  this.absolutePath "$devHome/.."
  info.log "absolutePath of \"$devHome\..\": $RESULT"
  local dir="$RESULT"

    export CONFIG="$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig/user.env"
    export CONFIG_FILE="user.env"
    export CONFIG_PATH="$dir/shared/EAMD.ucp/Scenarios/localhost/EAM/1_infrastructure/Once.sh/sharedConfig"
    export OOSH_DIR="$dir/shared/EAMD.ucp/Components/com/ceruleanCircle/EAM/1_infrastructure/Once.sh/dev"
    export OOSH_MODE="dev"

    cd $HOME
    if [ -L config ]; then
      success.log "config is alredy a link"
      ls -al config
      return 0
    else
      mv config "config.orig"
      ln -s "$CONFIG_PATH" config
      ln -s "$OOSH_DIR" oosh
    fi

  return 0
}

private.check.user.state.machine.synced.with.root() {
  return 0
}

private.check.headless.setup.started() {
  return 0
}

private.check.headless.setup.finished() {
  return 0
}

private.check.once.setup.started() {
  once init
  #once set.domain localhost
  #once stage.next
  return 0
}

private.check.once.setup.finished() {
  return 0
}

private.check.finished() {
  return 0
}

oo.install.dev.keys() {
    return 0
}

private.install.dev.configs() {
  dir=$( user get basehome )
  if [ -n "$dir" ]; then
    if ! ossh config.get 2cuGitHub; then
      success.log "creating config 2cuGitHub"
      ossh config.create 2cuGitHub git@github.com:Cerulean-Circle-GmbH/once.sh.git "$dir/developking/.ssh/id_rsa"
      ossh config.save.last
      ssh-keyscan github.com >> ~/.ssh/known_hosts
    fi
    if ! ossh config.get 2cuBitbucket; then    
      success.log "creating config 2cuBitbucket"
      #ossh config.create 2cuBitbucket git@bitbucket.org:donges/eamd.ucp.git "$OOSH_DIR/templates/user/developking.ssh/id_rsa"
      ossh config.create 2cuBitbucket git@bitbucket.org:donges/eamd.ucp.git "$dir/developking/.ssh/id_rsa"
      ossh config.save.last
      ssh-keyscan bitbucket.org >> ~/.ssh/known_hosts
    fi
  fi

  return 0
}

# DEPRECATED — dangerous internal test utility
private.oo.tmp.cleanup.testing() { # # clean test BE CAREFULL removes oosh and SSH KEYS completly from the system
    sudo /root/oosh/init/deinstall.oosh
    sudo rm -rf /root/config.initial
    sudo rm -rf /root/oosh.http
    sudo rm -rf /root/ssh.root.u*
    sudo userdel -r developking
    #sudo rm -rf /home/shared
    rm config
    mv config.initial config
    source ~/config/user.env
    #oo update
    rm -rf oosh.http
    sudo rm -rf .ssh
    init/deinstall.oosh
}











oo.install.dev() # # DEPRECATED install the official dev oosh. GitHub keys required
{
  error.log "oo.install.dev() is deprecated"

  cd $OOSH_DIR
  cd ..

  check dir /var/dev not exists \
    call once su.mkdir.dev $USER
  
  private.install.dev.configs
  # ossh config.create 2cuGitHub git@github.com:Cerulean-Circle-GmbH/once.sh.git '~/.ssh/ids/ssh.marcel.iMac/private_key/donges.mcdonges.fritz.box.private_key'
  # ossh config.save.last
  ossh pull.id iMac

  cd /var/dev/Workspaces/2cuGitHub
  check dir /var/dev/Workspaces/2cuGitHub/once.sh/.git not exists \
    call git clone 2cuGitHub:Cerulean-Circle-GmbH/once.sh.git
  check dir ~/oosh exists \
    call mv ~/oosh/ ~/oosh.https
  ln -s /var/dev/Workspaces/2cuGitHub/once.sh ~/oosh
  check dir ~/init.bak exists \
    call rm -r ~/init.bak
  check dir ~/init.bak not exists \
    call mv ~/init ~/init.bak

  
}

## oo.mode.fullDebug — removed: use `oo mode fullDebug` (worktree-based switching)

oo.cmd() # <cmd> <?packageName> # checks if <cmd> is installed and installes it with: $SUDO $PM <?packageName>
{
    current=$1
    shift
    package=$1

    if [ -z "$1" ]; then
        package=$current
    else
      shift
      package=$1
    fi   
    
    if [ -z "$OOSH_PM" ]; then
      console.log "no PM found...checking" 
      oo.pm.discover
    fi
    if ! [ -x "$(command -v $current)" ]; then
        console.log "no $current"
        if [ -n "$OOSH_PM" ]; then
          case $current in
            eamd)
              once load $current tla/EAMD/UcpComponentSupport/1.0.0/src/sh/eamd
              export PATH="$PATH:$ONCE_LOAD_DIR"
              hash -d eamd    #clears the command cache for eamd
              #hash -r   #clears the command cache completley
              ;;
            oosh)
              once load $current com/ceruleanCircle/EAM/1_infrastructure/OOSH/1.0.0/src/sh/oosh
              ;;
            once)
              once load once.sh tla/EAM/layer1/Thinglish/Once/latestServer/src/sh/once.sh
              cd $ONCE_LOAD_DIR
              mv once.sh once
              private.stage status
              ;;
            # npm)
            #   # if ! which $current > /dev/null; then
            #     once.su.npm.install
              # else
              #   console.log "$current allready installed!";
              # fi
              # exit;
            # ;;
            mkcert)
              once.su.mkcert.install
              ;;
            update)
              if [ -z "$OOSH_PM_UPDATED" ]; then
                $SUDO -S apt-get update
              else
                warn.log "Package manager already updated with: $OOSH_PM_UPDATED"
              fi
              ;;
            errno)
              oo cmd moreutils
              ;;
            *)
              if [ "$OOSH_PM" = "brew install" ]; then
                SUDO=""
              fi
              $SUDO $OOSH_PM $package
            esac
        else
            console.log "no package manger"
        fi
        if [ -n "$1" ]; then
          shift
        fi
    fi
    RETURN=$1
}

oo.pm() # # checks if the pm is well configured
{
  if [ -n "$OOSH_PM" ]; then
    console.log "package manager is set:"
    console.log "for OOSH: $OOSH_PM"
    console.log "for ONCE: $ONCE_PM"
    if [ "$OOSH_PM" = "$ONCE_PM" ]; then
      success.log "package manager well configured"
      return 0
    else
      warn.log "package manager differ!
      use
      
        oo pm.discover
      
      to fix that
      "
      return 1
    fi
  fi
  OOSH_PM=
  private.check.all.pm
  console.log "PM: $OOSH_PM"

  RETURN=$1
}

oo.pm.discover() # # finds out OS and corresponding package manager (pm)
{
  OOSH_PM=
  private.check.all.pm
  console.log "OOSH_PM: $OOSH_PM"
  config save

  RETURN=$1
}

private.check.pm()             # checks for a package manager
{

    local packageManager=$1
    local packageManagerCommand=$2


    if [ -z "$packageManagerCommand" ]; then
        package=$packageManager
    fi   
    if ! [ -x "$(command -v $packageManager)" ]; then
        debug.log "no $packageManager"
    else
        if [ -z "$OOSH_PM" ]; then
            export OOSH_PM=$packageManagerCommand
            export OS_CMD_GROUP_ADD=$3
            export OS_CMD_USER_ADD=$4
            echo "Package Manager found: using $OOSH_PM somePackage"
            if [ "$packageManager" = "apt-get" ]; then
                if [ -z "$OOSH_PM_UPDATED" ]; then
                  OOSH_PM_UPDATED="$SUDO apt-get update"
                  #if [ "$ONCE_PRIVILEGE" = root ]; then
                    $OOSH_PM_UPDATED
                  # else 
                  #   PM="sudo $PM"
                  # fi
                else
                  echo "in case of installation errors try to call: apt-get update"
                fi
            fi
            config save os.commands "OS_CMD"
        fi
    fi
}

private.check.all.pm()         # adds tools and configurations to package manager (brew, apt-get, addgroup, adduser, dpkg, pkg)
{

    private.check.pm brew "brew install"    
    #once.check.pm apt "apt add"
    private.check.pm apt-get "apt-get -y install" "groupadd -f" "useradd -g dev"
    private.check.pm apk "apk add" "addgroup" "adduser -g dev"
    private.check.pm dpkg "dpkg install"
    private.check.pm pkg "pkg install"
    private.check.pm pacman "pacman -S"

 
}

oo.install() { # <scriptClass> <path> # installs an external oo script from <path> into oosh/external as a link
  local class="$1"
  shift
  local path="$1"
  shift

  if [ -z "$path" ]; then
    this.absolutePath .
    path=$RESULT
  fi

  this.absolutePath $path
  path=$RESULT

  debug.log "path: $path"
  if [ -L "$OOSH_DIR/external/$class" ]; then
    console.log "updating links: $OOSH_DIR/external/$class -> $path/$class"
    rm $OOSH_DIR/external/$class
    ln -s $path/$class $OOSH_DIR/external/$class
  fi

  if [ -f "$path/$class" ]; then
    console.log "installing link: $class -> $path/$class"
    rm $OOSH_DIR/external/$class
    ln -s "$path/$class" "$OOSH_DIR/external/$class"
  fi

  if [ -f "$OOSH_DIR/$class" ]; then
    console.log "installing: $class -> $path/$class"
    mv "$OOSH_DIR/$class" "$path/$class"
    ln -s "$path/$class" "$OOSH_DIR/external/$class"
  fi

}

oo.install.completion() {
  compgen -d $OOSH_DIR/$1
}

oo.cmd.find() { # <cmd> # finds the <cmd> on the apt repositories
  oo cmd apt-file
  apt-file update
  apt-file search --regexp ".*$1$"
}


oo.su() {
  if [ "$USER" = "root" ]; then
    cd $OOSH_DIR/su
    echo ${GREEN}root command are:
    ls -al
    echo ${NORMAL}
    bash
  else
    error.log "You are not root! 
        ${BOLD_YELLOW}USER: $USER"

    warn.log "trying to switch to root:
    
    Type user $USER"
    sudo su
  fi
}

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

  is the management interface for the oosh environment
  create new classes with: oo new <class>

  The oosh lifecycle
    1. oo mode.dev  # All development exclusively in dev mode
    2. oo update    # Updating oosh environment to the latest
    3. oo commit    # Commit local changes to the oosh dev global environment
    4. oo release   # Publish the dev environment to the main environment as well as switching to main mode. This is the commercial mode for using the oosh environment
    5. oo mode.dev  # Switch back do dev mode to start development cycle again


  ${CYAN}\$OOSH_DIR${NORMAL}           is where it is installed: $OOSH_DIR
  ${CYAN}\$OOSH_DIR/${GREEN}init/oosh${NORMAL} is the ${YELLOW}initial${NORMAL} installer based on the ${GREEN}sh${NORMAL} Shell
  ${CYAN}\$OOSH_DIR/${GREEN}this${NORMAL}      is ${YELLOW}starting${NORMAL} the oosh environment and provides common oo functionality

  Usage:
  $this: command   description and Parameter

      usage     prints this dialog while it will print the status when there are no parameters          
      ----      --------------------------"
  this.help
  echo "
  ${GREEN}Examples${NORMAL} 
    $this new myNewCommand
    $this update
  "
}

oo.start() # <method> <parameter> # default start and parameter processing
{
  #echo "sourcing init"
  source this

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

  this.start "$@"
}

oo.start "$@"

