#!/bin/bash

########################################################################

### Reads label to get data offsets in FITS
### Read FITS data to make table

### Usage:  newrex_bash.bash __rawdata/rex_003031500?_0x7b3_eng_*.lbl


########################################################################
### Extract ordinal-1 of 2880-byte FITS record from PDS label file
### e.g. extract the "13" from a line like this:
###
### ^EXTENSION_IQVALS_TABLE = ("REX_0030315000_0X7B3_ENG_1.FIT", 13)              
function getifitrec() {
   line=( `head -1 | tr '\" (),\r' ' '` )
   echo "${line[3]}-1"
}


########################################################################
### Usage:  headfit file.fit 12880 10000
### - output 10000 bytes, starting at an offset of 2880 bytes past the
###   1st byte (ordinal byte 2881), from file file.fit start

function headfit() {
  fit="$1"
  rtheadbytes="$2"
  rtbytes="$3"
  head -${rtheadbytes}c $fit \
  | tail -c -$rtbytes
}

########################################################################
### ASCII codes for A and B are odd and even, respectively
### So if 2-byte string AB is interpreded as 2-byte integer, it will
### be odd if the local system is LSByte-first, and it will be even
### if the local system is MSByte-first.

unset lsbfirst
unset msbfirst

echo "AB"  \
| od -w2 -t d2 \
| head -1 \
| ( read a b ; let b=$b%2 ; [ $b -eq 1 ] ) \
&& lsbfirst=yes || msbfirst=yes

### lsbfirst=yes if local system is LSByte-first:
### - [ "$lsbfirst" ] evaluates true
### - [ "$msbfirst" ] evaluates false

### msbfirst=yes if local system is MSByte-first:
### - [ "$lsbfirst" ] evaluates false
### - [ "$msbfirst" ] evaluates true

####################################
### Function to swap, if necessary,
### N MSByte-first bytes at a time
### from STDIN to local byte order
###
### Usage:  doNswap 12 < MSByte-firstStream.dat > LocalByteOrderStream.dat
###
### - N is $1; N <= 32
### - Input stream length must be a multiple of N
### - This routine does nothing if local architecture
###   is already MSByte-first
function doNswap() {
  if [ "$lsbfirst" ] ; then
    let n=$1
    let rn=32-$n
    fwd="0123456789abcdefghijklmnopqrstuv"
    bck="vutsrqponmlkjihgfedcba9876543210"
    fwd=${fwd:0:n}
    bck=${bck:$rn:$n}
    od -b -v -w$n \
    | sed -e 's/^[0-9]* *//' \
    | grep . \
    | while read octal3s ; do
        to=`echo " $octal3s" | sed -e 's/  */\\\\/g'`
        echo -n $fwd | tr $bck $to
      done
  else
    cat
  fi
}

function OBSOLETE_doNswap() {
  [ "$lsbfirst" ] && ./nswap $1 || cat
}

########################################################################
### Temporary files
tmppfx=/tmp/newrex_bash.$$.`date +%Y%m%d%H%M%S`
tmprad="$tmppfx.rad"
tmprt="$tmppfx.rt"

