#!/bin/bash
# set -x
# exec 2>$HOME/foo.log

# make sure we have minimum arg count
if [ $# -lt 1 ]; then
    echo "$0 [cmd] [args ...]"
    exit 1
fi

# on entry, the following JS9 environment variables will be available:
# JS9_DIR		top level directory of js9 helper
# JS9_WORKDIR		working directory, if configured
# JS9_WORKDIR_QUOTA	quota for working directory, if configured
# JS9_HOST		host ip of client
# JS9_ID		id (from js9 div) of client

#defaults
CHANDRA_BINS="500:8000:1875"
XMM_BINS="400:15000:1825"
XRAY_ELEMENTS='{"text": "O VII", "x": 570, "y": "%Y"}, {"text": "O VIII", "x": 650, "y": "%Y"}, {"text": "Ne X", "x": 1020, "y": "%Y"}, {"text": "Mg XI", "x": 1340, "y": "%Y"}, {"text": "Si XIII", "x": 1850, "y": "%Y"}, {"text": "Si XIV", "x": 2010, "y": "%Y"}, {"text": "S XV", "x": 2450, "y": "%Y"}, {"text": "S XVI", "x": 2620, "y": "%Y"}, {"text": "Ar XVII", "x": 3130, "y": "%Y"}, {"text": "Ar XVIII", "x": 3320, "y": "%Y"}, {"text": "Ca XIX", "x": 3890, "y": "%Y"}, {"text": "Ca XX", "x": 4110, "y": "%Y"}, {"text": "Fe XXV", "x": 6670, "y": "%Y"}'

# if we are being called via CGI, send stderr to stdout
if [ x"$QUERY_STRING" != x ]; then
  exec 2>&1
fi

# error handler: send to stderr (which will go to stdout for CGI)
error() {
  echo "$*" | egrep "^ERROR:" 1>/dev/null 2>&1
  if [ $? = 0 ]; then
    echo "$*" >&2
  else
    echo "ERROR: $*" >&2
  fi
  exit 1
}

xsed() {
  sed 's#'${JS9_DIR:-none}'#${JS9_DIR}#g;'
}

getpar () {
  egrep "$1 *=" | awk -F= '{print $2}' | awk -F/ '{print $1}' | sed "s/[' ]*\([^ ']*\)[ ']*/\1/" | tr [a-z] [A-Z] | head -1
}

quotacheck () {
  if [ x"${JS9_WORKDIR}" = x ]; then
    error "task requires configuration of a temporary work directory"
  fi
  mb=`du -sk . | awk '{printf("%d", ($1 + 500) / 1000)}'`
  if [ ${JS9_WORKDIR_QUOTA:-0} -gt 0 ]; then
    if [ ${mb:-0} -ge ${JS9_WORKDIR_QUOTA} ]; then
      error "disk quota exceeded. Please close a displayed image or remove a proxy file (see File menu)."
    fi
  fi
}

# sanity check that we have system programs in the path
hash awk sed egrep du mv rm cat echo 1>/dev/null 2>&1
if [ $? != 0 ]; then
      error "can't find system programs (e.g. awk, sed). Please check the PATH of the JS9 helper."
fi

# regcnts is preferred
hash regcnts 1>/dev/null 2>&1
if [ $? = 0 ]; then
  CNTS=regcnts
else
  hash funcnts 1>/dev/null 2>&1
  if [ $? = 0 ]; then
    CNTS=funcnts
  else
    CNTS="error requires regcnts or funcnts ..."
  fi
fi

# process standard arguments
CMD="$1";     shift;
case $CMD in
counts)
    if [ $# -eq 1 ]; then
      ${CNTS} "$1" "$2" | xsed
    else
      ${CNTS} "$1" "$2" "$3" | xsed
    fi
    exit 0
    ;;

fits2png)
    fits2png $*
    exit 0
    ;;

fitshead)
    funhead -a "$1" | xsed
    exit 0
    ;;

