#! /bin/sh
#!perl -w # --*- Perl -*--
eval 'exec perl -x $0 ${1+"$@"}'
    if 0;
#------------------------------------------------------------------------------
#$Author: antanas $
#$Date: 2016-06-20 00:17:04 +0300 (Mon, 20 Jun 2016) $
#$Rev: 4671 $
#$URL: svn://www.crystallography.net/cod-tools/tags/v2.1/data/AtomProperties/bin/compare_properties $
#------------------------------------------------------------------------------
#*
# Compares selected atom property between two yaml format files containing 
# atom infromation.
#*
#* Usage:
#*     $0 file1.yaml file2.yaml
#**

use strict;
use warnings;
use COD::SOptions qw( getOptions );
use COD::SUsage qw( usage );

use YAML qw( Dump Bless Load LoadFile );

my $prop = "atomic_number";
my $cutoff = 0.01;

@ARGV = getOptions(

#** Options:
#**
#** -p,--property
#**                     The compared property. Default "atomic_number".
#** -c,--cutoff
#**                     Cutoff used in numerical comparison.
#** --help,--usage      Print a short usage message (this message) and exit.

    "-p,--property"  => \$prop,
    "-c,--cutoff"    => \$cutoff,
    "--help,--usage" => sub { usage; exit }
);

if ( @ARGV != 2 ) {
    die "$0:: ERROR, the script must be given two files to compare.\n";
};

my @atoms;

for (my $i = 0; $i < 2; $i++ ) {
    local $/ = undef;
    my $atoms_local;

    if ( $ARGV[$i] eq "-" ) {
        my $yaml = do { local $/; <STDIN> };
        $atoms_local = Load($yaml);
    } else {
        $atoms_local = LoadFile($ARGV[$i]);
    }
    $atoms[$i] = $atoms_local;
}

my %atoms1 = %{$atoms[0]};
my %atoms2 = %{$atoms[1]};

my %joint_hash = %{{%atoms1,%atoms2}};
my @elements = (sort {$joint_hash{$a}{atomic_number} <=> 
                      $joint_hash{$b}{atomic_number}} keys %joint_hash);

foreach (@elements) {
    my $value1 = exists $atoms1{$_}{$prop} ? $atoms1{$_}{$prop} : undef;
    my $value2 = exists $atoms2{$_}{$prop} ? $atoms2{$_}{$prop} : undef;

    my $diff_str;
    if ( $prop eq "covalent_radius" || $prop eq "vdw_radius" ) {
        $diff_str = diff_numbers($value1, $value2, "--");
    } elsif ($prop eq "atomic_weight") {
        foreach ($value1, $value2) { $_ =~ s/[\[\]]//g if defined $_} ;
        $diff_str = diff_numbers($value1, $value2, "--");
    } elsif ($prop eq "valence") {
        $diff_str = diff_arrays ($value1, $value2);
    } else {
        $diff_str = diff_strings($value1, $value2, "--");
    }

    print "$_\t$diff_str" if defined $diff_str;
}

sub diff_numbers {
    my ($value1, $value2, $default) = @_;

    my $diff = undef;
    if ( defined $value1 && defined $value2 ) {
        $diff = $value1 - $value2;
        if (abs($diff) > $cutoff) {
            return sprintf "%1.2f\t%1.2f\t%1.4f\n", $value1, $value2, $diff;
        } else {
            return undef;
        }
    } else {
        foreach my $elem ($value1, $value2, $diff) {
            if ( !defined $elem ) {
                $elem = $default;
            } else {
                $elem = sprintf "%1.2f", $elem;
            }
        }
        return sprintf "%3s\t%3s\t%3s\n", $value1, $value2, $diff;
    }
}

sub diff_strings {
    my ($value1, $value2, $default) = @_;

    my $diff = 0;
    if ( defined $value1 && defined $value2 ) {
        $diff = ( $value1 eq $value2 ) ? 1 : 0;
    } else {
        foreach my $elem ($value1, $value2) {
            $elem = $default if !defined $elem;
        }
    }

    return sprintf "%3s\t%3s\t%3s\n", $value1, $value2, $diff;
}

sub diff_arrays {
    my ($ref1, $ref2) = @_;

    my @array1 = defined $ref1 ? sort @$ref1 : ();
    my @array2 = defined $ref2 ? sort @$ref2 : ();
    my @uniq = sort keys %{{ map { $_ => 1 } (@array1,@array2) }};

    my ($str1, $str2) = ("","");
    foreach my $elem (@uniq) {
        $str1 .= sprintf "%3s\t", ( grep {$_ eq $elem} @array1 ) ? $elem : "-";
        $str2 .= sprintf "%3s\t", ( grep {$_ eq $elem} @array2 ) ? $elem : "-";
    }

    my $eq = ( @array1 == @uniq && @array2 == @uniq ) ? 1 : 0;

    return "$eq\n$str1\n$str2\n";
}
