#!/bin/bash
## Time-stamp: <2004-02-10 02:30:47 vk>

# generate filename without directory:
FILENAME=$(basename $0)
CAT=$(which cat)


print_help()
{
##########################################################################
$CAT <<EOF

  $0

  author:      Karl Voit, shellscript@Karl-Voit.at

  version:     v0.1 2004-02-09

  homepage:    http://www.Karl-Voit.at/scripts/

  copyright:   GPL

  usage:       $FILENAME OLDFILE.tex NEWFILE.tex
               $FILENAME --purge

  description: This script generates a LaTeX-document called
               ${TEXOUTFILE} that points out modified words using
               wdiff. ${TEXOUTFILE} is processed with pdflatex and
               displayed with acroread or xpdf (if no problem
               occured). OLDFILE and NEWFILE are not modified through
               this script.

               The markings for new or deleted words can be changed
               via the variable \$MARKING_METHOD in the file $0: the
               LaTeX-package soul, \fbox{}, or changebar.

               When $FILENAME is called with the argument "--purge", all
               temporary files are being deleted.

               Sometimes ${TEXOUTFILE} can not be compiled by
               (pdf)latex without errors. In those cases, you have to
               edit ${TEXOUTFILE} by yourself and look for 
               - wrong nestings (wrong "}"), 
               - encapsulated "\item",
               - duplicated commands (i.e. two "\small{" but only one closing "}"),
               - change markings in the preamble (before "\begin{document}"),
               - or similar
               (depending on the chosen \$WDIFF_PARAMETERS).

               Please email me suggestions for improvements and errors!
               I am still learning how to write good shell-scripts *g*

EOF
##########################################################################
}

## 2do:
##      * include changebar package if not found (\usepackage{changebar})
##      * look at file timestamps in order to spare some decisions (e.g. an infile is newer 
##        than TEXFILE -> generate new without asking)
##      * 
##      * 



########################################################
########################################################
########################################################
##                                                    ##
##                  PERSONALISATION                   ##
##                                                    ##
########################################################
########################################################
########################################################


## marking differences using:  (my personal favorite so far)
## ,----
## | soul
## `----
## deleted words: overstriked
## new words: underlined
## prerequisite: \usepackage{soul}
## advantage: smooth outline
## disadvantage: 
## URL: -
MARKING_METHOD=soul


## marking differences using:
## ,----
## | \fbox{}
## `----
## deleted words: two boxes
## new words: one box
## prerequisite: none
## advantage: works without additional packages, striking outline
## disadvantage: can harm layout (newlines, itemize, ...)
## URL: http://cclib.nsu.ru/projects/gnudocs/gnudocs/wdiff/wdiff_3.html#SEC3
#MARKING_METHOD=fbox


## marking differences using: 
## ,----
## | changebar.sty
## `----
## deleted words: included, marked with gray bar on side
## new words: included, marked with gray bar on side
## prerequisite: \usepackage[dvips]{changebar}
## advantage: ment for this purpose
## disadvantage: no pdflatex-support, no striking outline
## URL: http://xpt.sourceforge.net/techdocs/Latex/Packages/Latex22.000.html
## URL: http://www.ifi.unizh.ch/cl/manuals/revlatex.html
#MARKING_METHOD=changebar


## The name of the file generated by this script (with no file extension like ".tex")
OUTFILE=ladiff


# change to "done", if you changed all options above to _your_ needs!
CONFIGURED_="done"


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




# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #

# --- normally you DON'T have to change anything below this line! --- #

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #




########################################################
########################################################
########################################################
##                                                    ##
##               hardcoded configuration              ##
##                                                    ##
########################################################
########################################################
########################################################

PDFLATEX_PARAMETERS="--interaction=batchmode"

TEXOUTFILE=DO_NOT_MODIFY_-_generated_automatically.
PDFOUTFILE=DO_NOT_MODIFY_-_generated_automatically.


# change to "on" if you want to read the debug-messages (can be much) to trace
# down problems:
export DEBUG="off"


########################################################
########################################################
########################################################
##                                                    ##
##                   F U N C T I O N S                ##
##                                                    ##
########################################################
########################################################
########################################################

## ---------------------------------------------------------

myexit()
{
    doreport debug "function myexit($1) called"

    [ "$1" -lt 1 ] && echo "$FILENAME done."
    [ "$1" -gt 0 ] && echo "$FILENAME aborted with errorcode $1."

#optionally    [ "$1" -gt 0 ] && do_sound_error

    exit $1
}


