#!/bin/ksh
set +xv
#begin
#
# odbdiff -c                # Enforce recompilations
#         -v sqlfile        # SQL-file (with or w/o prefix .sql) or a table, if starts with '@'
#                             If SQL-file, an editor will be opened (unless -e pipe or -e batch)
#         -e editor_name    # Preferred editor name (use pipe or batch, if no editor)
#                             As in odbviewer, the default being $ODB_EDITOR
#         -q 'query_string' # Data query itself : no editor will be opened
#         -n maxdiffs       # Max. number of diffs allowed before bailing out (default=2147483647)
#         -g                # Do *NOT* generate diff.database REFCMP i.e.
#                             input files for simulobs2odb & create database REFCMP & run odbviewer
#         -C _color         # Name of the "color" column for diff database (default=_color)
#         -l label          # Label for this job to separate multiple diff DBs (default=default)
#         -1                # Enforce (lat,lon)-conversion to degrees for reference database (DB#1)
#         -2                # Enforce (lat,lon)-conversion to degrees for comparison database (DB#2)
#         -b nbits          # How many last bits to ignore after (lat,lon)-conversion (default=0 i.e. none)
#         -p poolmask       # List of pools to search. Can appear multiple times. As in odbviewer
#         -s                # Right-adjust string-datatype before comparison (by default NOT adjusted)
#         -R                # Do NOT convert (lat,lon) into degrees in odbviewer
#         -r                # Convert (lat,lon) into degrees in odbviewer only in the plot, but not in textual report
#         -k                # Convert (lat,lon) into degrees in odbviewer for both plot & report (the default)
#         -m                # Use less memory by reading reference database pool-by-pool (default uses more memory)
#         -i                # Latitude band increment (default=180)
#         reference_database_dir compare_database_dir
#
# Author: Sami Saarinen, ECMWF, 27-Jun-2005 .. 11-Jul-2005
#
#end
#
#

set -eu

cmd=$(\cd $(dirname $0); echo $(pwd))/$(basename $0)

thisdir=$(pwd)
cd $thisdir
export WDIR=${WDIR:=$thisdir}

maxdiffs=2147483647
recomp=0
query=""
query_given=0
defview=myview
viewname=$defview
hassql=1
simulobs=1
color="_color"
label=default
rad2deg_1=0
rad2deg_2=0
rad2deg_flag="-k" # for odbviewer : convert (lat,lon) radians to degrees in plot & textual report
nbits=0
poolmask=""
adjustr=0
editor=${ODB_EDITOR:=emacs}
memopt=0
rlatinc=180
rlatinc_given=0

abort=no
FLAGS=b:cC:e:gi:kl:mn:p:q:Rrsv:12

abort=no
while getopts ${FLAGS} i
do
  case $i in
  b)	nbits="$OPTARG";;
  c)	recomp=1;;
  C)	color="$OPTARG";;
  e)	editor="$OPTARG";;
  g)	simulobs=0;;
  i)	rlatinc="$OPTARG" ; rlatinc_given=1;;
  k)	rad2deg_flag="-k" ;;
  l)	label="$OPTARG";;
  m)	memopt=1;;
  n)	maxdiffs="$OPTARG";;
  p)	poolmask="$poolmask $OPTARG";;
  q)	query_given=1; query="$OPTARG";;
  r)	rad2deg_flag="-r" ;;
  R)	rad2deg_flag="-R" ;;
  s)	adjustr=1;;
  v)	viewname="$OPTARG";;
  1)	rad2deg_1=1 ; rad2deg_flag="-R" ;; # -R for odbviewer : (lat,lon) assumed in degrees at REFCMP-database
  2)	rad2deg_2=1 ; rad2deg_flag="-R" ;; # -R for odbviewer : (lat,lon) assumed in degrees at REFCMP-database
  \?)   abort=yes; break;;
  esac
done

shift $(expr $OPTIND - 1)

