#!/bin/bash

set -E

Dir="$(readlink -m "$(dirname "${BASH_SOURCE[0]}")/..")"
PowscriptSourceDirectory="$Dir/src"
PowscriptLibDirectory="$Dir/lib"

if [ -f ./powscript ]; then
  mv "$Dir/powscript" "$Dir/.powscript.backup"
  trap '{ mv "$Dir/.powscript.backup" "$Dir/powscript"; exit; }' ERR
fi

source "$PowscriptSourceDirectory/compiler/version.bash"
OldPatchVersion="$(version:patch-of "$(version:number)")"
NewPatchVersion="$(( OldPatchVersion + 1))"


update_patch_version() {
  sed -i -e 's/"version":[ ]*\"\(.*\)\.\(.*\)\..*",/"version": "\1.\2.'"$1"'",/g' "$Dir/package.json" || true
  sed -i -e 's/POWSCRIPT_VERSION=*\(.*\)\.\(.*\)\..*/POWSCRIPT_VERSION=\1.\2.'"$1"'/g' "$Dir/powscript" || true
}


printf '' >"$Dir/powscript"

add() {
  echo "$1" >>"$Dir/powscript"
}


if ${POWSCRIPT_CDEBUG-false}; then
  LineNum=0
  InsideSingleQuotes=false
  InsideDoubleQuotes=false
  MultiLine=false
  NextMultiLine=false
  Escape=false

  echo >"$Dir/.cdebug"

  add "$(cat "$Dir/.tools/debugger/preamble.bash")"

  debuggable_line() {
    ! $InsideSingleQuotes && ! $InsideDoubleQuotes && ! $MultiLine
  }
  non_empty_line() {
    [ -n "$line" ] && [[ ! "$line" =~ ^[\ ]*'#'.*$ ]]
  }
  not_before_case() {
    [[ ! "$line" =~ ^("'""$"?"("|[^'('])*')' ]] && [[ ! "$line" =~ esac$ ]]
  }
  at_function_start() {
    [[ "$line" =~ ^.*'() {'$ ]]
  }
  at_function_exit() {
    [ "$line" = '}' ] || [[ "$line" =~ ^[\ ]*exit([\ ]+[0-9]+)?$ ]]
  }

  flip() {
    if ${!1}; then
      printf -v "$1" false
    else
      printf -v "$1" true
    fi
  }

  update_quote_count() {
    local i
    MultiLine=false
    for i in $( seq 0 $((${#line}-1)) ); do
      case ${line:$i:1} in
        '\')
          if ! $InsideSingleQuotes; then flip Escape; fi; ;;
        '"')
          if ! $Escape && ! $InsideSingleQuotes; then flip InsideDoubleQuotes; fi
          Escape=false;;
        "'")
          if ! $Escape && ! $InsideDoubleQuotes; then flip InsideSingleQuotes; fi
          Escape=false;;
        *)
          Escape=false;;
      esac
    done
    if $Escape && ! $InsideSingleQuotes && ! $InsideDoubleQuotes; then MultiLine=true; Escape=false; fi
  }

  check_before_line() {
    LineNum=$((LineNum+1))
    if debuggable_line && at_function_exit; then
      local ec="cdebug_err_code_$LineNum"
      if [ "$line" = '}' ];  then add "$ec=\$?"; fi

      add "powscript-cdebug:line '${line//\'/,}'"
      add 'powscript-cdebug:function-end'

      if [ "$line" = '}' ];  then add "return \$$ec"; fi

    elif debuggable_line && non_empty_line && not_before_case; then
      add "powscript-cdebug:line '${line//\'/\`}'"
    fi
    if at_function_start; then
      add "POWSCRIPT_CDEBUG_FUNCTIONS[${line:0:-4}]=true"
    fi
    if non_empty_line; then update_quote_count; fi
  }

  check_after_line() {
    if debuggable_line && non_empty_line && at_function_start; then
      add "powscript-cdebug:function-start '${line:0:-4}' \"\$@\""
    fi
  }
else
  if [ -f "$Dir/.cdebug" ]; then rm "$Dir/.cdebug"; fi
fi

read_file() {
  local line file lib var val noshadow_mode=false noshadow_func=""
  export RequireOp=add
  export ShadowingOp=trimming_add
  export ShadowingGetFunc=get_noshadow_func
  trimming_add() {
    local line
    while IFS='' read -r line || [ -n "$line" ]; do
      line="${line% }"
      if ${POWSCRIPT_CDEBUG-false}; then check_before_line; fi
      add "$line"
      if ${POWSCRIPT_CDEBUG-false}; then check_after_line; fi
    done <<< "$1"
  }
  get_noshadow_func() {
    echo "$noshadow_func"
  }

  while IFS='' read -r line || [ -n "$line" ]; do
    if ${POWSCRIPT_CDEBUG-false} && ! $noshadow_mode; then check_before_line; fi

    if [[ "$line" =~ .*'#<<EXPAND>>' ]]; then
      file=${line//*source/}
      file=${file//#*/}
      file=${file// /}
      read_file "$Dir/src/$file"
      add "# FILE: $file"

    elif [[ "$line" =~ .*'#<<INCLUDE>>' ]]; then
      file=${line//*source/}
      file=${file//#*/}
      file=${file// /}
      read_file "$(eval echo "$file")"
      source "$(eval echo "$file")"
      add "# FILE: $file"

    elif [[ "$line" =~ .*'#<<REQUIRE>>' ]]; then
      lib=${line//*powscript_require/}
      lib=${lib//#*/}
      lib=${lib// /}
      powscript_require "$lib"

    elif [[ "$line" =~ .*'#<<IGNORE>>' ]]; then
      :

    elif [[ "$line" =~ .*'#<<VAR>>' ]]; then
      var="${line%%=*}"
      eval "val=${line#$var=}"
      add "$var=$val"

    elif [[ "$line" =~ .*'#<<NOSHADOW>>' ]]; then
      noshadow_func="dummy()"$'\n'"{"
      noshadow_mode=true

    elif $noshadow_mode; then
      if [[ "$line" =~ noshadow.* ]]; then
        eval "$line"
        noshadow_mode=false
      else
        noshadow_func="$noshadow_func"$'\n'"$line"
      fi
    else
      add "$line"
    fi

    if ${POWSCRIPT_CDEBUG-false}; then check_after_line; fi
  done <"$1"
}



read_file "$Dir/src/powscript.bash"

chmod +x "$Dir/powscript"


if [ -f "$Dir/.powscript.backup" ]; then
  if ! cmp -s "$Dir/.powscript.backup" "$Dir/powscript"; then
    if [[ "$*" =~ (--verbose|-v) ]]; then
      diff "$Dir/.powscript.backup" "$Dir/powscript" || true
    fi
    update_patch_version "$NewPatchVersion"
  fi
  rm "$Dir/.powscript.backup"
fi