### Main function
while [ $# -gt 0 ] ; do

  ### Get and consume first command-line argument
  lbl="$1" ; shift

  ### Ensure end in .lbl
  [ "${lbl%.lbl}" == "$lbl" ] && ( echo "### Skipping $lbl" 1>&2 || true ) && continue

  ### Build FITS pathname from PDS label path name
  fit="${lbl%lbl}fit"

  ### Determine if FitS file is Raw or Calibrated
  [ "${fit/_0x7b?_sci_[1-9]*.fit}" == "$fit" ] && isRaw=yes || unset isRaw

  ### Get 2880-byte FITS record offsets to
  ### IQ and Radiometry/TimeTag BINTABLES
  let iqoffset=`grep '^ *[\^]EXTENSION_IQVALS_TABLE *= *(' "$lbl" | getifitrec`
  let rtoffset=`grep '^ *[\^]EXTENSION_RAD_TIME_TAGS_TABLE *= *(' "$lbl" | getifitrec`

  ###OBSOLETE### ### Ensure nswap application exists
  ###OBSOLETE### make nswap > /dev/null

  ### Calculate byte offsets
  let iqbyteoffset=2880*$iqoffset
  let rtbyteoffset=2880*$rtoffset

  ### Determine BINTABLE data lengths and other parameters
  ### - rtbytes:  Radiometry and Time Tags; 10 rows x [12(Raw) or 8(Cal.)] bytes/row
  ### - iqbytes:  IQ; 1250 rows x [4(Raw) or 8(Cal.)] bytes/row
  ### - iqtype:  IQ data type for od:  d2(Raw; int16) or f4(Cal.; float32)
  ### - NEWREXFMT:  gawk format for output columns, environment variable
  if [ "$isRaw" ] ; then
    let rtbytes=120
    let iqbytes=5000
    iqtype=d2
    export NEWREXFMT="%16d"
  else
    let rtbytes=80
    let iqbytes=10000
    iqtype=f4
    export NEWREXFMT="%16.4f"
  fi

  ### Calculate total number of bytes from start of file to end of
  ### each BINTABLE
  let iqheadbytes=$iqbyteoffset+$iqbytes
  let rtheadbytes=$rtbyteoffset+$rtbytes

  if [ "$isRaw" ] ; then

    ### Raw:  Radiometry (int64) and Time Tags (int32)
    ### Stored in FITS BINTABLE as RRRRRRRRTTTTrrrrrrrrtttt... MSByte-first

    ### Byteswap - if local system is LSByte-first - using doNswap 12
    ### Will change that to this:

    ### TTTTRRRRRRRRttttrrrrrrrr... LSByte-first

    [ "$lsbfirst" ] && skip=4 || skip=0

    ### Extract 8-byte Radiometry values in two passes
    ### - Rows 1,3,5,7,9
    ### - Rows 2,4,6,8,10

    for rtidx0 in 1 2 ; do
      rtidx=$rtidx0
      headfit $fit $rtheadbytes $rtbytes \
      | doNswap 12 \
      | od -v --skip-bytes=$skip -w24 -t d8 \
      | while read pfx d8 xxx ; do
          [ "$d8" ] && echo $rtidx $d8
          let rtidx=$rtidx+2
        done
      let skip=$skip+12
    done \
    | sort -n \
    | while read nnn d8 ; do echo $d8 ; done \
    > "$tmprad"

    [ "$lsbfirst" ] && skip=0 || skip=8

    ### Extract 4-byte Time Tag values in one pass
    ### - Rows are 12 bytes each; every third int32 is a Time Tag

    headfit $fit $rtheadbytes $rtbytes \
    | doNswap 12 \
    | od -v --skip-bytes=$skip -w12 -t d4 \
    | while read pfx d4 xxx ; do echo $d4 ; done \
    | paste $tmprad - 

    rm -f "$tmprad" 1>/dev/null 2>&1

  else

    ### Calibrated:  Radiometry and Time Tags as float32s

    headfit $fit $rtheadbytes $rtbytes \
    | doNswap 8 \
    | od -v -w8 -t f4 \
    | head -10 \
    | while read pfx ttg rad xxx ; do echo $rad $ttg ; done \
    \
  fi \
  > "$tmprt"

  ### Raw or Calibrated IQ BINTABLE
  ### - paste 10 lines of Radiometry/TimeTag BINTABLE to
  ###   first 10 lines of IQ BINTABLE
  ### - Use GAWK and NEWREXFMT envvvar to output columns

  let iqbyteperrow=$iqbytes/1250

  headfit $fit $iqheadbytes $iqbytes \
  | doNswap $iqbyteperrow \
  | od -v -w$iqbyteperrow -t $iqtype \
  | head -1250 \
  | while read pfx qval ival xxx ; do echo $ival $qval ; done \
  | paste - "$tmprt" \
  | tr \\t \  \
  | sed 's/  *$//' \
  | gawk '
  BEGIN { fmt=ENVIRON["NEWREXFMT"] }
  {
    printf "%5d", FNR
    for (i=1; i<=NF; ++i) { printf fmt, $i }
    print ""
  }
  '

  rm -f "$tmprt" 1>/dev/null 2>&1

done

exit 0