#!/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>"
if ! [ "$(type -t info.log)" = "function" ]; then
  source this; 
fi  

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

  Usage:
  $this: command    <?message <?level> text> object value condition <?fix.message <?level> text> <?fix \"method parameter\"> 

  where \'object\' is one of    
      argument      checks \$1
      function      initializes a new user config
      file          checks if \$CHECK_FILE   
      dir           checks if \$CHECK_FILE   
    
  where \'condition\' is one of
    not
    exists
    empty
    readable
    writable
    executable    
  
  Examples
    $this message \"test the west\" file .oce not exists
    $this message test     fix.message success \"repair it all\"      fix test.repair      file .once not exists 
    $this message test     fix.message success \"repair it all\"      fix test.repair      dir  config    exists 
    
    $this message test fix.message success repair   file .once not exists fix success.log \"success is cool\"    
    $this message test file .once not exists fix.message success repair fix success.log \"success is cool\"    
    
    $this message test fix.message success repair fix success.log \"success is cool\"   file .once not exists 

    $this file ./test.debug exists fix no.test.debug
    $this argument exists

    $this file /Users/marcel/config/stateMachines/test.states.env exists fix error.log \"does not exist\"

  "
}

check.condition() {
  local condition=$1
  shift

  local value=$1
  shift

  if [ -n "$not" ]; then 
    not="!"
  fi
  debug.log "test $not \"$condition\" \"$value\""

  test $not "$condition" "$value"
  TEST_RESULT=$?
  if [ "$TEST_RESULT" = 0 ]; then
    create.result 0 "$condition $value true   :$*"
    if [ -n "$CHECK_MESSAGE" ]; then 
      success.log "check    ok: $CHECK_MESSAGE"
    fi
  else
    create.result 1 "$condition $value false"
    if [ -n "$CHECK_MESSAGE" ]; then 
      warn.log "check failed: $CHECK_MESSAGE"
    fi
    private.check.fix.execute
  fi
  return "$(result)"
}

check.message()
{
  local level=$1
  CHECK_MESSAGE_LEVEL="console"

  if (this.functionExists "$level.log"); then
    CHECK_MESSAGE_LEVEL=$1
    CHECK_MESSAGE=$2 
    shift
    shift
  else
    CHECK_MESSAGE=$1
    shift
  fi
  #"$CHECK_MESSAGE_LEVEL".log "$CHECK_MESSAGE"
  RETURN=$1
}

check.fix.message()
{
  local level=$1
  CHECK_FIX_MESSAGE_LEVEL="console"

  if (this.functionExists $level.log); then
    CHECK_FIX_MESSAGE_LEVEL=$1
    CHECK_FIX_MESSAGE=$2 
    shift
    shift
  else
    CHECK_FIX_MESSAGE=$1
    shift
  fi

  RETURN=$1
}

check.file.completion() {
  ls $1*
}

check.directory() {
  check.dir "$@"
}

check.dir()
{
  unset FILE
  CHECK_DIR=$1
  info.log "set DIR: $CHECK_DIR"
  
  if [ -z "$CHECK_DIR" ]; then
    create.result 2 "check.dir: no directory specified" "$1"
    error.log "$RESULT"
  else
    shift
    create.result 0 "check.dir: $CHECK_DIR"
  fi

  if [ -f "$CHECK_DIR" ]; then
    create.result 1 "check.dir: $CHECK_DIR is a file" "$1"
    warn.log "$RESULT"
    CHECK_FILE=$CHECK_DIR
    unset DIR
    exit "$(result)"
  fi

  RETURN=$1
}

check.file()
{
  unset DIR
  CHECK_FILE=$1
  info.log "set FILE: $CHECK_FILE"

### TODO PROBLEM: this is case insensitive on case insensitive filesystems like on Mac OSX default 
# if [ -f "$dir/$filename" ]; then
# 
# Solution
#   local fileExistsCaseSensitive="$( find "$dir" -type f -name "$filename" )"
#   if [ -n "$fileExistsCaseSensitive" ]; then  
  
  if [ -z "$CHECK_FILE" ]; then
    create.result 2 "check.dir: no file specified"
    error.log "$RESULT"
  else
    shift
  fi

  if [ -d "$CHECK_FILE" ]; then
    create.result 1 "check.file: $CHECK_FILE is a dir"
    warn.log "$RESULT"
    CHECK_DIR=$CHECK_FILE
    unset FILE
    exit "$(result)"
  fi

  local dir=$(dirname $CHECK_FILE)
  local filename=$(basename $CHECK_FILE)
  local fileExistsCaseSensitive="$( find "$dir" -maxdepth 1 -type f -name "$filename" )"
  if [ -z "$fileExistsCaseSensitive" ]; then 
    warn.log "The filesystem is case insensitive and the case sensitive file $dir/$filename DOES NOT exist!"
  fi

  RETURN=$1
}

