#!/bin/sh

#             $HOME/.lcmodel/philips/bin2raw (24 August 2013)
#
#                  Specific Instructions for this File
#                  ===================================

#     If you want to modify this file, use this file as a template only; copy 
# it to my-bin2raw (in the same directory as bin2raw), and then edit 
# my-bin2raw.
#     LCMgui always first attempts to execute my-bin2raw.  If LCMgui cannot 
# find my-bin2raw, then it executes bin2raw.
#     bin2raw will be overwritten by updates, but your my-bin2raw will not be 
# overwritten.

#     This script may fail (with no diagnostic messages) if you have not 
# selected a DICOM file or an SDAT file.  Furhermore, with an SDAT file, there 
# must be an SPAR file with the same name (except for the endings ".spar" & 
# ".sdat" or ".SPAR" & ".SDAT").

#     Normally you do not have to read anything further in this script.
# However, if you wish, you should be able to easily modify the TITLE or the 
# HEADER_INFO's below.  There are "General Instructions" at the end of this 
# script for all my-bin2raw scripts.

#============================================================================

#                   Start of This Script
#                   ====================

#
# Function for checking if a variable is an integer (adapted from B. Blinn)
#
IsNonInteger() {
    expr "$1" + 1  >/dev/null  2>&1
    if [ $?  -ge  2 ]
    then
	return 0
    fi
    return 1
}
#-----------------------------------------------------------------------------

# Initial definitions.
# Note that $LCM_DIR has a "/" at the end and $BIN2RAW_DIR does not.
#
DATA_FILE=$1
LCM_DIR=$2
MET_H2O=$3
BIN2RAW_DIR=$2$3

CP_START=$BIN2RAW_DIR/cpStart
EXTRA_INFO=$BIN2RAW_DIR/extraInfo
ERROR=$BIN2RAW_DIR/error
RAW=$BIN2RAW_DIR/RAW

# Delete possible old files, e.g., after "Reload" Button. 
#
rm  -f  $CP_START
rm  -f  $EXTRA_INFO
rm  -f  $ERROR
rm  -f  $RAW

mkdir -p $LCM_DIR/met
mkdir -p $LCM_DIR/h2o
#-----------------------------------------------------------------------------

$HOME/.lcmodel/philips/bin2raw-dicom  $DATA_FILE  $LCM_DIR  $MET_H2O  2>$ERROR
if [ $? -ne 99 ]
then
    exit 0
fi
#-----------------------------------------------------------------------------

#      Check for the existence of the SPAR file.
#      This assumes that the SDAT file has at least 4 characters, since it is  
# assumed to end in ".sdat".
#      The SPAR filename must be identical with the SDAT filename, except for 
# "spar" or "SPAR" in place of the last 4 characters.
#      Also allowed is the VMS ";" followed by a version number (bad with Unix)
#
case $1 in
    *sdat  )       SPAR=`echo $1 | sed 's/sdat$/spar/'`  ;;
    *SDAT  )       SPAR=`echo $1 | sed 's/SDAT$/SPAR/'`  ;;
    *sdat";"*  )   SPAR=`echo $1 | sed 's/sdat;/spar;/'`  ;;
    *SDAT";"*  )   SPAR=`echo $1 | sed 's/SDAT;/SPAR;/'`  ;;
    *  )           SPAR=$1.sdat  ;;
esac

if [ !  -r  "$SPAR" ]
then
    echo "     You have not selected a DICOM file, and the following Philips 
SDAT file that you selected:

$1

must end in \"sdat\", 
and there must be an SPAR file with the identical name,
except with \"spar\" instead of \"sdat\". "  >  $ERROR
    exit 0
fi
#-----------------------------------------------------------------------------

#      Extract info for cpStart from SPAR file.

# For simplicity, awk will be called repeatedly, which is a waste of (a small 
# amount of) time.

# Functions and "bc" are not supported by all Unix versions.  The extremely 
# repetitive & awkward "awk" calls are used instead.  Several basic 
# "awk" commands cannot be used, because they are missing on some Suns.

# "tr -d" below deletes carriage return that sometimes gets inserted during
# file manipulations or transfers.