## ---------------------------------------------------------

## par1: ERRORNUMBER
## par2-9: message for stdout
myexit_with_message()
{
    doreport debug "function myexit_with_message([${1}],[${2}],[${3}],[${4}],[${5}],[${6}],[${7}],[${8}],[${9}]) called"
    ERRORNUMBER=${1}

    doreport error "${2}" "${3}" "${4}" "${5}" "${6}" "${7}" "${8}" "${9}"
    myexit ${ERRORNUMBER}
}

## ---------------------------------------------------------


## check, if some files needed are not found
testiffound()
{
    doreport debug "function testiffound($1) called"

  if [ -z "$2" ]; then
    doreport debug "The tool \"$1\" is missing because \"$2\" is empty."
    doreport notify "The tool \"$1\" could not be located (missing?)"
    export SOMETHINGMISSING="yes"
  fi
}



## ---------------------------------------------------------

report()
{
## reports the parameter to the stdout

  echo
  echo "==============================================================="
  echo "                                                 $FILENAME"
  echo "$1"
  echo
  echo "==============================================================="
  echo

}



## ---------------------------------------------------------

debugthis()
{
## debugs the script
        #echo $FILENAME: DEBUG: $1
        echo "do nothing" >/dev/null
}



## ---------------------------------------------------------

logthis()
{
## logs some text with a timestamp added
## usage: logthis "mytext"

    ## generates a timestamp like "2002_Jan_31_-_09h43m03s"
    TIMESTAMPLONG=`/bin/date +%Y_%b_%d_-_%Hh%Mm%Ss`

    ## generates a syslog-like timestamp like "Mar 16 09:19:50"
    TIMESTAMPSHORT=`/bin/date +"%b %d %H:%M:%S"`

    ## add computername and scriptname like "lisa qmail: "
    LOGTIMESTAMP=$TIMESTAMPSHORT" lisa $FILENAME:"


    # probably won't annoy logfiles with this crap?
    #        echo $LOGTIMESTAMP "$1" >> $mylogfile
    #        echo $LOGTIMESTAMP "$1" 
        echo "do nothing" >/dev/null
}



## ---------------------------------------------------------

mailthis()
{
        # usage: $1=To $2=Subject $3=Body

        echo -e "$3" | mail -s "$2" $1
}



## ---------------------------------------------------------


doreport_internal_writestring()
{
## !! for use withing function "doreport" only !!
## prints out all strings on stdout

## 2do: error-msg written with { echo 1>&2 "text" } (stderr)

        echo
        echo "===$1============================================"
        echo "                                                 $FILENAME"


## FIXXME:
## 2DO: loop instead of this quick-hack!!!

        if [ ! -z "$2" ]; then
	    echo "$2"
        fi
        if [ ! -z "$3" ]; then
	    echo "$3"
        fi
        if [ ! -z "$4" ]; then
	    echo "$4"
        fi
        if [ ! -z "$5" ]; then
	    echo "$5"
        fi
        if [ ! -z "$6" ]; then
	    echo "$6"
        fi
        if [ ! -z "$7" ]; then
	    echo "$7"
        fi
        if [ ! -z "$8" ]; then
	    echo "$8"
        fi

        echo
        echo "===============================================================";
        echo

}



## ---------------------------------------------------------


