#! /usr/local/apps/perl/current/bin/perl

#########################################################################################
# Program to read in two files (e.g. name.def, paramId.def, shortName.def or units.def)
# and check
#  1. They have the same number of parameters
#  2. They occur in the same order
#  3. And each param is defined in exactly the same way
# For each parameter we store its keys in the order encountered
# in the files and compare.
#
# Usage:
#     $0  file1 file2
#
# URLs:
#  http://perldoc.perl.org/perldsc.html#MORE-ELABORATE-RECORDS
#########################################################################################

$|=1;
#use strict;
use Test::More;
use Data::Dumper;
#use Algorithm::Diff qw[ diff ];
use Algorithm::Diff::Callback 'diff_hashes';

$extra_info= 0; # Do we print more info?
$debug = 0;
my $key; my @values;

die "Bad args. Expected two files" if (scalar @ARGV < 2);
$file1 = $ARGV[0];
$file2 = $ARGV[1];
print "Comparing $file1 and $file2\n";
#die "File extension should be '.def'" if $file1 !~ /\.def$/;
#die "File extension should be '.def'" if $file2 !~ /\.def$/;

while (my $arg = shift @ARGV){
    if ($arg =~ /-D(\w+)=(\w+)/) {
        $var_name = $1; $value = $2;
        $$var_name = $value;
    }
}

my %map1 = process("$file1");
my %map2 = process("$file2");
my $count1 = scalar(keys %map1);
my $count2 = scalar(keys %map2);

# Compare hashes
if ($compare) {
  print "Compare hashes...\n";
  diff_hashes(
        \%map1,
        \%map2,
        sub { print "\nLost ",   shift },
        sub { print "\nGained ", shift },
        undef,
    );
}
#diff_hashes(
#        \%map1,
#        \%map2,
#        sub { print 'Lost ',   shift },
#        sub { print 'Gained ', shift },
#        sub {
#            my ( $key, $before, $after ) = @_;
#            print "$key changed from $before to $after\n";
#        },
#    );

#@diffs = diff( \%map1, \%map2 );
#exit 0;
#print @$_ for map{
#    @$_ 
#} diff( 
#    [ split "\n", Dumper( \%map1 ) ], 
#    [ split "\n", Dumper( \%map2 ) ] 
#);

print "\nTesting now...\n";
ok($count1==$count2, "Same number of elements");
ok($count1 > 0 && $count2 > 0, "Check some params found");

#print "count1=$count1, count2=$count2\n";

# Check name maps are the same
is_deeply(\%map1, \%map2,   'Check hashes are the same');

print Data::Dumper->Dump([\%map1], ["Name Map1"]), $/ if ($debug);

done_testing();

# -------------------------------------------------------------------------
# Function to return a hash:
#    key   = parameter long name
#    value = an array holding 1 or more hashes
# We use a trick to store the main title e.g. units, paramId in they key "<MAIN>"
# E.g.
# hash = {
#  'Reactive tracer 10 mass mixing ratio' => [
#       {
#           'parameterCategory' => '210',
#           'parameterNumber' => '149',
#           'discipline' => '192'
#       },
#       {
#           'parameterCategory' => '211',
#           'parameterNumber' => '149',
#           'discipline' => '192'
#       }
#   ],
#  'downward shortwave radiant flux density' => [
#       {
#           'parameterCategory' => '201',
#           'parameterNumber' => '1',
#           'discipline' => '192'
#       }
#   ],
# .... etc
#
# -------------------------------------------------------------------------
sub process {
    my ($filename) = @_;
    
    open FILE, $filename or die "Tried to open $filename\n$!";
    my @lines = <FILE>;
    close(FILE);
    
    my %map1 = ();
    my %map2 = ();  # inner map
    my $lineNum = 0;
    my $desc = "";
    my $this;           # a line in file
    foreach $this (@lines) {
        $lineNum++;
        chomp $this;
        #if ($lineNum == 1 && $this !~ /Automatically generated by/ ) {
        #    die "File: $filename, Line 1: Should say 'Automatically generated'";
        #}
        #next if ($lineNum == 1); # always skip first line
        # Description line
        if ($this =~ /^\s*#\s*(.*)\s*/) {
            $desc = $1;
            die "File: $filename, Empty description" if ($desc eq "");
        }
        # 'something' = {
        elsif ($this =~ /^'(.*)'\s*=\s*{\s*$/ && $desc) {
            $map2{"<MAIN>"} = $1;
        }
        # key = value
        elsif ($this =~ /(\w+)\s*=\s*([^ ]+)\s*;/ && $desc) {
            $key = $1; $val = $2;
            $map2{$key} = $val;
        }
        # Hit the end brace
        elsif ($this =~ /^\s*}\s*$/) {
            my %map2_copy = %map2;  # copy inner hash
            # Store this inner hash in our array
            push @{ $map1{$desc} }, \%map2_copy;
            %map2 = ();             # Empty inner map for next param
        }
    }
    return (%map1);
}
