#!/usr/bin/env bash

# shellcheck shell=bash

# ``````````````````````````````````````````````````````````````````````````````
# Function name: cli_distributor()
#
# Description:
#   Modules distributor.
#
# Usage:
#   cli_distributor
#
# Examples:
#   cli_distributor
#

function cli_distributor() {

  # shellcheck disable=SC2034
  local _FUNCTION_ID="cli_distributor"
  local _STATE=0

  local _argv=("$@")

  # shellcheck disable=SC2154
  if [[ "${_argv[0]}" == "help" ]] ; then

    if [[ "$_in_module" -eq 0 ]] ; then

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        cli_help

      else

        init_module "${_argv[@]}"
        module_help

      fi

    else

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        init_module "${_argv[@]}"
        module_help

      else

        echo

        nmap --script-help="${_argv[1]}"

        echo

      fi

    fi

  elif [[ "${_argv[0]}" == "list" ]] ; then

    if [[ "$_in_module" -eq 0 ]] ; then

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        cli_show

      else

        printf "stdout: %s\\n" "unknown module"

      fi

    else

      printf "stdout: %s\\n" "unknown command"

    fi

  elif [[ "${_argv[0]}" == "set" ]] ; then

    if [[ "${#_argv[1]}" -eq 0 ]] ; then

      printf "stdout: %s\\n" "invalid key"

    else

      if [[ "$_in_module" -eq 0 ]] ; then

        # shellcheck disable=SC2034
        _variables_stack=("${_session_variables[@]}")

        set_config "${_argv[@]}"

        _session_variables=("${_variables_stack[@]}")

      else

        # shellcheck disable=SC1090
        source "$_module_cfg"

        _sess_num="${#_session_variables[@]}"

        if [[ "${#_module_variables[@]}" -eq 0 ]] ; then

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}")

          set_config "${_argv[@]}"

          _session_variables=("${_variables_stack[@]:0:${_sess_num}}")

        else

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

          set_config "${_argv[@]}"

          _session_variables=("${_variables_stack[@]:0:${_sess_num}}")
          _module_variables=("${_variables_stack[@]:${_sess_num}}")

          printf "_module_variables=(\"%s\")\\n" "${_module_variables[@]}" > "$_module_cfg"

        fi

        init_module "$_ld_module"

        # shellcheck disable=SC2034
        __cli_banner="$_fname"

        # shellcheck disable=SC1090
        source "$_module_cfg"

      fi

    fi

  elif [[ "${_argv[0]}" == "config" ]] ; then

    if [[ "$_in_module" -eq 0 ]] ; then

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        # shellcheck disable=SC2034
        session_type="main"

        # shellcheck disable=SC2034
        _variables_stack=("${_session_variables[@]}")

        show_config "${_argv[@]}"

      else

        _st=0
        for i in "${_argv[@]:1}" ; do

          for j in "${modules_list[@]}" ; do

            if [[ "$i" == "$j" ]] ; then

              _st=1
              _fname="$j"

            fi

          done

        done

        if [[ "$_st" -eq 1 ]] ; then

          # shellcheck disable=SC2034
          session_type="module"

          init_module "${_argv[@]}"

          if [[ "${#_module_variables[@]}" -eq 0 ]] ; then

            # shellcheck disable=SC2034
            true

          else

            # shellcheck disable=SC2034
            _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

          fi

          show_config "${_argv[@]}"

        else

          # shellcheck disable=SC2034
          session_type="main"

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}")

          _tc=0
          for i in "${_variables_stack[@]}" ; do

            _pvar=$(echo "$i" | awk -v FS="(;|;)" '{print $3}')

            if [[ "$_pvar" == "${_argv[1]}" ]] ; then

              show_config "${_argv[@]}"

            else

              _tc=$((_tc + 1))

            fi

          done

          if [[ "$_tc" -eq ${#_variables_stack[@]} ]] ; then

            printf "stdout: %s\\n" "invalid key"

          fi

        fi

      fi

    else

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        # shellcheck disable=SC1090
        source "$_module_cfg"

        # shellcheck disable=SC2034
        session_type="module"


        if [[ "${#_module_variables[@]}" -eq 0 ]] ; then

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}")

          show_config "${_argv[@]}"

        else

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

          show_config "${_argv[@]}"

        fi

      else

        # shellcheck disable=SC1090
        source "$_module_cfg"

        # shellcheck disable=SC2034
        # It's a fake - We use it for checking specific key.
        session_type="main"

        if [[ "${#_module_variables[@]}" -eq 0 ]] ; then

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}")

        else

          # shellcheck disable=SC2034
          _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

        fi

        show_config "${_argv[@]}"

      fi

    fi

  elif [[ "${_argv[0]}" == "reload" ]] ; then

    if [[ "$_in_module" -eq 0 ]] ; then

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        printf "stdout: %s\\n" "invalid param"

      else

        if [[ "${_argv[1]}" == "config" ]] ; then

          init_config
          init_session

          printf "stdout: %s\\n" "config reloaded"

        elif [[ "${_argv[1]}" == "modules" ]] ; then

          # shellcheck disable=SC2034
          modules_list=()
          # shellcheck disable=SC2034
          modules_full_list=()
          # ReInitialize modules.
          load_modules

          # shellcheck disable=SC2034
          for i in $(find "${_modules}" -name '*.cfg' -exec ls {} + | sort -k 10) ; do

            : >"$i"

          done

          printf "stdout: %s\\n" "modules reloaded"

        fi

      fi

    else

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        printf "stdout: %s\\n" "invalid param"

      else

        if [[ "${_argv[1]}" == "config" ]] ; then

          init_config
          init_session

          printf "stdout: %s\\n" "config reloaded"

        fi

      fi

    fi

  elif [[ "${_argv[0]}" == "use" ]] ; then

    _st=0
    for i in "${_argv[@]:1}" ; do

      for j in "${modules_list[@]}" ; do

        if [[ "$i" == "$j" ]] ; then

          _st=1
          _fname="$j"

        fi

      done

    done

    if [[ "$_st" -eq 1 ]] ; then

      _in_module=1

      # shellcheck disable=SC2034
      _ld_module="$_fname"

      init_module "$_ld_module"

      # shellcheck disable=SC2034
      __cli_banner="$_fname"

      if [[ -e "$_module_cfg" ]] ; then

        # shellcheck disable=SC1090
        source "$_module_cfg"

        _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

      else

        _variables_stack=("${_session_variables[@]}")

      fi

    else

      printf "stdout: %s\\n" "invalid module"

    fi

  elif [[ "${_argv[0]}" == "show" ]] ; then

    if [[ "$_in_module" -eq 0 ]] ; then

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        printf "stdout: %s\\n" "invalid module"

      else

        if [[ "${#_argv[2]}" -eq 0 ]] ; then

          _tc=0
          for i in "${modules_list[@]}" ; do

            if [[ "$i" == "${_argv[1]}" ]] ; then

              _in_module=0

              init_module "${_argv[@]}"
              module_show

            else

              _tc=$((_tc + 1))

            fi

          done

          if [[ "$_tc" -eq ${#modules_list[@]} ]] ; then

            printf "stdout: %s\\n" "invalid key"

          fi

        else

          _in_module=0

          init_module "${_argv[@]}"

          _count=0

          for i in "${_module_commands[@]}" ; do

            # shellcheck disable=SC2034
            _key_id=$(echo "$i" | awk -v FS="(;|;)" '{print $1}')
            # shellcheck disable=SC2034
            _key_var=$(echo "$i" | awk -v FS="(;|;)" '{print $3}')

            if [[ "${_argv[2]}" == "$_key_var" ]] ; then

              module_show "$_key_var"

              printf "  \\e[1;38m%s\\e[m:\\n\\n" "Description"

              printf "    %s\\n\\n" "$_key_id" | sed 's/\\n \+/\n    /g'

            elif [[ "${_argv[2]}" == "$_count" ]] ; then

              module_show "$_key_var"

              printf "  \\e[1;38m%s\\e[m:\\n\\n" "Description"

              printf "    %s\\n\\n" "$_key_id" | sed 's/\\n \+/\n    /g'

            fi

            _count=$((_count + 1))

          done

        fi

      fi

    else

      if [[ "${#_argv[1]}" -eq 0 ]] ; then

        _in_module=1

        module_show

      else

        _in_module=1

        _tc=0
        _count=0

        for j in "${_module_commands[@]}" ; do

          # shellcheck disable=SC2034
          _key_id=$(echo "$j" | awk -v FS="(;|;)" '{print $1}')
          # shellcheck disable=SC2034
          _key_var=$(echo "$j" | awk -v FS="(;|;)" '{print $3}')

          if [[ "${_argv[1]}" == "$_key_var" ]] ; then

            module_show "$_key_var"

            printf "  \\e[1;38m%s\\e[m:\\n\\n" "Description"

            printf "    %s\\n\\n" "$_key_id" | sed 's/\\n \+/\n    /g'

          elif [[ "${_argv[1]}" == "$_count" ]] ; then

            module_show "$_key_var"

            printf "  \\e[1;38m%s\\e[m:\\n\\n" "Description"

            printf "    %s\\n\\n" "$_key_id" | sed 's/\\n \+/\n    /g'

          else

            _tc=$((_tc + 1))

          fi

          _count=$((_count + 1))

        done

        if [[ "$_tc" -eq ${#_module_commands[@]} ]] ; then

          printf "stdout: %s\\n" "invalid profile"

        fi

      fi

    fi

  elif [[ "${_argv[0]}" == "init" ]] ; then

    _script_args_tmp=()

    _script_args_state="false"

    if [[ "$_in_module" -eq 1 ]] && [[ ! -z "${_argv[1]}" ]] ; then

      _count=0

      # shellcheck disable=SC2034
      _variables_stack=("${_session_variables[@]}" "${_module_variables[@]}")

      for _scan in "${_module_commands[@]}" ; do

        if [[ "$_cmd_state" -eq 0 ]] ; then

          # shellcheck disable=SC2034
          _key_id=$(echo "$_scan" | awk -v FS="(;|;)" '{print $3}')
          # shellcheck disable=SC2034
          _key_var=$(echo "$_scan" | awk -v FS="(;|;)" '{print $4}')
          # shellcheck disable=SC2034
          _key_arg=$(echo "$_scan" | awk -v FS="(;|;)" '{print $5}')

          # shellcheck disable=SC2034
          IFS="," read -r -a _script_args <<< "$(sed 's/,\s+/???/g' <<< "$_key_arg")"

          if [[ "${_argv[1]}" == "$_key_id" ]] ; then

            _argvA=("${_argv[@]:2}")
            _argvB=("${_argv[@]:${#_argv[@]}-1}")

            if [[ "${#_argvA[@]}" -eq 0 ]] ; then

              for i in "${_argvB[@]}" ; do

                if [[ "$i" == "--args" ]] ; then

                # shellcheck disable=SC2034
                _script_args_state="true"

                fi

              done

              _init_cmd "${_key_var}"
              _cmd_state=1

            else

              for i in "${_argvB[@]}" ; do

                if [[ "$i" == "--args" ]] ; then

                  for j in "${_script_args[@]}" ; do

                    # shellcheck disable=SC2001
                    _tmp_script_args=$(echo "${j}" | sed 's/^ *//g' | sed 's/???/\\n/g')

                    if [[ "${_tmp_script_args}" == *"="* ]] ; then

                      _key_arg_x=$(echo "${_tmp_script_args}" | tr -d '"' | cut -d "=" -f1)
                      _key_value_x=$(echo "${_tmp_script_args}" | tr -d '"' | cut -d "=" -f2)

                    else

                      _key_arg_x=$(echo "${_tmp_script_args}" | tr -d '"')
                      _key_value_x=""

                    fi

                    _script_args_tmp+=("${_key_arg_x}")
                    _script_value_tmp+=("${_key_value_x}")

                    # shellcheck disable=SC2034
                    _script_args_state="true"

                  done

                  _argvC=("${_argvA[@]}")

                  unset "_argvC[${#_argvC[@]}-1]"

                else

                  _argvC=("${_argvA[@]}")

                fi

              done

              _init_cmd "${_key_var}" "${_argvC[@]}"
              _cmd_state=1

            fi

          elif [[ "${_argv[1]}" == "$_count" ]] ; then

            _argvA=("${_argv[@]:2}")
            _argvB=("${_argv[@]:${#_argv[@]}-1}")

            if [[ "${#_argvA[@]}" -eq 0 ]] ; then

              for i in "${_argvB[@]}" ; do

                if [[ "$i" == "--args" ]] ; then

                  # shellcheck disable=SC2034
                  _script_args_state="true"

                fi

              done

              _init_cmd "${_key_var}"
              _cmd_state=1

            else

              for i in "${_argvB[@]}" ; do

                if [[ "$i" == "--args" ]] ; then

                  for j in "${_script_args[@]}" ; do

                    # shellcheck disable=SC2001
                    _tmp_script_args=$(echo "${j}" | sed 's/^ *//g' | sed 's/???/\\n/g')

                    if [[ "${_tmp_script_args}" == *"="* ]] ; then

                      _key_arg_x=$(echo "${_tmp_script_args}" | tr -d '"' | cut -d "=" -f1)
                      _key_value_x=$(echo "${_tmp_script_args}" | tr -d '"' | cut -d "=" -f2)

                    else

                      _key_arg_x=$(echo "${_tmp_script_args}" | tr -d '"')
                      _key_value_x=""

                    fi

                    _script_args_tmp+=("${_key_arg_x}")
                    _script_value_tmp+=("${_key_value_x}")

                    # shellcheck disable=SC2034
                    _script_args_state="true"

                  done

                  _argvC=("${_argvA[@]}")

                  unset "_argvC[${#_argvC[@]}-1]"

                else

                  _argvC=("${_argvA[@]}")

                fi

              done

              _init_cmd "${_key_var}" "${_argvC[@]}"
              _cmd_state=1

            fi

          fi

        fi

        _argvA=()
        _count=$((_count + 1))

      done

      ### https://github.com/trimstray/sandmap/issues/53
      # if [[ "$_cmd_state" -eq 0 ]] ; then

        # printf "stdout: %s\\n" "unknown command"

      # fi

    elif [[ -z "${_argv[1]}" ]] ; then

      printf "stdout: %s\\n" "invalid key"

    else

      printf "stdout: %s\\n" "invalid param"

    fi

  elif [[ "${_argv[0]}" == "pushd" ]] ; then

    if [[ "${#_argv[1]}" -eq 0 ]] ; then

      printf "stdout: %s\\n" "invalid key"

    else

      if [[ "${_argv[1]}" == "init" ]] ; then

        if [[ "${#_pushd_stack[@]}" -ne 0 ]] ; then

          _init_cmd "${_pushd_stack[@]}"

        else

          printf "stdout: %s\\n" "pushd empty"

        fi

      elif [[ "${_argv[1]}" == "show" ]] ; then

        if [[ "${#_pushd_stack[@]}" -ne 0 ]] ; then

          # shellcheck disable=SC2034
          printf "pushd: %s\\n" "${_pushd_stack[@]}"

        else

          printf "stdout: %s\\n" "pushd empty"

        fi

      elif [[ "${_argv[1]}" == "flush" ]] ; then

        # shellcheck disable=SC2034
        _pushd_stack=()

        printf "stdout: %s\\n" "pushd flushed"

      else

        _count=0
        _cmd_state=0

        for _scan in "${_module_commands[@]}" ; do

          # shellcheck disable=SC2034
          _key_id=$(echo "$_scan" | awk -v FS="(;|;)" '{print $3}')
          # shellcheck disable=SC2034
          _key_var=$(echo "$_scan" | awk -v FS="(;|;)" '{print $4}')

          if [[ "${_argv[1]}" == "$_key_id" ]] ; then

            _pushd_stack+=("$_key_var")
            _cmd_state=1

          elif [[ "${_argv[1]}" == "$_count" ]] ; then

            _pushd_stack+=("$_key_var")
            _cmd_state=1

          fi

          _count=$((_count + 1))

        done

        if [[ "$_cmd_state" -eq 0 ]] ; then

          printf "stdout: %s\\n" "unknown command"

        fi

      fi

    fi

  elif [[ "${_argv[0]}" == "search" ]] ; then

    init_search "${_argv[1]}"

  else

    printf "stdout: %s\\n" "unknown command"

  fi

  return $_STATE

}
