#! /bin/bash
# ag-nchainz - Agoric-specific nchainz scripts
#
# First run at least two Agoric chains:
# (https://github.com/cosmos/relayer/blob/d59c98adb368822a25328fe74db433f8aae78a1d/scripts/nchainz)
#
#   nchainz init agoric agoric
#   ag-nchainz start-solos
#
# or something.  See nchainz --help for more details.
set -e
progname=$(basename -- "$0")

trap 'kill $(jobs -p) 2>/dev/null' EXIT 

BASE_PORT=8000
NUM_SOLOS=1

real0=$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")
thisdir=$(cd "$(dirname -- "$real0")" && pwd -P)

PATHCONFIG=nchainz/config/paths
DAEMON=agd
DAEMON_CMD="$thisdir/../../golang/cosmos/build/$DAEMON"
CLI="$DAEMON_CMD"
NODE_HOME=agd
SOLO="$thisdir/../solo/bin/ag-solo"
SKIP=no
COMMAND=

while [[ $# -gt 0 ]]; do
  case $1 in
  -*)
    echo "unrecognized option \`$1'"
    exit 1
    ;;
  *)
    if [[ $SKIP == no && $1 == skip ]]; then
      SKIP=yes
      shift
    elif [[ -z $COMMAND ]]; then
      COMMAND=$1
      shift
      break;
    fi
    ;;
  esac
done

case $COMMAND in
testnet)
  chainid="$1"
  shift
  echo | "$DAEMON_CMD" testnet ${1+"$@"} --node-daemon-home="$DAEMON"
  n0d=$chainid/n0/$DAEMON
  i=$(echo $chainid | sed -e 's/^[^0-9]*//')
  portstart=$(( $BASE_PORT + $i * $NUM_SOLOS ))
  portend=$(( $portstart + $NUM_SOLOS - 1 ))
  SOLO_ADDRS=()
  POWER_FLAGS='[\"agoric.vattp\"]'
  egresses=
  sep=''
  for port in `seq $portstart $portend`; do
    solo="$chainid/ag-solo-$port"
    echo "Initializing ag-solo in $solo"
		$SOLO init $solo --webport=$port
    addr=$(cat $solo/ag-cosmos-helper-address)
    SOLO_ADDRS+=( "$addr" )
		"$DAEMON_CMD" add-genesis-account --home=$n0d \
      $($CLI --home=$solo/$CLI-statedir --keyring-backend=test keys show -a ag-solo) \
      1000uist,1provisionpass
    # Generate powerful SwingSet egresses.
    egresses="$egresses$sep\"egress.$addr\":\"{\\\"nickname\\\":\\\"$solo\\\",\\\"peer\\\":\\\"$addr\\\",\\\"powerFlags\\\":$POWER_FLAGS}\""
    sep=,
	done
  for node in `ls -d $chainid/n* 2>/dev/null || true`; do
    [[ "$node/$DAEMON" == $n0d ]] || cp $n0d/config/genesis.json $node/$DAEMON/config/genesis.json
	  "$thisdir/../../agoric-cli/bin/agoric" set-defaults --bootstrap-address=${SOLO_ADDRS[0]} \
      ag-chain-cosmos $node/$DAEMON/config
    cp "$node/$DAEMON/config/genesis.json" "$node/$DAEMON/config/genesis-orig.json"
    # Append the egresses to the genesis and reset bond_denom.
    jq ".*{app_state:{staking:{params:{bond_denom:\"stake\"}},swingset:{storage:{$egresses}}}}" \
      "$node/$DAEMON/config/genesis-orig.json" > "$node/$DAEMON/config/genesis.json"
  done
  exit 0
  ;;
start-daemon)
  if [[ $1 == '--debug' ]]; then
    debug=yes
    shift
  fi
  BASEDIR=$1
  shift
  for solo in `ls -d $BASEDIR/ag-solo-* 2>&1`; do
    cp -r "$BASEDIR/n0/$DAEMON/config" "$solo/$CLI-statedir/"
  done
  # "$($CLI --home "$BASEDIR/n0/$DAEMON" keys show n0 --keyring-backend=test | jq -r .address)"
  echo "Starting $DAEMON_CMD ${1+"$@"}"
  if [[ $debug == yes ]]; then
    NODE_OPTIONS=--inspect-brk DEBUG=agoric "$DAEMON_CMD" ${1+"$@"}
  else
    DEBUG=agoric "$DAEMON_CMD" ${1+"$@"}
  fi
  exit 0
  ;;