# Some languages (most non-English European) use a comma instead of a period 
# for the decimal point.  So, it seems necessary to work with integers to be 
# compatible with both cases.  This is very tedious below.  Without this, the 
# fractional part of decimal numbers are truncated.  (The Philips SPAR files 
# have periods for decimal points in all cases.)
# The "tr ',' '.'" commands below are to correct for the final awk output for 
# this.

# "exit" below is necessary to prevent double reading of the same value in 
# some SPAR files produced by Sunspec.
#
# First make TITLE
#
EXAM=`awk -F: '/^examination_name/    { print $2 ; exit }' $SPAR | tr -d '\r'`
EXAM=`echo $EXAM`
DATE=`awk '/^scan_date/               { print $0 ; exit }' $SPAR | tr -d '\r'`
DATE=`echo $DATE | cut -d: -f2-`
DATE=`echo $DATE`
NAME=`awk -F: '/^patient_name/        { print $2 ; exit }' $SPAR | tr -d '\r'`
NAME=`echo $NAME`
BIRTH=`awk -F: '/^patient_birth_date/ { print $2 ; exit }' $SPAR | tr -d '\r'`
BIRTH=`echo $BIRTH`


# Get voxel volume.  (Fractional parts of mm are truncated when comma decimal 
#                     points are expected.)
# May not be always correct, especially for non-standard CSI, e.g., when 
#    number of columns does not equal number of rows.
# NDROWS = number of rows in 2D CSI slice
# ROWS = total number of spectra (voxels)
# If ROWS=1, then single-voxel
# If ROWS>1 and dim3_pnts=NDROWS=1 or non-existent, then time series
# If ROWS>1 and NDROWS>1, then CSI
# FOV, AP_SIZE, LR_SIZE, CC_SIZE assumed to be valid numbers; zero values not 
#                                always checked for.
# Thanks to Jan Weis and Enrico De Vita for suggestions on the CSI part.

NDROWS=`awk -F: '/dim3_pnts/ { print $2 ; exit }' $SPAR | tr -d '\r'`
NDROWS_VALUE=1
if  IsNonInteger $NDROWS
then
    :
else
    if [ $NDROWS -gt 0 ]
    then
        NDROWS_VALUE=$NDROWS
    fi
fi
echo "ndrows= $NDROWS_VALUE"  >  $CP_START

ROWS=`awk -F: '/^rows/                { print $2 ; exit }' $SPAR | tr -d '\r'`
AP_SIZE=`awk -F: '/^ap_size/          { print $2 ; exit }' $SPAR | tr -d '\r'`
LR_SIZE=`awk -F: '/^lr_size/          { print $2 ; exit }' $SPAR | tr -d '\r'`
CC_SIZE=`awk -F: '/^cc_size/          { print $2 ; exit }' $SPAR | tr -d '\r'`
TIME_SERIES=0

if IsNonInteger $ROWS
then
    :
elif [ $ROWS -eq 1 ]
then
    #
    # Assume single-voxel
    #
    VOLUME=`echo "$AP_SIZE $LR_SIZE $CC_SIZE" |\
            awk '{ if (  $1 * $2 * $3 > 0)
                  printf ( "%e", $1 * $2 * $3 / 1000 ) }'`
elif [ $ROWS -gt 1 ]
then
    if [ $NDROWS_VALUE -gt 1 ]
    then
        #
        # Assume CSI.
        #
        FOV=`awk -F: '/^phase_encoding_fov/ { print $2 ; exit }' $SPAR \
            | tr -d '\r'`
        THICK=`awk -F: '/^slice_thickness/ { print $2 ; exit }' $SPAR \
            | tr -d '\r'`
        if [ "$FOV" != ""    -a   "$THICK" != "" ]
        then
            VOLUME=`echo "$FOV $THICK $ROWS" |\
                   awk '{ if ( $3 > 0 )
                         printf ( "%e", $1 * $1 * $2 / ( 1000 * $3 ) ) }'`
        fi
    else
        #
        # Assume time-series with $ROWS columns and 1 row.
        #
        VOLUME=`echo "$AP_SIZE $LR_SIZE $CC_SIZE" |\
                awk '{ if ( $1 * $2 * $3 > 0 )
                      printf ( "%e", $1 * $2 * $3 / 1000 ) }'`
        echo "ndcols= $ROWS" >> $CP_START
        TIME_SERIES=1
    fi