hist)
    if [ $# -lt 4 ]; then
      error "funhist filename norm width [column] [bin] [$#]"
    fi
    ARGS=""
    FILE="$1"; shift
    FILE=`echo $FILE | sed 's/\]\[/,/g'`
    NORM="$1"; shift;
    if [ $NORM = "true" ]; then
      ARGS="$ARGS -n"
    fi
    WIDTH=$1; shift;
    if [ $WIDTH = "true" ]; then
      ARGS="$ARGS -w"
    fi
    COL="$1"; shift;
    if [ "x$COL" = 'x%energy' ]; then
      COL="pi";
      TELESCOP=`funhead $FILE | getpar TELESCOP`
      case "$TELESCOP" in
        CHANDRA)
          COL="energy"
          if [ x"$BINS" = x0 ]; then
              BINS="${CHANDRA_BINS}"
          fi
        ;;
        XMM)
          if [ x"$BINS" = x0 ]; then
              BINS="${XMM_BINS}"
          fi
        ;;
      esac
    fi
    if [ $# -eq 0 ]; then
	funhist $ARGS "$FILE" "$COL" | xsed
    else
	funhist $ARGS "$FILE" "$COL" "$1" | xsed
    fi
    exit 0
    ;;

radialplot)
    if [ $# -lt 2 ]; then
      error "${CNTS} filename [source] [bkgd] [$#]"
    fi
    if [ x"$2" = x ]; then
        error "please specify an annulus region for the source"
    fi
    echo "$2" | egrep 'box|circle|ellipse|line|point|poly' 1>/dev/null 2>&1
    if [ $? = 0 ]; then
        error "please specify an annulus region (only) for the source"
    fi
    if [ $# -eq 1 ]; then
      ${CNTS} -rG "$1" "$2" | funcnts2flot | xsed
    else
      ${CNTS} -rG "$1" "$2" "$3" | funcnts2flot | xsed
    fi
    exit 0
    ;;

histplot)
    if [ $# -lt 4 ]; then
      error "funhist filename norm width [column] [bin] [$#]"
    fi
    ARGS=""
    FILE="$1"; shift;
    FILE=`echo $FILE | sed 's/\]\[/,/g'`
    NORM="$1"; shift;
    if [ $NORM = "true" ]; then
      ARGS="$ARGS -n"
    fi
    WIDTH=$1; shift
    if [ $WIDTH = "true" ]; then
      if [ "x$2" = x0 ]; then
        error "please don't use a bin width of 0"
      fi
      ARGS="$ARGS -w"
    fi
    COL="$1"; shift;
    BINS="$1"
    TELESCOP=`funhead $FILE | getpar TELESCOP`
    YAXIS="counts"
    XAXIS="${COL} bin"
    if [ "x$COL" = 'x%energy' ]; then
      COL="pi";
      XAXIS="${COL} bin"
      case "$TELESCOP" in
        CHANDRA)
          COL="energy"
          if [ x"$BINS" = x0 ]; then
            BINS="${CHANDRA_BINS}"
          fi
          XAXIS="${COL} (ev)"
          ANNOTATE="${XRAY_ELEMENTS}"
        ;;
        XMM)
          if [ x"$BINS" = x0 ]; then
            BINS="${XMM_BINS}"
          fi
          XAXIS="${COL} (ev)"
        ;;
      esac
    elif [ "x$COL" = 'x%time' ]; then
      COL="time"
      XAXIS="${COL}"
      case "$TELESCOP" in
      CHANDRA|EINSTEIN|XMM)
        COL="time"
        XAXIS="time (sec)"
      ;;
      esac
    fi
    TITLE="$YAXIS vs. $XAXIS"
    if [ x"$BINS" = "x0" ]; then
	funhist $ARGS "$FILE" "$COL"            | \
	funhist2flot -a "$ANNOTATE" -t "$TITLE" | xsed
    else
	funhist $ARGS "$FILE" "$COL" "$BINS"    | \
	funhist2flot -a "$ANNOTATE" -t "$TITLE" | xsed
    fi
    exit 0
    ;;

