#!/bin/bash

# COPYRIGHT {{{1
# This file is part of Mkat
#
# Copyright (C) 2004, 2005, 2013 Dmitry Maksyoma <ledestin at gmail.com>.
#
# Mkat is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
# USA.

# LOAD GLOBAL CONFIG {{{1
# User config is loaded later because -c option allows to specify config name.
RCFILE=mkatrc
[ -f "/etc/$RCFILE" ] && . "/etc/$RCFILE"
[ -z "$MKAT_LIBPATH" ] && \
  { echo >&2 "ERROR: MKAT_LIBPATH not set (edit /etc/$RCFILE)"; exit 1; }
. "$MKAT_LIBPATH/helpers.sh" || exit 1
. "$MKAT_LIBPATH/common.sh" || exit 1

# UNSET INTERNAL VARIABLES {{{1
# (so that environment variables wouldn't interfere)
unset CONFIG

# CLI ARGUMENTS {{{1 
BANNERS=("[options]" "-w -t <tag1,tag2> <file>...")
OPTIONS=(\
  -a "show what tags can be searched with -S" 'SHOW_AVAILABLE_TAGS=1' \
  --add-id-tag 'add unique ID tag (format #<NUMBER>), when cataloguing' '?ADD_ID_TAG' \
  '-c|--config=FILE' "read FILE instead of the default config (~/.$RCFILE)"\
    'CONFIG="$2"; CHILD_PARAMS=$CHILD_PARAMS\ -c\ \"$CONFIG\"' \
  '-d|--debug' "debug output" 'DEBUG=1; CHILD_PARAMS=$CHILD_PARAMS\ -d' \
  -E "use extended regular expressions" '?EXTENDED_REGEX' \
  -f "overwrite list file" 'FORCE_OVERWRITE=1' \
  '-h|--help' "print this help screen" 'usage 0' \
  -m=FILE "make file md5 sum and search for it in the db" '@MD5FILES' \
  --md5dir=DIR "print files with md5 sums not present in the db" '@DIR'
  --next-id-tag "print ID tag that would be used to catalog new media" '?NEXT_ID_TAG' \
  -p=PATH 'catalog custom path instead of $CD' 'CATALOG_PATH=${2%%/}' \
  -q "be quiet" 'CHILD_PARAMS=$CHILD_PARAMS\ -q; GREP_PARAMS="-q"' \
  -s=REGEX "search the catalog database" '@REGEX' \
  -S=TAG1,TAG2 "search within tags only" 'TAG_REGEX=$2; EXTENDED_REGEX=1' \
  -t=TAG1,TAG2 "write list file with 'tags: TAG1 TAG2' string" 'TAGS=${2//,/ }' \
  -T "don't search within tags with -s (no tags)" '?FILTER_TAGS' \
  -w "write tag line into existing files (use with -t)" 'RETAG_FILES=1' \
  -y "loop { mkat; eject; }" 'CYCLE_CATALOG=1')

process_options "$@"

# LOAD USER-LEVEL CONFIG {{{1
if [ -n "$CONFIG" ]; then
  debug "reading rc file: \`$CONFIG'"
  . "$CONFIG" || {
    error "\`$CONFIG': could not read config (specified with -c)"
    exit 1
  }
else
  CONFIG=~/."$RCFILE"
  if [ -f "$CONFIG" ]; then
    debug "reading rc file: \`$CONFIG'"
    . "$CONFIG"
  fi
fi

# CHECK CONFIGURATION (CONFIG-LOADED) {{{1
fail_unless_defined "CD LISTDIR"
interpolate_envvars

make_dir "$LISTDIR"

MKAT="$0${CHILD_PARAMS:+ $CHILD_PARAMS}"
GREP_PARAMS="${GREP_PARAMS:+$GREP_PARAMS }-i"
if [ "$EXTENDED_REGEX" ]; then
  GREP_PARAMS="$GREP_PARAMS -E"
else
  GREP_PARAMS="$GREP_PARAMS -F"
fi
GREP="grep${GREP_PARAMS:+ $GREP_PARAMS}"

