#!/bin/sh
#
# tarprj <project>
#
#        03/03/2026  Now handles IMU and STREAM tags.
#        12/14/2023  The .calglobs file is now included.
#        08/08/2023  The .rdmask file is now included.
#        07/22/2023  The .psp file is no longer included.
#        04/25/2023  Fix BODY_SEARCH_PARAMS.SEARCH_PARAMS not being included.
# 0.9.0  12/10/2022  Added -no_images option
#        07/01/2021  Made -t use PATTERN instead of FILE for .ppf files.
# 0.8.0  08/19/2019  Added -t option.
# 0.7.2  05/12/2017  Now handles .mdl files specified with BIO_DATA_DIR
#                    even if BIO_DATA_DIR is not set.
# 0.7.1  04/27/2017  Now handles background movies.
# 0.7.0  12/12/2014  Updated to use GIANT_DATA_DIR.
#        12/17/2014  Removed extra blank lines from file listing output
#        04/06/2015  Now exits with an error if the tar fails
# 0.6.0a 04/13/2012  Now handles textures in the graphics models.
# 0.6.0  05/31/2011  Updated to release version.
# 0.5.0d 04/18/2012  Handles more of the extra files.
# 0.5.0c 02/12/2011  Prints the name of the tar file at the end.
# 0.5.0b 07/06/2009  Prints missing files to stderr.
# 0.5.0a 02/11/2009  Added -r option.
# 0.5.0  07/18/2008  Now handles files that contain INCLUDE sections which
#                    include files of the same type.
# 0.4.0  06/04/2008  Now includes all .ppf files from the bodydef directory
#                    if a bodydef is specified in the project.
# 0.3.3  06/13/2003  Made it recognize gzipped files.
#        12/23/2004  Made it recognize directories (IMAGES)
#        03/21/2005  Added -l option.
#        03/28/2006  Added -f option.
#        12/11/2006  Now includes .psf file
#        02/09/2007  Changed to handle symlinks in current directory better.
#        03/05/2007  Handles .rtparams and .cpj files
#        03/08/2007  Handles symlinks better when absolute path is given for
#                    project file.
# 0.3.2  06/12/2001  Made it handle BIO_DATA_DIR with trailing slash.
#                    tarprj tries to remove the $BIO_DATA_DIR from the
#                    project name that you give it.  In doing so, it gets the
#                    full path of the project file.  If this path has a symlink
#                    in it, then the beginning of the path won't match
#                    $BIO_DATA_DIR, so it won't get substituted.  tarprj
#                    now doesn't try to expand the path if you give a full
#                    path to begin with.  This means that you can use
#                      tarprj $PWD/subject.trial.prj
#                    to get the correct behavior since $PWD usually has the
#                    non-symlink-substituted path name.
# 0.3.1  01/05/2001  Was looking for UNSCALED_BODYDEF instead of
#                    UNSCALED_BODY_DEF
# 0.3.0  10/20/2000  Updated to read projects that contain the string
#                    "$BIO_DATA_DIR" as part of a file name.
#                    Handles the newer names for the MAPPING, MODELS, and
#                    UNSCALED_MODELS tags.
# 0.2.0  10/16/2000  Updated to include problem specifications in the tar file.
#                    Previous versions created the tar file in $BIO_DATA_DIR.
#                    The tar file will now be created in the current directory.
#                    The full path name of the project is no longer required.
# 0.1.0  05/22/2000  Initial version.
#


