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


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"

    sed -i '0,/----/{s/----/'"$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"

    sed -i '0,/--------------------------/{s/--------------------------/'"$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"

    sed -i '0,/test_description/{s/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"

    sed -i '0,/new_argument(s)/{s/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"

    sed -i '0,/new_expect/{s/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.stage.to.prod
}

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

oo.mode.dev() # # switches to dev branch
{
  cd $OOSH_DIR
  git pull
  git checkout dev
  git push
  export OOSH_MODE="dev"
  config save oosh OOSH
}

oo.mode() # # shows branch status
{
  cd $OOSH_DIR
  source $CONFIG_PATH/oosh.env
  GIT_PUSH_ORIGIN="$( git remote -v | line find push | line split "it" | line 'select' 2 | line unquote )"
  
  if [ "$GIT_PUSH_ORIGIN" = 'Hub:Cerulean-Circle-GmbH/once.sh.g' ]; then
    console.log "push origin correct"
  else
    warn.log "push origin wrong: 
    
    is         [$( git remote -v | line find push )]
    should be  [origin     2cuGitHub:Cerulean-Circle-GmbH/once.sh.git (push)] 

    please do git clone with ssh url that starts with: git clone git@github...
    or type:
      git remote set-
      url origin 2cuGitHub:Cerulean-Circle-GmbH/once.sh.git"
  fi
  git status
  console.log "OOSH_MODE=$OOSH_MODE"
}

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 get.config 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 get.config 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
}

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() # # switches to fullDebug branch
{
  cd $OOSH_DIR
  git pull
  git checkout fullDebug
  git merge dev
  git push
}

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.find.cmd() { # <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 "$@"