evfilter)
    # required args
    if [ "$#" -lt 3 ]; then
	error "evfilter ifile filter cen dims [$*]"
    fi
    # make sure we are not over quota
    quotacheck
    # input file
    IFILE="$1"; shift
    # get filter, remove spaces
    FILTER=`echo $1 | sed 's/ //g;s/__ampersand__/\&/g'`; shift
    CEN="$1"; shift
    # get dims
    DIMS="$1"; shift
    # make up funtools image section extension from cen and dims
    X=`echo $CEN | awk -F, '{print $1}'`
    Y=`echo $CEN | awk -F, '{print $2}'`
    EXT="[$DIMS@$X,$DIMS@$Y]"
    # try to get a base name for output
    IBASE=`basename "$IFILE" | sed 's/\.gz$//' | sed 's/\.fits$//' | sed 's/\.ftz$//'`
    # make up unique output file base
    OBASE=`echo ${IBASE}_${FILTER} | sed 's/\[.*\]//g' | awk -F/ '{print $NF}' | sed 's/[,<>$&|!\*@]/_/g'`
    # make up new filter ... might need to combine with old filter
    echo "$IFILE" | egrep '\]\[' 1>/dev/null 2>&1
    if [ $? = 0 ]; then
	# remove closing bracket from old filter
        X=`echo $IFILE | sed 's/\]$//'`
	# append new filter onto old filter
        IFILEX="${X}&&$FILTER]"
    else
        IFILEX="${IFILE}[$FILTER]"
    fi
    # create the filtered FITS event file
    funtable $IFILEX ${OBASE}.fits >& err.log
    if [ $? != 0 ]; then
	error "`cat err.log`"
    fi
    # create a smaller representation file for display
    funimage ${OBASE}.fits"$EXT" stdout | gzip -c > ${OBASE}.fits.gz
    if [ $? != 0 ]; then
	error "`cat err.log`"
    fi
    # send representation file and parent file
    echo "${JS9_WORKDIR}/${OBASE}.fits.gz ${JS9_WORKDIR}/${OBASE}.fits"
    exit 0
    ;;

imsection)
    # optional args
    while [ x"$1" != x ]; do
        case $1 in
	-parent) DOPARENT=1
	       shift
	       continue;;
        *)     break;;
        esac
    done
    # required args
    if [ "$#" -lt 2 ]; then
	error "imsection file section filter slice"
    fi
    hash js9helper 1>/dev/null 2>&1
    if [ $? != 0 ]; then
	error "for imsection support, please build and install js9helper"
    fi
    # gzip files
    DOGZIP=1
    # input file
    IFILE="$1"
    # get section
    SECTION="$2";
    # get filter
    FILTER="$3"
    # get filter
    SLICE="$4"
    # false means no filter
    if [ "$FILTER" = "false" ]; then
      FILTER=""
    fi
    # try to get a base name for output
    IBASE=`basename "$IFILE" | sed 's/\.gz$//' | sed 's/\.fits$//' | sed 's/\.ftz$//'`
    OBASE=`echo ${IBASE}_${SECTION} | sed 's/\[.*\]//g' | awk -F/ '{print $NF}' | sed 's/[,@]/_/g'`
    if [ x$DOGZIP = x1 ]; then
        OFILE=${OBASE}.fits.gz
    fi
    # make sure we are not over quota
    quotacheck
    # send back relative path to the output file
    echo "${JS9_WORKDIR}/${OFILE}"
    # run imsection in the js9helper to generate a FITS image
    # (and send back json with useful info)
    js9helper -i "$IFILE" imsection \!"$OFILE" "$SECTION" "$FILTER" "$SLICE"
    if [ x$DOPARENT = x1 ]; then
      # send parent file, so analysis is performed on the original file
      echo "${IFILE}" | xsed
    fi
    exit 0
    ;;

listhdus)
    # required args
    if [ "$#" -lt 1 ]; then
	error "listhdus file"
    fi
    hash js9helper 1>/dev/null 2>&1
    if [ $? != 0 ]; then
	error "for listhdus support, please build and install js9helper"
    fi
    IFILE="$1"
    js9helper -i "$IFILE" listhdus
    ;;