if [ $# = 0 ]; then
  echo "" >&2
  echo "Usage: tarprj [<options>] <project>" >&2
  echo "  Creates a tar file with all the files related to the given .prj" >&2
  echo "  file." >&2
  echo >&2
  echo "Usage: tarprj -f <name> [<options>] <project>" >&2
  echo "  Creates a tar file with all the files related to the given .prj" >&2
  echo "  file. The resulting tar file is created with the given name." >&2
  echo "  If - is used for <name>, the output is written to stdout" >&2
  echo "  instead." >&2
  echo >&2
  echo "Usage: tarprj -l [<options>] <project>" >&2
  echo "  Lists all the files related to the given .prj file." >&2
  echo >&2
  echo "Usage: tarprj -t [<options>] <project>" >&2
  echo "  Lists the files that are directly used by the given .prj file." >&2
  echo >&2
  echo "Options:" >&2
  echo "  -r          : <project> is specified relative to the workspace." >&2
  echo "  -no_images  : Do not include the images directory." >&2
  echo "" >&2
  exit 1
fi

tar_file=""
list_only=0
top_only=0
relative_prj=0
no_images=0

while [ $# -gt 1 ]; do
  if [ x"$1" = x"-l" ]; then
    list_only=1
    shift
  elif [ x"$1" = x"-t" ]; then
    top_only=1
    shift
  elif [ x"$1" = x"-f" ]; then
    tar_file="$2"
    if [ x"$tar_file" != x- ]; then
      tar_file=`basename "$tar_file" .gz`
      tar_file=`basename "$tar_file" .tar`
      tar_file=`dirname "$2"`/"$tar_file"
    fi
    shift 2
  elif [ x"$1" = x"-r" ]; then
    relative_prj=1
    shift
  elif [ x"$1" = x"-no_images" ]; then
    no_images=1
    shift
  else
    break
  fi
done

if [ $# = 0 ]; then
  echo "No project specified." >&2
  exit 1
fi

if [ $# -gt 1 ]; then
  echo "Too many projects specified." >&2
  exit 1
fi

project_file=$1

# platform check

uname_out=`uname`
if [ `expr $uname_out : 'IRIX'` = 4 ]; then
  AWK=nawk
elif [ "$uname_out" = "Linux" ]; then
  AWK=awk
else
  echo "Unknown platform." >&2
  exit 1
fi

data_dir=${GIANT_DATA_DIR%/}

if [ "$data_dir" = "" ]; then
  data_dir=${BIO_DATA_DIR%/}
fi

if [ ! -f "$project_file" ]; then
  echo >&2
  echo "Project file: \"$project_file\" does not exist." >&2
  echo >&2
  exit 1
fi


fixup_fn() {
  fn=$1
  if [ x"$fn" = x ]; then
    echo "$fn"
  else
    fn=${fn#$data_dir/}    # remove the substring equal to the value of 
                              # $BIO_DATA_DIR and a "/"
    fn=${fn#'$BIO_DATA_DIR'/}    # remove the string "$BIO_DATA_DIR/"
    fn=${fn#'$GIANT_DATA_DIR'/}  # remove the string "$GIANT_DATA_DIR/"

    if [ -f "$fn" ]; then
      echo "$fn"
    elif [ -d "$fn" ]; then
      echo "$fn"
    elif [ -f "$fn.gz" ]; then
      echo "$fn.gz"
    else
      echo "Missing $fn" >&2
    fi
  fi
}


fixup_filenames () {
  local new_files=""

  for file in "$@"; do
    new_files="$new_files `fixup_fn $file`"
  done

  echo "$new_files"
}


full_path_name() {
  # No leading /
  # must be an easier way to do this
  cwd=`pwd`
  dn=`dirname $1`
  cd $dn
  dir=`/bin/pwd`
  cd $cwd
  echo $dir/`basename $1`
}


get_includes() {
# recursively finds include files in the given file using the tagfile utility
# this does not handle infinite recursion currently
# handles compressed files
  base_file=$1
  base_file=`eval echo $base_file`

  if [ x"$base_file" != x"" -a ! -f "$base_file" ]; then
    # choose the compressed version of the file if it exists and the 
    # uncompressed doesn't exist
    if [ -f "${base_file}.gz" ]; then
      base_file="${base_file}.gz"
    fi
  fi

  if [ x"$base_file" != x"" -a -f "$base_file" ]; then
    uncompressed_base_file=${base_file%.gz}

    if [ $uncompressed_base_file != $base_file ]; then
      tmp_uncompressed_base_file=${uncompressed_base_file}.tarprj_$$
      gunzip -c $base_file >$tmp_uncompressed_base_file
      tagfile_file=$tmp_uncompressed_base_file
    else
      tagfile_file=$base_file
    fi

    include_file_names=`tagfile -getfile INCLUDE.FILE_NAME $tagfile_file`

    if [ x"$include_file_names" != x"" ]; then
      # pass the result through xargs to join the output into one line
      echo "$include_file_names" | expand_includes | xargs
    fi

    if [ "$uncompressed_base_file" != "$base_file" ]; then
      rm -f $tmp_uncompressed_base_file
    fi
  fi
}

expand_includes() {
  while read include_file_name; do
    fixup_fn "$include_file_name"
    get_includes "$include_file_name"
  done
}


topprjfiles () {
  prj="$1"
  awk -v no_images=$no_images '
    function expand(x)
    {
      gsub("\\$BIO_DATA_DIR/","",x);
      gsub("\\$GIANT_DATA_DIR/","",x);
      gsub("\\$NU_DATA_DIR/","",x);
      return x;
    }

    $1=="EST_POSITION:" { print "FILE: "expand($2) }
    $1=="MEASURED_INSTRUMENT:" { print "FILE: "expand($2) }
    $1=="MEASURED:" { print "FILE: "expand($2) }
    $1=="CALIBRATION:" { print "FILE: "expand($2) }
    $1=="THREEDDATA:" { print "FILE: "expand($2) }
    $1=="SEARCH_PARAMS:" { print "FILE: "expand($2) }
    $1=="RAW_DATA:" { print "FILE: "expand($2) }
    $1=="CAL_GLOBS:" { print "FILE: "expand($2) }
    $1=="RAW_DATA_MASK:" { print "FILE: "expand($2) }
    $1=="GLOB_IDS:" { print "FILE: "expand($2) }
    $1=="PATTERN:" { print "PATTERN: "expand($2) }
    $1=="SCALE_DEF:" { print "FILE: "expand($2) }
    $1=="PROBLEM_SPEC:" { print "FILE: "expand($2) }
    #  Problem spec is treated as a regular file, so it will not be expanded,
    #  since it is just there for reference.
    $1=="PROBLEM_DEF:" { print "PROBLEM_DEF: "expand($2) }
    $1=="UNSCALED_MODELS:"  { print "BODY_DEF: "expand($2) }
    $1=="UNSCALED_BODY_DEF:" { print "BODY_DEF: "expand($2) }
    $1=="IMAGES_DIR:" { if (!no_images) { print "DIRECTORY: "expand($2) } }
    $1=="MAPPING:"  { print "MAPPING: "expand($2) }
    $1=="MODELS:"   { print "BODY_DEF: "expand($2) }
    $1=="BODY_DEF:" { print "BODY_DEF: "expand($2) }
    $1=="LIMITS:" { print "LIMITS: "expand($2) }
    $1=="GFX_MODEL:" { print "MODEL: "expand($2) }
    $1=="GFX_MAPPING:" { print "MAPPING: "expand($2) }
    $1=="GFX_SCALING:" { print "SCALING: "expand($2) }
    $1=="MOTION:" { print "MOTION: "expand($2) }
  ' <"$prj" || exit 1
}


#
# Make it so that the command can be executed from any directory.
# We have to create the tar file as if we are in the workspace
# so it will extract properly.
#

if [ $relative_prj = 1 ]; then
  project_file=$data_dir/$project_file
  # This option lets you get around issues where your prj is stored outside
  # the workspace but a symlink is used to make the prj appear to be
  # inside the workspace.
else
  project_file=`full_path_name $project_file`
fi

if [ $top_only = 1 ]; then
  topprjfiles $project_file || exit 1

  # special logic to get any .ppf files which are in the same directory
  # as the .bdf file.

  body_def=`
    $AWK '
      $1=="MODELS:"   { print $2 }
      $1=="BODY_DEF:" { print $2 }
    ' <$project_file`

  body_def=`eval echo $body_def`

  if [ x"$body_def" != x"" ]; then
    body_def_dir=`dirname $body_def`

    for ppf in $body_def_dir/*ppf; do
      if [ -f $ppf ]; then
        relative_ppf=${ppf#$data_dir/}
        echo "FILE: $relative_ppf"
      fi
    done
  fi

  # special logic to get extra files that may be useful.

  prjname=`basename $project_file .prj`
  prjdir=`dirname $project_file`/$prjname

  for ext in rtparams wav imu str rng psf ppf; do
    extra_file=$prjdir/$prjname.$ext

    if [ -f $extra_file ]; then
      # remove workspace from the beginning
      extra_file=${extra_file#$data_dir/}
      echo "FILE: $extra_file"
    fi
  done

  exit 0
fi

cwd=`pwd`
cd $data_dir

problem_def=`
  $AWK '
    $1=="PROBLEM_DEF:" { print $2 }
  ' <$project_file
`

problem_def_inc=`get_includes $problem_def`

measured_inst=`
  $AWK '
    $1=="MEASURED_INSTRUMENT:" { print $2 }
  ' <$project_file
`

calibration=`
  $AWK '
    $1=="CALIBRATION:" { print $2 }
  ' <$project_file
`

measured=`
  $AWK '
    $1=="MEASURED:" { print $2 }
  ' <$project_file
`

scale_def=`
  $AWK '
    $1=="SCALE_DEF:" { print $2 }
  ' <$project_file
`

unscaled_body_def=`
  $AWK '
    $1=="UNSCALED_MODELS:"  { print $2 }
    $1=="UNSCALED_BODY_DEF:" { print $2 }
  ' <$project_file
`

raw_data=`
  $AWK '
    $1=="RAW_DATA:" { print $2 }
  ' <$project_file
`

rdmask=`
  $AWK '
    $1=="RAW_DATA_MASK:" { print $2 }
  ' <$project_file
`

calglobs=`
  $AWK '
    $1=="CAL_GLOBS:" { print $2 }
  ' <$project_file
`

if [ $no_images -eq 0 ]; then
  images_dir=`
    $AWK '
      $1=="IMAGES_DIR:" { print $2 }
    ' <$project_file
  `
fi

mapping=`
  $AWK '
    $1=="MAPPING:"  { print $2 }
    $1=="GLOB_IDS:" { print $2 }
  ' <$project_file
`

threed_data=`
  $AWK '
    $1=="THREEDDATA:" { print $2 }
  ' <$project_file
`

body_def=`
  $AWK '
    $1=="MODELS:"   { print $2 }
    $1=="BODY_DEF:" { print $2 }
  ' <$project_file
`

body_def_inc=`get_includes $body_def`

limits=`
  $AWK '
    $1=="LIMITS:" { print $2 }
  ' <$project_file
`

limits_inc=`get_includes $limits`

search_params=`
  $AWK '
    $1=="SEARCH_PARAMS:" { print $2 }
  ' <$project_file
`

est_position=`
  $AWK '
    $1=="EST_POSITION:" { print $2 }
  ' <$project_file
`

gfx_model=`
  $AWK '
    $1=="GFX_MODEL:" { print $2 }
  ' <$project_file
`

if [ "$gfx_model" != "" ]; then
  gfx_model=`full_path_name $(fixup_fn "$gfx_model")`
fi

gfx_mapping=`
  $AWK '
    $1=="GFX_MAPPING:" { print $2 }
  ' <$project_file
`

gfx_mapping_inc=`get_includes $gfx_mapping`

gfx_scaling=`
  $AWK '
    $1=="GFX_SCALING:" { print $2 }
  ' <$project_file
`

gfx_scaling_inc=`get_includes $gfx_scaling`

motion=`
  $AWK '
    $1=="MOTION:" { print $2 }
  ' <$project_file
`

imu=`
  $AWK '
    $1=="IMU:" { print $2 }
  ' <$project_file
`

stream=`
  $AWK '
    $1=="STREAM:" { print $2 }
  ' <$project_file
`

pattern=`tagfile -getfile PATTERN "$project_file"`
prjname=`basename $project_file .prj`
prjdir=`dirname $project_file`/$prjname

extra_files=""
for ext in rtparams cpj psf secondary.anm wav imu str rng rtparams; do
  extra_file=$prjdir/$prjname.$ext
  if [ -f $extra_file ]; then
    extra_file=`fixup_fn $extra_file`
    extra_files="$extra_files $extra_file"
  fi
done

if [ x"$tar_file" = x ]; then
  tar_file=$cwd/`basename $project_file`
fi

if [ x"$tar_file" != x"-" ]; then
  tar_file="$tar_file".tar.gz
fi

background_movies=`tagfile -getfile BACKGROUND_MOVIE.MOVIE $project_file`

if [ $? != 0 ]; then
  exit 1
fi

#
# Process the file names so they tar up nicely relative to the workspace.
# Set the file names to nothing if they do not exist.
#

project_file=`fixup_fn $project_file`
problem_def=`fixup_fn $problem_def`
measured_inst=`fixup_fn $measured_inst`
calibration=`fixup_fn $calibration`
measured=`fixup_fn $measured`
scale_def=`fixup_fn $scale_def`
unscaled_body_def=`fixup_fn $unscaled_body_def`
raw_data=`fixup_fn $raw_data`
rdmask=`fixup_fn $rdmask`
calglobs=`fixup_fn $calglobs`
images_dir=`fixup_fn $images_dir`
mapping=`fixup_fn $mapping`
threed_data=`fixup_fn $threed_data`
body_def=`fixup_fn $body_def`
limits=`fixup_fn $limits`
search_params=`fixup_filenames $search_params`
est_position=`fixup_fn $est_position`
gfx_mapping=`fixup_fn $gfx_mapping`
gfx_scaling=`fixup_fn $gfx_scaling`
motion=`fixup_fn $motion`
imu=`fixup_fn $imu`
stream=`fixup_fn $stream`
ppf_files=""
ppf_files_inc=""

if [ x"$gfx_model" != x ]; then
  gfx_model_files=`tarmdl -l $gfx_model`
fi


background_movies=$(fixup_filenames $background_movies)

# generate the ppf files and includes

if [ x"$body_def" != x"" ]; then
  body_def_dir=`dirname $body_def`

  if [ "$pattern" = "" ]; then
    ppf_pattern=$body_def_dir/*.ppf
    the_ppf_files=`echo $ppf_pattern`

    if [ x"$the_ppf_files" = x"$ppf_pattern" ]; then
      # no ppf files
      ppf_files=""
    else
      ppf_files=`echo $the_ppf_files | xargs -n 1 | expand_includes | xargs`
    fi
  else
    ppf_files=`echo $pattern | xargs -n 1 | expand_includes | xargs`
  fi
fi

# collect the files

files="$project_file $problem_def $problem_def_inc $measured_inst $calibration $measured $scale_def $unscaled_body_def $raw_data $rdmask $calglobs $images_dir $mapping $threed_data $body_def $body_def_inc $limits $limits_inc $search_params $est_position $gfx_model_files $gfx_mapping $gfx_mapping_inc $gfx_scaling $gfx_scaling_inc $motion $imu $stream $ppf_files $ppf_files_inc $background_movies $extra_files"

# remove duplicate files

files=`echo $files | xargs -n 1 | sort | uniq`

if [ $list_only = 1 ]; then
  echo "$files"
else
  files=`echo $files | xargs`   # join into single line
  tar c -zvf $tar_file $files || exit 1
  echo >&2
  if [ x"$tar_file" != x"-" ]; then
    echo "Created $tar_file" >&2
    echo >&2
  fi
fi