doreport()
{
## reports the parameter to the stdout

## usage: (shortnote|notify|error|debug) string1 [string2] [string3] [...] [string7]

## NEEDS: doreport_internal_writestring


    case "$1" in

    "shortnote") 
	echo "$FILENAME: $2 $3 $4 $5 $6 $7";;

    "notify") 
	doreport_internal_writestring " notification ==" "$2" "$3" "$4" "$5" "$6" "$7";;

    "error") 
        doreport_internal_writestring " ERROR =========" "$2" "$3" "$4" "$5" "$6" "$7";;

    "debug") 
        ## debugs the script
        if [[ "$DEBUG" = "on" ]]; then echo "$TIMESTAMP $FILENAME: DEBUG: $2 $3 $4 $5 $6 $7"; fi;
        echo "do nothing" >/dev/null;;

    "log") 
        ## logs some text with a timestamp added
        ## usage: $2 == "mytext"
      
        ## generates a timestamp like "2002_Jan_31_-_09h43m03s"
        TEMP_TIMESTAMPLONG=`/bin/date +%Y_%b_%d_-_%Hh%Mm%Ss`;
        ## generates a syslog-like timestamp like "Mar 16 09:19:50"
        TEMP_TIMESTAMPSHORT=`/bin/date +"%b %d %H:%M:%S"`;
        ## add computername and scriptname like "lisa qmail: "
        TEMP_LOGTIMESTAMP=$TEMP_TIMESTAMPSHORT" lisa $FILENAME:";

        # probably won't annoy logfiles with this crap?
        #        echo $LOGTIMESTAMP "$2" >> $mylogfile;
        #        echo $LOGTIMESTAMP "$2" ;;
        echo "do nothing" >/dev/null;;

    "mail") 
        # usage: $2=To $3=Subject $4=Body
        echo -e "$4" | mail -s "$3" $2;;

    *)
        doreport_internal_writestring " INTERNAL ERROR "\
	    "An error occured, while calling function \"doreport\":"\
	    "The parameter that was given ($1) has no target/handle." "Aborting.";
        myexit 1;;

    esac
}




## ---------------------------------------------------------

ask()
{
## asks something (parameter 1) the user

  echo
  echo "=== question =================================================="
  echo "                                                 $FILENAME"
  echo "$1"
  [ -n "${2}" ] && echo "$2"
  [ -n "${3}" ] && echo "$3"
  [ -n "${4}" ] && echo "$4"
  [ -n "${5}" ] && echo "$5"
  [ -n "${6}" ] && echo "$6"
  [ -n "${7}" ] && echo "$7"
  [ -n "${8}" ] && echo "$8"
  [ -n "${9}" ] && echo "$9"
  echo
  echo "==============================================================="
  echo

}


## ---------------------------------------------------------

precondition_asserts()
{
## * test for things that are needed
## * check, if caller = root-user
## * check, if everything was configured by the user
## * check, if a parameter is given:

      export SOMETHINGMISSING="no"


      WDIFF=$(which wdiff)
      testiffound wdiff $WDIFF
      
      GREP=$(which grep)
      testiffound grep $GREP
      
      EGREP=$(which egrep)
      testiffound egrep $EGREP
      
      PDFLATEX=$(which pdflatex)
      testiffound pdflatex $PDFLATEX
      
      WC=$(which wc)
      testiffound wc $WC
      
      AWK=$(which awk)
      testiffound awk $AWK
      
      SED=$(which sed)
      testiffound sed $SED
      

    ## check, if any tool was NOT found
    doreport debug "CHECK: any tool missing?"
    if [ "$SOMETHINGMISSING" = "yes" ]; then
      print_help
      doreport error "One or more tool(s), that are needed are missing! (See output above!)"\
	  "Please make sure, that you those tools are installed properly and try again." "aborting."
      myexit 2
    fi


    ## check if acroread or xpdf is found
    if [ -n "$(which acroread)" ]; then
	doreport debug "acroread was found. taking it as default pdf-viewer."
	PDFVIEWER="$(which acroread)"
    elif [ -n "$(which xpdf)" ]; then
	doreport debug "acroread was not found. xdvi was found. taking xdvi it as default pdf-viewer."
        PDFVIEWER="$(which xpdf)"
    else
	doreport notify "Could not find acroread nor xpdf to show the resulting PDF-file."\
	    "Continuing without starting any PDF-viewer."
	PDFVIEWER=none
    fi
	

      ## check, if everything was configured by the user
      if [ ! "$CONFIGURED_" = "done" ]; then
        print_help
	doreport "error" "Please make sure, that you checked/modified all options"\
	    "to meet your requirements!" "(see section "PERSONALISATION" in file $0)"
        myexit 3
      fi
      


      ## check, if a parameter is given:
      if [ -z "$1" ]; then
        print_help
        doreport "error" "no parameter 1 for OLDFILE found!" "aborting."
        exit 1
      else
        doreport debug "parameter 1 was found."
        OLDFILE="$1"
      fi


      ## check, if a parameter is given:
      if [ -z "$2" ]; then
        print_help
        doreport "error" "no parameter 2 for NEWFILE found!" "aborting."
        exit 1
      else
        doreport debug "parameter 2 was found."
        NEWFILE="$2"
      fi


      ## checks par1 for containing the LaTeX-package soul and asking for adding it
      ## par1: filename
      check_file_for_soul()
      {
          CURRENTFILE=${1}
	  doreport debug "check_file_for_soul($1) called."

          if ${GREP} -Eq '\usepackage([.*])?{soul}' "${CURRENTFILE}"; then

	      doreport debug "LaTeX-package soul seems to be included in file ${CURRENTFILE}"

	  else

	      doreport debug "LaTeX-package soul does not seem to be included in file ${CURRENTFILE}"
	      ask "The file" "  ${CURRENTFILE}"\
		  "does not contain a package declaration for package \"soul\"."\
		  "Please add \"\\usepackage{soul}\" in order to get a correct result."\
		  " "\
		  "Do you want me to add this declaration just before the"\
		  "line \"\\begin{document}\"? (y/n)"
	      echo
	      read ANSWER
	      echo
	      case "${ANSWER}" in
		  
		  "y"|"Y"|"j"|"J")
		      doreport shortnote "Modifying ${CURRENTFILE}...";
		      ${SED} 's/\\begin{document}/\\usepackage{soul}  %% added by ladiff.sh\n\n\\begin{document}/'\
			  ${CURRENTFILE} >${CURRENTFILE}_WITH_SOUL;
		      [ $? -ne 0 ] && myexit_with_message 10 "File modification of ${CURRENTFILE} failed. Aborting.";
		      mv ${CURRENTFILE}_WITH_SOUL ${CURRENTFILE};;
		  *)
		      doreport shortnote "Continuing without modifying ${CURRENTFILE}";;
	      esac

	  fi
      }


      case "${MARKING_METHOD}" in

	  "fbox")
	      WDIFF_PARAMETERS="-w \fbox{ -x } -y \fbox{\fbox{ -z }}";;

	  "soul")
	      ## ask for packet inclusion, if not found:
	      check_file_for_soul ${OLDFILE};
	      check_file_for_soul ${NEWFILE};
	      WDIFF_PARAMETERS="-w \st{ -x } -y \ul{ -z }";;

	  "changebar")
	      WDIFF_PARAMETERS="-w \cbstart{} -x \cbend{} -y \cbdelete{ -z }";;

	  *) myexit_with_message 4 "\${MARKING_METHOD} is unknown (${MARKING_METHOD})." "Please check $0!";;

      esac


    doreport debug "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< all checks OK!"
    export PRECONDITIONS_CHECKED="yes"


}