start-solos)
  for solo in `ls -d nchainz/data/*/ag-solo-* 2>/dev/null`; do
    chainid=$(basename -- "$(dirname -- "$solo")")
    log="$(basename -- "$solo")-$chainid.log"
    if [[ -n $1 ]]; then
      case " $@ " in
      " $chainid ") ;;
      *) continue ;;
      esac
    fi
    echo "Logging to nchainz/logs/$log"
    (
      cd "$solo"
      n0d=../n0/$DAEMON

      rpcport=`$thisdir/../calc-rpcport.js $n0d/config/config.toml`

      addr=$(cat ag-cosmos-helper-address)
      while ! $CLI --home=./$CLI-statedir tx swingset provision-one \
        "$solo" "$addr" agoric.vattp \
        --node="tcp://$rpcport" --chain-id="$chainid" \
        --keyring-backend=test --from=ag-solo --yes; do
        sleep 5
      done

      # Now wire into the chain.
      gci=`$thisdir/../calc-gci.js $n0d/config/genesis.json`
      $SOLO set-gci-ingress --chainID="$chainid" "$gci" "$rpcport"

      DEBUG=agoric $SOLO start
    ) >>nchainz/logs/$log 2>&1 &
  done
  sleep 2
  echo "Waiting for all ${1+"$@ "}solos (Hit Control-C to exit)..."
  wait
  exit 0
  ;;
start-relayer)
  replace=no
  while [[ $# -gt 0 ]]; do
    case $1 in
    --replace)
      replace=yes
      shift
      ;;
    *)
      template=$1
      shift
      break
      ;;
    esac
  done
  BASE_RE='([^/]*)\.json$'

  echo "Reading path specification (Control-D to finish, Control-C to abort)..."
  tmpfile=$(mktemp ${TMPDIR-/tmp}/relayer-start.XXXXXX)
  cfgfile=$(mktemp ${TMPDIR-/tmp}/relayer-config.XXXXXX)
  trap "rm -f '$tmpfile' '$cfgfile'" EXIT 
  rly config show --json > "$cfgfile"
  cat > "$tmpfile"

  srccid=$(jq -r '.src["connection-id"]' "$tmpfile")
  if [[ $srccid == null ]]; then
    echo 1>&2 "You must specify .src[\"connection-id\"]"
    exit 1
  fi

  # Extract existing config.
  for path in $(jq '.paths | keys | .[]' "$cfgfile"); do
    rawpath=$(echo "$path" | jq -r .)
    jq -r ".paths[$path]" "$cfgfile" > "$PATHCONFIG/$rawpath.json"
  done

  jqexpr=
  for fname in $PATHCONFIG/*.json; do
    [[ -z $template || $fname == "$PATHCONFIG/$template.json" ]] || continue
    [[ $fname =~ $BASE_RE ]] || continue
    if grep -q '"generator": "ag-nchainz"' "$fname"; then :
    else
      oldsrccid=$(jq -r '.src["connection-id"]' "$fname")
      olddstcid=$(jq -r '.dst["connection-id"]' "$fname")
      case "$oldsrccid:$olddstcid" in
      $srccid:*)
        # Forward order.
        jqexpr='.[0] * .[1]'
        template=${BASH_REMATCH[1]}
        break
        ;;
      *:$srccid)
        # Swapped order.
        jqexpr='{ src: .[0].dst, dst: .[0].src, strategy: .[0].strategy } * .[1]'
        template=${BASH_REMATCH[1]}
        break
        ;;
      esac
    fi
  done

  if [[ -z $jqexpr ]]; then
    if [[ -n $template ]]; then
      echo 1>&2 "Connection ID \`$srccid' is not defined in $PATHCONFIG/$template.json"
    else
      echo 1>&2 "Connection ID \`$srccid' is not defined in $PATHCONFIG/*.json"
    fi
    exit 1
  fi

  # Trim off the channel ids.
  jqexpr=$jqexpr' | del(.src["channel-id"]) | del(.dst["channel-id"])'

  if [[ $replace == yes ]]; then
    # Overwrite existing path.
    echo "Replacing path \`$path'"
    path=$template
    jq -s "$jqexpr" \
      "$PATHCONFIG/$template.json" "$tmpfile" > "$PATHCONFIG/$path.json"
  else
    # Create a new path.
    i=0
    path=path-$i
    while [[ -e "$PATHCONFIG/$path.json" ]]; do
      i=$(( $i + 1 ))
      path=path-$i
    done

    echo "Creating new path \`$path'"
    jq -s "$jqexpr"' * { "generator": "ag-nchainz" }' \
      "$PATHCONFIG/$template.json" "$tmpfile" > "$PATHCONFIG/$path.json"
  fi

  # Bottom-up relay path validation may fail if src or dst chain is not past
  # block #2.
  # Keep trying to add-paths until both the chains have booted up.
  echo "$ rly config add-paths $PATHCONFIG/"
  while ! rly config add-paths $PATHCONFIG/; do
    sleep 3
  done

  echo "$ rly link $path --timeout=3s -d"
  try=0
  while ! rly tx link $path --timeout=3s -d >> "nchainz/logs/$path.log" 2>&1; do
    try=$(( $try + 1 ))
    echo "$path tx link not yet ready (try=$try)"
    sleep 1
  done
  try=$(( $try + 1 ))
  echo "$path tx link initialized (try=$try)"

  # Wait for the rly start command.
  echo "$ rly start -d $path"
  rly start -d "$path"
  ;;
*)
  echo 1>&2 "$progname: unrecognized command \`$COMMAND'"
  exit 1
  ;;
esac
