#!/bin/sh

paths=.
verbose=0
keep=0
validate_schema=0
check_tools=0

_usage () {
  echo "Usage: $0 [-s|--schema] [-d|--pml-dir pml_tools_dir] [-p|--path path1:path2:...] [-v|--verbose] [-k|--keep] [ --check-tools | pml_file(s) ]"
  echo "or"
  echo "       $0 --help   (for help)"
}
usage () {
  _usage
  exit 127
}
help () {
    usage;
    cat <<EOF
  -d|--pml-dir     - a directory with PML tools (pml2rng.xsl,pml_common.rng)
  -p|--path        - directories with PML schemas
  -s|--schema      - validate a PML schema (rather than an instance)
  -k|--keep        - keep a temporary directory with partial results
  -r|--rng-tool    - path to RNG validator (jing, relames, ...)
  -v|--verbose     - tell me what's happening
  -c|--check-tools - test if RNG validator and pml_simplify are present and exit

For each PML instance on the command line, this script determines its
PML schema, converts it to RelaxNG and validates the instance against
the resulting RelaxNG schema via Sun's Multi-Schema Validator (msv) or
J.Clark's Jing (jing).

If the flag -s is used, the script takes PML schemas rather than
instances and validates them against pml_schema.rng.

EOF
}

OPTS=`getopt -o shvkd:p:r:c --long help,verbose,keep,path:,rng-tool:,pml-dir:,check-tools -- "$@"`
if [ $? != 0 ] ; then usage ; fi
eval set -- "$OPTS"
while true ; do
        case "$1" in
                -v|--verbose) verbose=1 ; shift ;;
                -k|--keep)    keep=1 ; shift ;;
                -s|--schema)  validate_schema=1 ; shift ;;
                -p|--path)   paths=$2 ; shift 2 ;;
                -d|--pml-dir)   share=$2 ; shift 2 ;;
                -r|--rng-tool)   validator=$2 ; shift 2 ;;
                -c|--check-tools)   check_tools=1 ; shift ;;
                -h|--help)   help ; shift 1 ;;
                --) shift ; break ;;
                *) echo "internal error: unparsed argument $1" >&2; exit 1;;
        esac
done


get_schema () {
  file="$1"
  schema=`perl -MXML::LibXML::Reader -e '
  my $r=XML::LibXML::Reader->new(location=>shift) || die "$!";
  $r->nextElement("schema"); 
  print $r->getAttribute("href"),"\n"' "$file"`
  if [ -z "$schema" ]; then
      schema="$file"
  elif [ "$(basename $schema)" = "$schema" ]; then
      for p in $(dirname "$file") ${paths//:/ }; do
	  if [ -f "$p/$schema" ]; then
	      schema="$p/$schema";
	      break;
	  fi
      done
  fi
  echo "$schema" 2>&1
}

msg () {
    if [ "$verbose" = 1 ]; then
	echo "$@"
    fi
}

cleanup () {
    if [ $keep =  1 ]; then
	echo "Temporary files kept in: $temp"
    elif [ -n "$temp" ] && [ -d "$temp" ]; then
	msg "Removing temporary files"
	rm -rf "$temp"
    fi
}
fail () {
    echo "ERROR $2";
    cleanup
    exit $1;
}

if [ $check_tools = 0 ] && [ $# = 0 ]; then
  usage;
fi

msg -n "Looking up pml_simplify: "
pml_simplify=`which pml_simplify 2>/dev/null`
if [ -z "$pml_simplify" ]; then 
    if [ -x "$share/pml_simplify" ]; then
	pml_simplify=$share/pml_simplify
    else
	fail 120 "Utility pml_simplify not found!"
    fi 
fi
msg $pml_simplify

msg -n "Looking up MSV (Sun's Multi-Schema Validator): "
if [ -n "$validator" ]; then
    if ! [ -x "$validator" ]; then
	validator=`which "$validator" 2>/dev/null`
    fi
    if [ -z "$validator" ] || ! [ -x "$validator" ]; then
	echo "Didn't find validator $validator!"
	exit 1
    fi
fi
if [ -z "$validator" ] || ! [ -x "$validator" ]; then
    validator=`which msv 2>/dev/null`
	if [ -z "$validator" ] || ! [ -x "$validator" ]; then
	    msg "Tool 'msv' not found, will try Jing"
	    msg -n "Looking up Relames: "
	    validator=`which relames 2>/dev/null`
	    if [ -z "$validator" ] || ! [ -x "$validator" ]; then
		msg "Tool 'relames' not found, will try Jing"
		msg -n "Looking up Jing: "
		validator=`which jing 2>/dev/null`
		if [ -z "$validator" ] || ! [ -x "$validator" ]; then
		    fail 120 "Tool 'jing' not found!"
		fi
	    fi
	fi
fi
msg "$validator"

if [ $check_tools = 1 ]; then
    [ $# = 0 ] || usage;
    echo "Tools OK"
    exit 0
fi

i=0;total=$#;
while [ $# -gt 0 ]; do
    file="$1"; shift
    msg "Instance: $file ($((++i))/$total)"

    if [ -z "$share" ]; then
	prog=`readlink -f "$0"`
	progdir=`dirname "$prog"`
	if [ -f "$progdir/../share/pml/pml2rng.xsl" ]; then
	    share="$progdir/../share/pml"
	else
	    share="$progdir"
	fi
	msg "Share: $share"
    fi

    temp=`mktemp -d` || fail 126 "Cannot create a temporary directory!"

    if [ "${file}" = "-" ]; then
	msg "Creating temporary copy of STDIN"
	cat "$file" > "$temp/data.pml" || fail 123 "Copying failed" 
	file="$temp/data.pml";
    fi

    if [ $validate_schema = 1 ]; then
	schema="$file"
    else
	schema=`get_schema "$file"`
    fi
    msg "Schema: $schema"

    msg "Simplifying schema"
    "$pml_simplify" --path "$paths" "$schema" > "$temp/simple_schema.xml" || fail 125 "Schema simplification failed"
    if [ $validate_schema = 1 ]; then
	msg "Validating schema using $validator and RNG '$share/pml_schema.rng'" 2>&1 
	"$validator" "$share/pml_schema.rng" "$temp/simple_schema.xml"    
    else
	msg "Transforming to Relax NG"
	xsltproc --param standalone 1 "$share/pml2rng.xsl" "$temp/simple_schema.xml" > "$temp/schema.rng" \
	    || fail 124 "XSLT transformation failed"
	if [ "${file%.gz}" != "${file}" ]; then
	    msg "Ungzipping the instance to a temporary directory"
	    zcat < "$file" > "$temp/data.pml" || fail 123 "Gunzip failed" 
	    file="$temp/data.pml";
	fi 
	msg "Validating instance using $validator" 2>&1 
	cp "$share/pml_schema.rng" "$share/pml_schema_1_1.rng" "$share/pml_schema_1_2.rng" "$temp/"
	"$validator" "$temp/schema.rng" "$file"
    fi
    exit=$?
    if [ $exit = 0 ]; then
	msg "Result: valid"
    else
	msg "Result: not valid"
    fi
    cleanup
    if [ $exit != 0 ]; then
	exit $exit
    fi
done

exit 0