## ---------------------------------------------------------

postcondition_asserts()
{

    echo "donothing" >/dev/null

    if [ -f ${PDFOUTFILE} -o -f ${TEXOUTFILE} ]; then
	ask "Temporary generated files were found." "Do you want to"\
	    "  (k)eep or"\
	    "  (d)elete them?"
	read ANSWER
	echo
	case "${ANSWER}" in
	    
	    "d"|"D")
		doreport debug "temporary files should be deleted...";
		purge_all_temporary_files;;
	    *)
		doreport shortnote "temporary files will be kept.";
		doreport shortnote "(you can delete them using \"${FILENAME} --purge\")";;
	esac
    else
	doreport debug "no ${PDFOUTFILE} or ${TEXOUTFILE} was found to be cleaned up."
    fi

}



########################################################
########################################################
########################################################
##                                                    ##
##                S C R I P T                         ##
##                                                    ##
########################################################
########################################################
########################################################

## ---------------------------------------------------------

generate_new_outfile()
{
    doreport debug "generate_new_outfile() called"

    doreport shortnote "generating wdiff-file..."
    "${WDIFF}" ${WDIFF_PARAMETERS} "${OLDFILE}" "${NEWFILE}" >"${TEXOUTFILE}"
    [ $? -eq 2 ] && myexit_with_message 5 "wdiff failed. Please check you parameters and try again."
}

## ---------------------------------------------------------

compile_outfile()
{
    doreport debug "compile_outfile() called"

    doreport shortnote "invoking pdflatex... (please wait)"
    "${PDFLATEX}" "${PDFLATEX_PARAMETERS}" "${TEXOUTFILE}" 2>&1 >/dev/null
    [ $? -ne 0 ] && myexit_with_message 6 "pdflatex failed. Please check ${TEXOUTFILE} manually and"\
	"compile (using pdflatex) by hand."
}

## ---------------------------------------------------------