if [[ $# -ne 2 || "$abort" = "yes" ]] ; then
  awk '/#begin/,/#end/' $cmd | egrep -v '#(begin|end)' | sed 's/^#//'
  exit 1
fi

refpath=$1
cmppath=$2

is_table=$(echo "$viewname" | perl -ne 'if (m/^\@/) {print 1;} else {print 0;}')

if [[ $is_table -eq 1 && $query_given -eq 0 ]] ; then
  hassql=0
  sqlfile=/dev/null
elif [[ $query_given -eq 1 ]] ; then
  viewname=$(echo "$viewname" | perl -pe 's/\..*//')
  sqlfile=$viewname.sql
  echo "$query" > $sqlfile
elif [[ -f $viewname ]] ; then
  sqlfile=$viewname
  query_given=2
else
  sqlfile=$viewname
  suffix=$(echo "$viewname" | perl -ne 'print $1 if (/.*(\.\w+)/);')
  if [[ "$suffix" = ".so" && $recomp -eq 0 && $rlatinc_given -eq 0 ]] ; then
    hassql=0
    query_given=1
  else
    query_given=2
  fi
  viewname=$(echo "$viewname" | perl -pe 's/\..*//')
  sqlfile=$viewname.sql
fi

sqldir=$(dirname $sqlfile)
sqlfile=$(basename $sqlfile)
sqldir=$(\cd $sqldir >/dev/null 2>&1 ; pwd)

if [[ $query_given -eq 2 ]] ; then
  if [[ "$editor" != pipe && "$editor" != batch ]] ; then
    $editor $sqldir/$sqlfile &
  fi
fi

refpath=$(\cd $refpath >/dev/null 2>&1 ; pwd)
cmppath=$(\cd $cmppath >/dev/null 2>&1 ; pwd)

REF=$thisdir/REF.$label
CMP=$thisdir/CMP.$label
REFCMP=REFCMP.$label

cd $thisdir
out=out$$

if [[ $recomp -eq 1 ]] || \
   [[ ! -d $REF ]] || [[ ! -d $CMP ]] ; then # Recompile layout AND SQL
  cd $thisdir
  odbdup -i $refpath -o $REF -l REF -F -D
  cd $REF
  if [[ ! -d dca ]] ; then
    dcagen -F -n -z >$thisdir/1.$out 2>&1 &
  fi
  newodb -z REF >$thisdir/2.$out 2>&1 &

  cd $thisdir
  odbdup -i $cmppath -o $CMP -l CMP -F -D
  cd $CMP
  if [[ ! -d dca ]] ; then
    dcagen -F -n -z >$thisdir/3.$out 2>&1 &
  fi
  newodb -z CMP >$thisdir/4.$out 2>&1 &
  echo "*** Waiting for subprocesses to finish ..."
  wait
  for n in 1 2 3 4
  do
    if [[ -f $thisdir/$n.$out ]] ; then
      cat $thisdir/$n.$out
      rm -f $thisdir/$n.$out
    fi
  done
fi

wait

if [[ $hassql -eq 1 ]] ; then # Recompile SQL
  if [[ $rlatinc_given -eq 1 ]] ; then
    where_fiddle=1
    egrep -i '(lat|hdr)' $sqldir/$sqlfile >/dev/null 2>&1 || where_fiddle=0
  else
    where_fiddle=0
  fi

  cd $REF
  if [[ $where_fiddle -eq 1 ]] ; then
    if [[ $rad2deg_1 -eq 1 ]] ; then # Latitude already assumed in degrees
       env ODB_WHERE_FIDDLE='$lat1 < lat <= $lat2' \
           perl -w $ODB_BINPATH/where_fiddle.pl < $sqldir/$sqlfile > $sqlfile
    else
       env ODB_WHERE_FIDDLE='$lat1 < degrees(lat) <= $lat2' \
           perl -w $ODB_BINPATH/where_fiddle.pl < $sqldir/$sqlfile > $sqlfile
    fi
  else
    cat < $sqldir/$sqlfile > $sqlfile
  fi
  echo "*** The following SQL is in concern (database=REF at $(pwd)):"
  cat $sqlfile
  echo " "
  odbcomp -z -lREF $sqlfile

  cd $CMP
  if [[ $where_fiddle -eq 1 ]] ; then
    if [[ $rad2deg_2 -eq 1 ]] ; then # Latitude already assumed in degrees
       env ODB_WHERE_FIDDLE='$lat1 < lat <= $lat2' \
           perl -w $ODB_BINPATH/where_fiddle.pl < $sqldir/$sqlfile > $sqlfile
    else
       env ODB_WHERE_FIDDLE='$lat1 < degrees(lat) <= $lat2' \
           perl -w $ODB_BINPATH/where_fiddle.pl < $sqldir/$sqlfile > $sqlfile
    fi
  else
    cat < $sqldir/$sqlfile > $sqlfile
  fi
  echo "*** The following SQL is in concern (database=CMP at $(pwd)):"
  cat $sqlfile
  echo " "
  odbcomp -z -lCMP $sqlfile
else
  echo "*** The following TABLE is in concern: $viewname"
fi

cd $thisdir
create_odbglue REF CMP

export ODB_DATAPATH_REF=$REF
export ODB_SRCPATH_REF=$ODB_DATAPATH_REF
export ODB_DATAPATH_CMP=$CMP
export ODB_SRCPATH_CMP=$ODB_DATAPATH_CMP

export IOASSIGN=$thisdir/IOASSIGN_$label
cat $ODB_SRCPATH_REF/REF.IOASSIGN $ODB_SRCPATH_CMP/CMP.IOASSIGN > $IOASSIGN

export ODB_READONLY=1
export ODB_IO_METHOD=5

obj=$($ODB_AR t $ODB_LIBPATH/libodbmain.a | grep Odbdiff)
$ODB_AR x $ODB_LIBPATH/libodbmain.a $obj

odbf90 $obj -o odbdiff.x -L$ODB_DATAPATH_REF -lREF -L$ODB_DATAPATH_CMP -lCMP

if [[ $simulobs -eq 1 ]] ; then
  simulobs_file2="only_in_cmp.txt.$label"
  simulobs_file1="only_in_ref.txt.$label"
  cat > $simulobs_file1 <<'EOF'
#refcmp
#/poolno=1
#/end
# These data rows were only found from REFERENCE database and/or are different from COMPARISON database
EOF
  cat > $simulobs_file2 <<'EOF'
#refcmp
#/poolno=2
#/end
# These data rows were only found from COMPARISON database and/or are different from REFERENCE database
EOF
else
  simulobs_file1="/dev/null"
  simulobs_file2="/dev/null"
fi

if [[ $hassql -eq 1 ]] ; then
  view=$(echo "$sqlfile" | perl -pe 's/\..*//')
else
  view=$viewname
fi

#-- Poolmask
if [[ "$poolmask" != "" ]] ; then
  poolmask=$(echo $poolmask | perl -pe 's/^\s+//; s/\s+$//; s/\s+/,/g')
  export ODB_PERMANENT_POOLMASK_REF="$poolmask"
  export ODB_PERMANENT_POOLMASK_CMP="$poolmask"
  echo "==> Scanning only pools : $poolmask"
fi

#-- Remove gprof output (if any)
rm -f gmon.out*

./odbdiff.x CMP REF $view $maxdiffs $simulobs_file1 $color 1 $rad2deg_2 $rad2deg_1 $nbits $adjustr $memopt $rlatinc
if [[ -f gmon.out ]] ; then
  mv gmon.out gmon.out.CMPvsREF
fi
./odbdiff.x REF CMP $view $maxdiffs $simulobs_file2 $color 2 $rad2deg_1 $rad2deg_2 $nbits $adjustr $memopt $rlatinc
if [[ -f gmon.out ]] ; then
  mv gmon.out gmon.out.REFvsCMP
fi

#-- Disable gprof'fing (if it was on)
export ODB_GPROF=""

if [[ $simulobs -eq 1 ]] ; then
  # Pool#1 contains REF vs. CMP database diffs
  # Pool#2 contains CMP vs. REF database diffs
  # "color" is set to 1 in pool#1 and 2 in pool#2
  ndiffs1=$(tail -1 $simulobs_file1 | awk '{print $NF}')
  ndiffs2=$(tail -1 $simulobs_file2 | awk '{print $NF}')
  if [[ $ndiffs1 -gt 0 ]] || [[ $ndiffs2 -gt 0 ]] ; then
    export ODB_IO_METHOD=1 # Better than 4 in case of low memory system, and since cannot be 5
    cd $thisdir
    simulobs2odb -l $REFCMP -i $simulobs_file1 -i $simulobs_file2 -n 2 -c
    montage=$(whence montage 2>/dev/null || echo "")
    xdiff=$(whence xdiff 2>/dev/null || echo "")
    cd $REFCMP
    export ODB_REPORTER="head -10" # Just to avoid opening b4.x-window ;-)
    has_lat=$(grep ' lat_hdr ' REFCMP.sch >/dev/null 2>&1 || echo "no")
    has_lon=$(grep ' lon_hdr ' REFCMP.sch >/dev/null 2>&1 || echo "no")
    if [[ "$has_lat" = no ]] || [[ "$has_lon" = no ]] ; then
      export ODB_PLOTTER=0 # Plotting off; no (lat,lon)-coordinates
    else
      export ODB_VIEWER_LAT="lat_hdr@refcmp"
      export ODB_VIEWER_LON="lon_hdr@refcmp"
      export ODB_VIEWER_TEXT_3="Only in DB = $refpath"
    fi
    odbviewer -F $rad2deg_flag -v data_only_in_ref_db \
              -p 1 -q "select '!/:${color}@/' from refcmp orderby *" -e batch -I < /dev/null
    export ODB_VIEWER_TEXT_3="Only in DB = $cmppath"
    odbviewer -F $rad2deg_flag -v data_only_in_cmp_db \
              -p 2 -q "select '!/:${color}@/' from refcmp orderby *" -e batch -I < /dev/null
    ls -ltr data_only_in_ref_db.rpt data_only_in_ref_db.jpg || :
    ls -ltr data_only_in_cmp_db.rpt data_only_in_cmp_db.jpg || :
    if [[ -x "$montage" && -f data_only_in_ref_db.jpg && -f data_only_in_cmp_db.jpg ]] ; then
      $montage -tile 2x1 -geometry 600x600 data_only_in_ref_db.jpg data_only_in_cmp_db.jpg montage.jpg
      xv montage.jpg &
    fi
    if [[ -x "$xdiff" && -f data_only_in_ref_db.rpt && -f data_only_in_cmp_db.rpt ]] ; then
      $xdiff data_only_in_ref_db.rpt data_only_in_cmp_db.rpt &
    fi
    echo ">>> Databases differ against the given query/table"
    echo ">>> There are $ndiffs1 rows which are ONLY found in reference database ($refpath)"
    echo ">>> There are $ndiffs2 rows which are ONLY found in comparison database ($cmppath)"
    echo ">>> Difference database is found under $thisdir/$REFCMP"
    echo ">>> Data in pool#1 denotes the rows found only in reference database"
    echo ">>> Data in pool#2 denotes the rows found only in comparison database"
  else
    echo ">>> Databases are considered similar against the given query/table"
    rm -rf $REFCMP
  fi
fi

exit 0