# OPTION PROCESSING PART {{{1
# Show tags (-a) {{{2
if [ -n "$SHOW_AVAILABLE_TAGS" ]; then
  grep -h ^tags: "$LISTDIR"/*.list | awk -F: '{ print $2 }'\
    | awk 'BEGIN { RS="\n| " }; { if (length > 0 && $0 !~ /^#/) print }' | sort -u
  exit
fi

# Tag list files {{{2
if [ "$RETAG_FILES" ]; then
  [ -z "$TAGS" ] && \
    { error "use -t option to specify tags" && usage && exit 1; }
  #write new tags line in RETAG_FILES 
  debug "${#ARGUMENTS[@]} files to process"
  for f in "${ARGUMENTS[@]}"; do
    [ -f "$f" ] || { "file not found: $f"; exit 1; }
    debug "adding tag line to $f"
    sed -i "2 {
    /^tags:/ {
    c\
tags: ${TAGS[@]}
    n
    }

    i\
tags: ${TAGS[@]}
}" "$f"
  done
  exit
fi

# Process --md5dir option {{{2
if [ "$DIR" ]; then
  IFS=:; FILES=(`find "$DIR" -type f -printf '%p:'`)
  unset IFS; 
  for f in "${FILES[@]}"; do
    cmd="$MKAT -q -m \"$f\""
    debug "$cmd"; eval "$cmd"
    [ $? -ne 0 ] && echo "$f";
  done;
  exit
fi

# Tag search (-S) {{{2
if [ "$TAG_REGEX" ]; then
  debug "grep for tags (-S)"
  FILES="$LISTDIR/*.list"
  cmd="$GREP ^tags:.+$TAG_REGEX \$FILES"
  if [ ${#TAG_REGEX[@]} -gt 1 ]; then
    i=1
    while [ $i -lt ${#TAG_REGEX[@]} ]; do
      cmd="$cmd | $GREP ${TAG_REGEX[$i]}"
      let "i += 1"
    done
  fi
  debug $cmd; RES=`eval "$cmd"`
  #exit if -s isn't present, else RES will be further processed by -s
  #handler
  if [ -z "$REGEX" ]; then
    echo "$RES"
    exit $?
  fi
fi

# Search the database with grep (-s option) {{{2
if [ "$REGEX" ]; then
  IFS=''; 
  if [ "$RES" ]; then
    cmd="echo -e \"${RES//$RET/\\\\n}\" | $GREP $REGEX"
  else
    cmd="$GREP "\'$REGEX\'" "$LISTDIR"/*.list"
  fi
  [ $FILTER_TAGS ] && cmd="$cmd | $GREP -v '(^|:)tags:'"
  if [ ${#REGEX[@]} -gt 1 ]; then
    i=1
    while [ $i -lt ${#REGEX[@]} ]; do
      cmd="$cmd | $GREP "\'${REGEX[$i]}\'""
      let "i += 1"
    done
  fi
  debug "command: $cmd"; eval "set +f; $cmd"
  exit $?
fi

# Search by md5 sum of a file {{{2
if [ "$MD5FILES" ]; then
  cmd="md5sum \"\${MD5FILES[@]}\" | awk '{ printf \"%s|\", \$1 }'\
    | sed 's/|$/\n/' | xargs -ivar $MKAT -s \'var\'"
  debug $cmd; eval $cmd
  exit $?
fi

# Catalog many CDs (-y): loop mkat, eject, wait for user input {{{2
if [ $CYCLE_CATALOG ]; then
  while : ; do
    $MKAT && sleep $AUTOFS_DELAY && eject
    read -p "Press Enter when ready..."
    [ $? -eq 0 ] || exit
  done
fi

# CATALOG THE $CD {{{1
if [ -z "$CATALOG_PATH" ]; then
  [ -z `which isoinfo` ] && { error 'binary not found: isoinfo'; exit 1; }
  LABEL=`isoinfo -d -i $DRIVE | sed -ne 's/Volume id: //p'`
  [ -z "$LABEL" ] && { echo "could not obtain disc label"; LABEL="NO_LABEL"; }
else
  LABEL="$CATALOG_PATH"
fi

if [ "$CATALOG_PATH" ]; then
  FNAME="${CATALOG_PATH#/}"
  FNAME="${FNAME//\//.}"
  CD=`realpath "$CATALOG_PATH"`
  TAGS="$TAGS filesystem"; TAGS=${TAGS# }
fi

# If automount -g is used, the following problems happen if $CD is not
# mounted:
# * df can't determine size of $CD media (CD or DVD?);
# * find doesn't find all the files on media.
# To resolve the problems above, ensure that $CD is mounted.
if [ ! -d "$CD" ]; then
  error "\`$CD': no such directory"
  [ -z "$CATALOG_PATH" ] && \
    echo "Hint: Set 'CD' variable in mkatrc(5) to a valid directory."
  exit 1
fi
cd "$CD" || exit 1

if [ -z "$CATALOG_PATH" ]; then
  FNAME=$LABEL
fi
DEST="$LISTDIR/$FNAME.list"
if [ -z $FORCE_OVERWRITE ]; then
  [ -e "$DEST" ] && \
    { echo >&2 "file or directory already exists: '$DEST'"; exit 1; }
else
  [ ! -f "$DEST" ] && \
    { echo >&2 "not a file already exists: '$DEST'"; exit 1; }
  [ -n "$ADD_ID_TAG" -o -n "$NEXT_ID_TAG" ] && rm "$DEST"
fi

# Automatic ID tag (--add-id-tag) {{{2
# NOTE: this option needs to be here because an ID tag may be contained in a
# file being overwritten. So, the file must be deleted first (above) and only
# then next ID tag is calculated.
if [ -n "$ADD_ID_TAG" -o -n "$NEXT_ID_TAG" ]; then
  LAST_ID=`sed -rn 's/^tags:.*[[:space:]]#([0-9]+)([[:space:]].*|$)/\1/p' "$LISTDIR"/*.list | sort -g --reverse | head -1`
  if [ -n "$LAST_ID" ]; then
    let LAST_ID++
  else
    LAST_ID=1
  fi

  if [ -n "$NEXT_ID_TAG" ]; then
    echo "Next ID tag: $LAST_ID"
    exit
  fi
    
  TAGS="${TAGS:+$TAGS }#$LAST_ID"
fi


{
echo $LABEL
[ "$TAGS" ] && echo "tags: $TAGS"
IFS='
'
for f in `find $CD -mindepth 1 | sort`; do
  rel=`echo "$f" | sed -ne "s!${CD%%/}/!!p"`
  if [ -f "$f" ]; then
    echo -e $rel:`du -h "$f" | awk '{print $1}'`:`md5sum "$f" | awk '{ print $1}'`
  else
    echo $rel
  fi
done
} | tee "$DEST"