loadproxy)
    # required args
    if [ "$#" -lt 1 ]; then
	error "loadproxy url"
    fi
    # make sure we are not over quota
    quotacheck
    URL=`echo $1 | sed 's/__ampersand__/\&/g'`
    if [ x"$2" != x ]; then
      OFILE="$2"
    else
      OFILE=`basename "$URL" | sed 's/\?.*//g;s/  *//g;s/%[0-9A-Fa-f][0-9A-Fa-f]//g'`
    fi
    # hack for google drive
    if [ x"$OFILE" = xuc ]; then
      OFILE="google_"$RANDOM".fits"
    fi
    # proxy
    if [ x"$JS9_PROXY" != x ]; then
      export http_proxy="$JS9_PROXY"
      export https_proxy="$http_proxy"
      export ftp_proxy="$http_proxy"
    fi
    # retrieve the FITS file via URL
    hash wget 1>/dev/null 2>&1
    if [ $? = 0 ]; then
      XFUNC="wget"
      wget -q --output-document="$OFILE" "$URL"
    else
      hash curl 1>/dev/null 2>&1
      if [ $? = 0 ]; then
        XFUNC="curl"
        curl -s -o "$OFILE" "$URL"
      else
        error "requires either wget or curl"
      fi
    fi
    if [ $? != 0 ]; then
      error "could not retrieve: $URL"
    else
      s=`file $OFILE`
      f=`echo $s | egrep "HTML document text" 1>/dev/null 2>&1`
      if [ $? = 0 ]; then
	f=`cat $OFILE | sed -n 's/.*\(The document has moved\) <A HREF="\([^"]*\)".*/\1 to: \2/gp'`
        if [ x"$f" != x ]; then
          error "$f"
        else
	  error `cat $OFILE`
        fi
      fi
      # look for a compressed file (and add .gz extension, if necessary)
      f=`echo $s | sed -n 's/.*gzip compressed data, was "\([^"]*\)".*/\1/gp'`
      if [ x"$f" != x ]; then
        # change ofile to original file + .gz (unless ofile was specified)
	if [ x"$2" = x ]; then
	  ext="${f##*.}"
          if [ x"$ext" = xgz ]; then
            NFILE="$f"
          else
            NFILE="$f".gz
          fi
          if [ x"$NFILE" != x"$OFILE" ]; then
            mv $OFILE $NFILE && OFILE="$NFILE"
          fi
        fi
      else
        # for ms-dos gip'ed file, there is no filename in the
        # try to get filename from url (this is how ESA HST archive does it)
        echo $s | egrep "gzip compressed data, from FAT" 1>/dev/null 2>&1
        if [ $? = 0 ]; then
          # look for original file + .gz (unless ofile was specified)
          if [ x"$2" = x ]; then
            f=`echo "$URL" | sed -n 's/.*=\([^=]*\.fits\{0,1\}\).*/\1/gp'`
            if [ x"$f" != x ]; then
              ext="${f##*.}"
              if [ x"$ext" = xgz ]; then
                NFILE="$f"
              else
                NFILE="$f".gz
              fi
              if [ x"$NFILE" != x"$OFILE" ]; then
                mv $OFILE $NFILE && OFILE="$NFILE"
              fi
            fi
          fi
        else
	  # better be a known image file type
          f=`echo $s | egrep -o '(FITS|JPEG|PNG) image data' | awk '{print $1}'`
	  case "$f" in
	    FITS|JPEG|PNG)
	    ;;
	    *)	rm -rf $OFILE
		error "$OFILE is not a FITS, JPEG, or PNG image file"
	    ;;
	  esac
        fi
      fi
      # special case: in chandra archive, check for rep file generation request
      echo $URL | egrep 'https://cxc.cfa.harvard.edu/cdaftp/.*_evt2.fits.gz\?repfile=true' 1>/dev/null 2>&1
      if [ $? = 0 ]; then
        hash funhead 1>/dev/null 2>&1
        if [ $? = 0 ]; then
          RFILE=`echo $OFILE | sed s#evt2#img#`
          # which chandra inst?
	  INST=`funhead $OFILE | getpar INSTRUME`
          # generate a rep file
          case "$INST" in
          HRC)
            DET=`funhead $OFILE | getpar DETNAM`
            case "$DET" in
            HRC-S)
              XCEN=32768
              YCEN=32768
              XDIM=4096
              YDIM=4096
              BLOCK=4
              BITPIX=32
              ;;
            HRC-I)
              XCEN=16384
              YCEN=16384
              XDIM=4096
              YDIM=4096
              BLOCK=4
              BITPIX=32
              ;;
            esac
            ;;
          ACIS)
            XCEN=4096
            YCEN=4096
            XDIM=4096
            YDIM=4096
            BLOCK=4
            BITPIX=32
            ;;
          esac
          if [ x$BITPIX != x ]; then
            (funimage $OFILE"[$XDIM@$XCEN,$YDIM@$YCEN,$BLOCK]" stdout bitpix=$BITPIX | gzip -c > $RFILE) 2>/dev/null
            if [ $? = 0 ]; then
              # tell JS9 the rep name to load, along with downloaded parent
              echo "${JS9_WORKDIR}/$RFILE ${JS9_WORKDIR}/$OFILE"
              exit 0
            else
              error "couldn't generate FITS representation file for $OFILE"
            fi
          fi
        fi
      fi
      # special case: in chandra archive, check for parent file request
      echo $URL | egrep 'https://cxc.cfa.harvard.edu/cdaftp/.*_img2.fits.gz\?parent=true' 1>/dev/null 2>&1
      if [ $? = 0 ]; then
        PFILE=`echo $OFILE | sed s#full_img2#evt2# | sed s#cntr_img2#evt2#`
        # and load the parent file asynchronously
        PURL=`echo $URL    | sed s#full_img2#evt2# | sed s#cntr_img2#evt2#`
        # retrieve the parent file
        if [ x$XFUNC = "xwget" ]; then
          wget -q --output-document="$PFILE" "$PURL"
        else
          curl -s -o "$PFILE" "$PURL"
        fi
        if [ $? != 0 ]; then
          error "could not retrieve parent file: $URL"
        fi
        # tell JS9 the new file name to load, along with parent file name
        echo "${JS9_WORKDIR}/$OFILE ${JS9_WORKDIR}/$PFILE"
        exit 0
      fi
    fi
    # tell JS9 the new file name to load (no parent file)
    echo "${JS9_WORKDIR}/$OFILE"
    exit 0
    ;;