fi

if [ "$VOLUME" = "" ]
then
    VOLUME_TITLE="??mL"
    VOLUME_NMID="1."
else
    VOLUME_TITLE=`echo "$VOLUME" | awk '{ printf ("%.2e mL", $1 ) }' |\
                  tr ',' '.'`
    VOLUME_NMID=`echo "$VOLUME" | awk '{ printf ("%.3e", $1 ) }' |\
                 tr ',' '.'`
fi


# Rest of TITLE.
# Start file $RAW

echo " \$SEQPAR"  >  $RAW

TE=`awk -F: '/^echo_time/             { print $2 ; exit }' $SPAR | tr -d '\r'`
TE_VALUE=`echo "$TE" |\
           awk '{if ( $1 > 0 )
                    printf ( "%.2f", $1 ) }' | tr ',' '.'`
if [ "$TE_VALUE" != "" ]
then
    TE_TITLE=`echo "$TE" | awk ' { printf ( "%d", $1 ) }'`
    echo " echot= $TE_VALUE"  >>  $RAW
    echo "echot  $TE_VALUE"  >>  $EXTRA_INFO
fi

TR=`awk -F: '/^repetition_time/       { print $2 ; exit }' $SPAR | tr -d '\r'`
TR_TITLE=`echo "$TR" | awk ' { printf ( "%d", $1 ) }'`

NS=`awk -F: '/^averages/              { print $2 ; exit }' $SPAR | tr -d '\r'`
if IsNonInteger $NS
then
    NS_TITLE="??"
else
    NS_TITLE=`echo "$NS" | awk ' { printf ( "%d", $1 ) }'`
fi

ID=`awk -F: '/^scan_id/               { print $2 ; exit }' $SPAR | tr -d '\r'`
ID=`echo $ID`

TITLE="title= '$EXAM ($DATE) $NAME ($BIRTH) $VOLUME_TITLE, \
TE/TR/NS=$TE_TITLE/$TR_TITLE/$NS_TITLE ($ID)'"

# Get the rest of the entries.
#
FILRAW="filraw= '$RAW'"
FILPS="filps= '${LCM_DIR}ps'"

echo "$TITLE
$FILRAW
$FILPS"  >>  $CP_START

HZPPPM=`awk -F: '/^synthesizer_frequency/ { print $2 ; exit }' $SPAR |\
        tr -d '\r'`
INT=`echo "$HZPPPM" | awk -F. '{print $1}'`

# HZPPPM may be in Hz or MHz.  Therefore, the test with "HZPPPM > 1000" below.
#

if [ $INT -gt 1000 ]
then
   HZPPPM_VALUE=`echo "$INT" | awk '{printf("%.4e", $1 / 1000000)}' |\
                               tr ',' '.'`
elif [ $INT -gt 10 ]
then
   # Clumsy way to get 3 figures behind decimal point with integers (assumes 
   #    that there are at least 3 figures there).
   # HZ1000 = 1000 * HZPPPM
   #
   HZ1000=`expr 1000 \* $INT`
   FRACT=`echo "$HZPPPM" | awk -F. '{print $2}' | cut -c1-3`
   HZ1000=`expr $HZ1000 + $FRACT`
   HZPPPM_VALUE=`echo "$HZ1000" | awk '{printf( "%.4e", $1 / 1000)}' |\
                                  tr ',' '.'`
fi
#echo "hzpppm = $HZPPPM = $HZPPPM_VALUE"
if [ "$HZPPPM_VALUE" != "" ]
then
    echo "hzpppm=  $HZPPPM_VALUE"  >>  $CP_START
    echo "hzpppm   $HZPPPM_VALUE"  >>  $EXTRA_INFO
    echo " hzpppm=  $HZPPPM_VALUE"  >>  $RAW
fi

DELTAT=`awk -F: '/^sample_frequency/  { print $2 ; exit }' $SPAR | tr -d '\r'`
DELTAT_VALUE=`echo "$DELTAT" |\
               awk ' { if ( $1 > 0 )
                          printf ( "%.3e", 1 / $1 ) }' | tr ',' '.'`
if [ "$DELTAT_VALUE" != "" ]
then
    echo "deltat= $DELTAT_VALUE"  >> $CP_START
fi