check.user()
{
  CHECK_USER=$1
  info.log "set USER: $CHECK_USER"
  
  if [ -z "$CHECK_USER" ]; then
    create.result 2 "check.user: no user specified"
    error.log "$RESULT"
  else
    shift
  fi

  if ! this.isNumber "$(id -u "$CHECK_USER")" ; then
    create.result 1 "check.user: $CHECK_USER is not recognised"
    warn.log "$RESULT"
    exit "$(result)"
  fi

  RETURN=$1
}

check.root()
{
  CHECK_ROOT=$1
  info.log "set ROOT: $CHECK_ROOT"
  
  if [ -z "$CHECK_ROOT" ]; then
    create.result 2 "check.root: no root specified"
    error.log "$RESULT"
  else
    shift
  fi

  if [ $(id -u "$CHECK_ROOT") -eq 0 ]; then
    create.result 1 "check.root: $CHECK_ROOT is not recognised"
    warn.log "$RESULT"
    exit "$(result)"
  fi

  RETURN=$1
}

check.exists()
{
  if [ -n "$CHECK_DIR" ]; then
      condition="-d $CHECK_DIR"
      info.log "set dir condition: $condition"
  fi
  if [ -n "$CHECK_FILE" ]; then
      condition="-f $CHECK_FILE"
      info.log "set file condition: $condition"
  fi
  if [ -n "$CHECK_USER" ]; then
    if this.isNumber $(id -u "$CHECK_USER") ; then
        condition="-n $CHECK_USER"
        info.log "set user condition: $condition"
    fi
  fi
  check.condition $condition

  RETURN=$1
}

check.admin()
{
  CHECK_ADMIN=$1
  if [ -n "$CHECK_ADMIN" ]; then
      condition="$(id -u "$CHECK_ADMIN") -eq 0"
      info.log "set admin user condition: $condition"
  fi
  echo "condition: $condition"
  check.condition $condition

  RETURN=$1
}

check.not() {
  not=true
  RETURN=$1
}

check.and() {
  debug.log "and"
  RETURN=$1
}

check.fix()
{
  FIX_FUNCTION=$1
  shift
  FIX_ARGUMENTS="$*"
  if (this.functionExists $FIX_FUNCTION); then
    debug.log "fixing with: $FIX_FUNCTION $*"
  else
    error.log "fix method: $FIX_FUNCTION does not exist"
    exit 1
  fi
  shift


  private.check.fix.execute
  return $?

  RETURN=$1
}


private.check.fix.execute()
{
  if [ -n "$TEST_RESULT" ]; then
      if [ "$TEST_RESULT" = 0 ]; then
        create.result 0 "nothing to fix...test was ok"
        unset RETURN
        debug.log "$RESULT"
          exit "$(result)"
      else
        if [ -n "$FIX_FUNCTION" ]; then
          debug.log "$FIX_FUNCTION $FIX_ARGUMENTS"
          $FIX_FUNCTION $FIX_ARGUMENTS
          create.result $? "fixed it with $FIX_FUNCTION $FIX_ARGUMENTS" "$1"

          if [ -n "$CHECK_FIX_MESSAGE" ]; then 
            "$CHECK_FIX_MESSAGE_LEVEL".log "$CHECK_FIX_MESSAGE"
          fi
          unset RETURN
          exit "$(result)"
        else
          debug.log "no fixfunction: $FIX_FUNCTION"
        fi
      fi
  else
    debug.log "not yet tested"
  fi
}


check.call()
{
  FIX_BY_CALL="$*"

  private.check.call.execute
  return $?
}


private.check.call.execute()
{
  if [ -n "$TEST_RESULT" ]; then
      if ! [ "$TEST_RESULT" = 0 ]; then
        create.result 0 "nothing to fix...test was ok"
        unset RETURN
        debug.log "$RESULT"
          exit "$(result)"
      else
        if [ -n "$FIX_BY_CALL" ]; then
          debug.log "$FIX_BY_CALL"
          $FIX_BY_CALL
          create.result $? "fixed it with $FIX_BY_CALL" "$1"

          if [ -n "$CHECK_FIX_MESSAGE" ]; then 
            "$CHECK_FIX_MESSAGE_LEVEL".log "$CHECK_FIX_MESSAGE"
          fi
          unset RETURN
          exit "$(result)"
        else
          debug.log "no fixfunction: $FIX_FUNCTION"
        fi
      fi
  else
    debug.log "not yet tested"
  fi
}


check.start()
{
  this.start "$@"
  debug.log "check result $TEST_RESULT"
  return "${TEST_RESULT:-0}"
}

check.start "$@"