removeproxy)
    # required args
    if [ "$#" -lt 1 ]; then
	error "removeproxy file"
    fi
    if [ x"${JS9_WORKDIR}" = x ]; then
      error "removeproxy requires a temporary work directory"
    fi
    # remove file(s) from our working directory, but ignore errors
    while [ x"$1" != x ]; do
	PROXY=`echo $1 | sed 's/__ampersand__/\&/g'`
        FILE=`basename "$PROXY"`
        rm -f "$FILE"
	shift
    done
    echo "OK"
    exit 0
    ;;

uploadfits)
    # required args
    if [ "$#" -lt 1 ]; then
	error "uploadfits filename"
    fi
    FNAME="$1"
    # make sure we are not over quota
    quotacheck
    # save stdin as a file
    cat > "$FNAME"
    # tell JS9 the new pathname
    echo "${JS9_WORKDIR}/$FNAME"
    exit 0
    ;;

quotacheck)
    # make sure we are not over quota
    quotacheck
    echo "OK ${JS9_WORKDIR_QUOTA:-0}"
    exit 0
    ;;

macros)
    echo "
    image:       [$1]
    file/parent: [$2]
    file/this:   [$3]
    ext:         [$4]
    imcen:       [$5]
    wcscen:      [$6]
    id:          [$7]
    foo:         [$8] (not expanded)
    sregions:    [$9]
    bregions:    [${10}]
    reg(wcs):    [${11}]
    reg(phy):    [${12}]
    string1:     [${13}] (passed on command line)"
    exit 0
    ;;

*)
    error "unknown function: $CMD"
    ;;
esac