NUNFIL=`awk -F: '/^samples/          { print $2 ; exit }' $SPAR | tr -d '\r'`
if  IsNonInteger $NUNFIL
then
    :
else
    if [ $NUNFIL -gt 0 ]
    then
        echo "nunfil= $NUNFIL"  >>  $CP_START
    fi
fi

NDCOLS=`awk -F: '/dim2_pnts/    { print $2 ; exit }' $SPAR | tr -d '\r'`
NDCOLS_VALUE=1
if IsNonInteger $NDCOLS
then
    :
else
    if [ $NDCOLS -gt 0 ]
    then
        NDCOLS_VALUE=$NDCOLS
    fi
fi
if [ $TIME_SERIES -ne 1 ] 
then
    echo "ndcols= $NDCOLS_VALUE"  >>  $CP_START
fi

NDSLIC=`awk -F: '/dim4_pnts/    { print $2 ; exit }' $SPAR | tr -d '\r'`
NDSLIC_VALUE=1
if IsNonInteger $NDSLIC
then
    :
else
    if [ $NDSLIC -gt 0 ]
    then
        NDSLIC_VALUE=$NDSLIC
    fi
fi
echo "ndslic= $NDSLIC_VALUE"  >>  $CP_START
#-----------------------------------------------------------------------------

# Extract further info for extraInfo from SPAR file.
#

# The default directory path for archiving the LCModel results will end in 
#   headerInfo1/headerInfo2/headerInfo3/.
# The headerInfoName's will appear in the "Configure Save Directory" window.
# You may want to eliminate some of these, add new ones, or change their order.
#
HEADER_INFO1="headerInfo1  $EXAM"
HEADER_INFO_NAME1="headerInfoName1 Examination Name"
HEADER_INFO2="headerInfo2  $NAME"
HEADER_INFO_NAME2="headerInfoName2 Patient Name"
HEADER_INFO3="headerInfo3  $DATE"
HEADER_INFO_NAME3="headerInfoName3 Scan Date"

# Get the coordinates of the voxel.  If eddy-current correction is to be done, 
#   the coordinates of the two spectra will be compared to be sure that they 
#   are from the same voxel.  (The abbreviations "Sag", "Cor' & "Tra" are 
#   unimportant here; they come from the Siemens header names.)
# If commas are used as decimal points, only integer values will be used.
#
SAG=`awk -F: '/^ap_off_center/       { print $2 ; exit }' $SPAR | tr -d '\r'`
SAG_VALUE=`echo "$SAG" | awk '{ printf ( "%.3e", $1 ) }' | tr ',' '.'`
if [ "$SAG_VALUE" != "" ]
then
    echo "voiPositionSag  $SAG_VALUE"  >>  $EXTRA_INFO
fi

COR=`awk -F: '/^lr_off_center/       { print $2 ; exit }' $SPAR | tr -d '\r'`
COR_VALUE=`echo "$COR" | awk '{ printf ( "%.3e", $1 ) }' | tr ',' '.'`
if [ "$COR_VALUE" != "" ]
then
    echo "voiPositionCor  $COR_VALUE"  >>  $EXTRA_INFO
fi

TRA=`awk -F: '/^cc_off_center/       { print $2 ; exit }' $SPAR | tr -d '\r'`
TRA_VALUE=`echo "$TRA" | awk '{ printf ( "%.3e", $1 ) }' | tr ',' '.'`
if [ "$TRA_VALUE" != "" ]
then
    echo "voiPositionTra  $TRA_VALUE"  >>  $EXTRA_INFO
fi


if [ $NDCOLS_VALUE -eq 1  -a  $NDROWS_VALUE -eq 1  -a  $NDSLIC_VALUE -eq 1 \
     -a   $TIME_SERIES -ne 1 ]
then
    echo "singleVoxel  1" >>  $EXTRA_INFO
fi

# Write extraInfo
#
echo "$HEADER_INFO1
$HEADER_INFO_NAME1
$HEADER_INFO2
$HEADER_INFO_NAME2
$HEADER_INFO3
$HEADER_INFO_NAME3"  >>  $EXTRA_INFO
#-----------------------------------------------------------------------------