view_outfile()
{
    doreport debug "view_outfile() called"

    if [ "${PDFVIEWER}" != "none" ]; then
	doreport shortnote "viewing pdf-file..."
	"${PDFVIEWER}" `echo ${TEXOUTFILE} | ${SED} 's/\.tex/\.pdf/g'`
	[ $? -ne 0 ] && myexit_with_message 7 "an error accured when trying to view the PDF-file."
    else
	doreport shortnote "No PDF-viewer could be found. Skipping 'view PDF-file'."
    fi
}


## ---------------------------------------------------------

purge_all_temporary_files()
{
    doreport debug "purge_all_temporary_files() called."

    for CURRENTFILE in ${OUTFILE}.*; do
	doreport shortnote "deleting file ${CURRENTFILE}"
	[ ${CURRENTFILE} != ${FILENAME} ] && rm "${CURRENTFILE}"
    done;
}


## ---------------------------------------------------------


## generate PDFOUTFILE out of OUTFILE
PDFOUTFILE="${OUTFILE}.pdf"

## generate TEXOUTFILE out of OUTFILE
TEXOUTFILE="${OUTFILE}.tex"


## parse parameter 1
case "$1" in

    "help"|"--help"|"?"|"/?")
	doreport debug "Parameter help|--help|?|/? detected";
	print_help;
	myexit 0;;
    "clean"|"purge"|"--clean"|"--purge")
	doreport debug "Parameter clean|purge|--clean|--purge detected";
	purge_all_temporary_files;
	myexit 0;;

esac


## test for important stuff:
precondition_asserts "$1" "$2" "$3" "$4" "$4" "$5" "$6" "$7" "$8" "$9"



## check, if ${PDFOUTFILE} exists and if so, ask for deletion or viewing
## (delete without asking if size==0)
if [ -f ${PDFOUTFILE} ]; then

    if [ `${WC} -l ${PDFOUTFILE} | ${AWK} '{print $1}'` -eq 0 ]; then
	doreport debug "${PDFOUTFILE} is zero length. Deleting without asking."
	rm ${PDFOUTFILE}
    else
	
	ask "An old ${PDFOUTFILE} was found." "Do you want to"\
	    "  (q)uit,"\
	    "  (d)elete (and generate new) or"\
	    "  (v)iew ${PDFOUTFILE}?"
	read ANSWER
	echo
	case "${ANSWER}" in
	    
	    "d"|"D")
		rm ${PDFOUTFILE} ;
		doreport shortnote "${PDFOUTFILE} deleted.";; ## and continue below
	    "v"|"V")
		view_outfile ;
		exit 0;; ## exit on return here (without error)
	    "q"|"Q"|"a"|"A")
		doreport shortnote "Aborting as requested.";
		exit 0;; ## exit on return here (without error)
	    *)
		echo "  ERROR. You did not choose (q), (d) or (v)." ;
		echo "  Aborting execution of ${FILENAME}." ;
		echo ;
		exit 1;;
	esac
    fi
fi


## check, if ${TEXOUTFILE} exists and if so, ask for deletion or compiling
## (delete without asking if size==0)
if [ -f ${TEXOUTFILE} ]; then

    if [ `${WC} -l ${TEXOUTFILE} | ${AWK} '{print $1}'` -eq 0 ]; then
	doreport debug "${TEXOUTFILE} is zero length. Deleting without asking."
	rm ${TEXOUTFILE}
    else
	
	ask "An old ${TEXOUTFILE} was found. Do you want to:"\
	    "  (q)uit,"\
	    "  (c)ompile or"\
	    "  (d)elete (and generate new) ${TEXOUTFILE}?"
	read ANSWER
	echo
	case "${ANSWER}" in
	    
	    "d"|"D")
		rm ${TEXOUTFILE} ;
		doreport shortnote "${TEXOUTFILE} deleted.";
		generate_new_outfile;
		compile_outfile;
		view_outfile;;
	    "c"|"C")
		compile_outfile;
		view_outfile;;
	    "q"|"Q"|"a"|"A")
		doreport shortnote "Aborting as requested.";
		exit 0;; ## exit on return here (without error)
	    *)
		echo "  ERROR. You did not choose (q), (c) or (d)." ;
		echo "  Aborting execution of ${FILENAME}." ;
		echo ;
		exit 1;;
	esac
    fi
else ## no TEXOUTFILE was found, generate new
    generate_new_outfile
    compile_outfile
    view_outfile
fi

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


## test for important stuff:
postcondition_asserts

myexit 0


########################################################
##                      E N D                         ##
########################################################