# Finish $RAW file
# Note that all lines in Namelists must start in Column 2.
# TRAMP is arbitrarily set to 1.0 below, because of lack of scaling 
#   information for the spectra.  This will only affect the absolute 
#   concentrations, not the concentration ratios.  The LCModel "Water-Scaling" 
#   option can help with estimates of absolute concentrations if you have an 
#   unsuppressed water reference spectrum from the same voxel.
#
echo " \$END
 \$NMID
 id= '`basename $DATA_FILE`'
 bruker= T
 fmtdat= '(2e15.6)'
 volume= $VOLUME_NMID
 tramp= 1.
 \$END"  >>  $RAW

# bin2asc now appends the time data to $RAW
# bin2asc outputs error messages to stderr (which is redirected to $ERROR, 
#   which is displayed in a diagnostic window by LCMgui).
#
$HOME/.lcmodel/philips/bin2asc  $DATA_FILE  $LCM_DIR  $MET_H2O  2>$ERROR
#----------------------------------------------------------------------------
#
# You must always exit this script with "exit 0"
#
exit 0

#=============================================================================
#=============================================================================
#=============================================================================

#                       General Instructions
#                       ====================

#     If you want to modify this file, use this file as a template only; copy 
# it to my-bin2raw (in the same directory as bin2raw), and then edit 
# my-bin2raw.
#     LCMgui always first attempts to execute my-bin2raw.  If LCMgui cannot 
# find my-bin2raw, then it executes bin2raw.
#     bin2raw will be overwritten by LCMgui updates, but your my-bin2raw will 
# not be overwritten.

#
#      LCMgui executes this script and supplies 3 arguments to it, i.e., it 
# executes
#   $HOME/.lcmodel/other/bin2raw  $1  $2  $3
#----------------------------------------------------------------------------

#      The 3 arguments supplied by LCMgui are:
#
# $1 = the absolute pathname of the data file that you selected to be 
#      analyzed.
#
# $2 = the absolute pathname (with a "/" at the end) of the temporary 
#      directory where you must out the output from this script.
#
# $3 = met if the data file contains your water-suppressed data (or if the 
#          data file contains both your water-suppressed data and your 
#          unsuppressed water reference data for eddy-current correction).
#    = h2o if the data file contains only the unsuppressed water reference 
#          data.

# (C programs can access $3 as argv[3], etc.)
#----------------------------------------------------------------------------

#     This script must output the following files:

# $2$3/RAW = LCModel RAW file.

# $2h2o/RAW = LCModel RAW file of the unsuppresed water reference data for
#             eddy-current correction. 
#                  This is only possible if your data file contains both the
#             unsuppressed and suppressed data.  In this case, $3 = "met", and 
#             you output both $2$3/RAW and $2h2o/RAW.
#                  If the unsuppressed and suppressed are in different files,
#             then you only output $2$3/RAW, first when $3 = "met", and later 
#             LCMgui calls other/bin2raw again with another $1 and with 
#             $3 = "h2o"

# $2$3/cpStart : sets any default Control Parameters (which you can later 
#                  modify in LCMgui) that can be obtained from (the headers 
#                  of) your data file.
#                The format illustrated below must be strictly followed; i.e.:
#                  control_parameter= value
#                e.g.,
#                  hzpppm= $HZPPPM_VALUE
#                with NO space between the control parameter and the "=" and 
#                with space between the "=" and the value.

# $2$3/extraInfo : As illustrated below, this file can contain "echot" and 
#                    "seq", with which LCMgui will attempt to automatically 
#                    select the correct default BASIS file of model spectra 
#                    with these sequence parameters.
#                  With the three "voiPosition*", LCMgui will produce an error 
#                    window if these three in the unsuppressed reference and 
#                    water-suppressed files do not agree (indicating spectra 
#                    from different voxels).
#                  With the "headerInfo*, the default path of the directory 
#                    that archives the LCModel results is determined.
#                  The format is illustrated below.  It is the same as for 
#                    cpStart, except that there is no "=".  There still must 
#                    be space between the parameter and the value.

# $2$3/error : Error messages on aborts should go here.  They will then be 
#                displayed by LCMgui, PROVIDED that you then exit with 
#                "exit 0"; i.e., a "successful" exit.  It is essential that 
#                ALL exits (successful and error exits) be with "exit 0".
#              From a C program, you must also always exit with "exit(0)".
