#!/usr/bin/perl
#############################################################################
# Merges 2 bib files into 1
# Usage: $0 [options] <my-bib-file> <pure-generated-bib-file>
# Example: ./purify.pl -v ~/hwloidl-remus/tex/bib/hwl_test2.bib ~/hwloidl-remus/tex/bib/pure_test2.bib 2>bonzo.log 1>bonzo.bib
# Options:
# -h ... help
# -v ... be verbose
#############################################################################

# ToDos:
# . more flexible comparison of titles to match entries
# . tunable way of merging (selecting which file to prefer for same fields)
# . eliminate duplicates (or use a separate tool for that)
# . check for correct fields based on type (or use a separate tool for that)
#############################################################################

# ----------------------------------------------------------------------------
# Imports
# ----------------------------------------------------------------------------

use BibTeX::Parser;
use IO::File;

# ----------------------------------------------------------------------------
# Command line processing and initialization
# ----------------------------------------------------------------------------

require "getopts.pl";

&Getopts('hv');  

my $my_bib_file = "/home/hwloidl/hwloidl-remus/tex/bib/hwloidl.bib";
my $pure_bib_file = "/home/hwloidl/hwloidl-remus/tex/bib/pure_hwloidl.bib";

&process_options();

&print_verbose_message() if ( $opt_v );

# print STDERR "Consistency checking is enabled\n"  if ( $opt_C ) ;

# ----------------------------------------------------------------------------
# Global Variables
# ----------------------------------------------------------------------------

# for each field specify which version to prefer
my %merge_advice = ( "url" => "pure", "default" => "mine" );

# $key="url";
# if (exists($merge_advice{$key})) {
#     print stderr "exists($merge_advice{$key}: TRUE\n";
# } else {
#     print stderr "exists($merge_advice{$key}: FALSE\n";
# } 

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

sub process_options {
    if ( $opt_h ) {                      
	open(ME,$0) || die "Can't open myself ($0): $!\n";
	$n = 0;
	while (<ME>) {
	    last if $_ =~ /^$/;
	    print $_;
	    $n++;
	}
	close(ME);
	exit ;
    }
    
    if ( $#ARGV != 1 ) {
	print stderr "Usage: $0 [options] <my-bib-file> <pure-generated-bib-file>\n";
	print stderr "Output is written to stdout, log messages to stderr\n";
	print stderr "Use -h option to get details\n";
	exit 1;
    }

    $my_bib_file = $ARGV[0];
    $pure_bib_file = $ARGV[1];
}

sub print_verbose_message {
    print stderr "Input files: $input\n";  
    print stderr "  My bib file: $my_bib_file\n";  
    print stderr "  Pure bib file: $pure_bib_file\n";  
    print stderr "Input files: $input\n";  
    print stderr "Output written to stdout";
}

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

sub munge {
    local ($str) = @_;
    $str = lc($str);
    $str =~ s/[{}()]//g;
    $str =~ s/[-'`":,;.]//g;
    return $str
}

sub findbib {
    local ($tit) = @_;
    my $my_bib    = IO::File->new($my_bib_file);
    my $my_parser = BibTeX::Parser->new($my_bib);

     $tit = munge($tit);
     # print "Finding title '$tit'";

    $nmine = 0;
    # ... and iterate over entries
    while (my $entry = $my_parser->next ) {
	    $nmine++;
            if ($entry->parse_ok) {
                    my $type    = $entry->type;
                    my $title   = $entry->field("title");
                    my $pages   = $entry->field("pages");

                    my @authors = $entry->author;
                    # or:
                    my @editors = $entry->editor;
                    
		    # # print "Searching for this paper in own bib-file: \n";
                    # foreach my $author (@authors) {
                    #         print $author->first . " "
                    #             . $author->von . " "
                    #             . $author->last . ", "
                    #             . $author->jr;
                    # }
		    #$title = lc($title);
		    #$title =~ s/[{}]//g;
		    $title = munge($title);
		    # print ".... $title\n";
		    if ($tit eq $title) {
			return $entry;
		    } 
	    } else {
		warn "Error parsing file: " . $entry->error;
            }
    }
    return null;
}

# the main merger function
# Input:  BibTeX::Parser::Entry $my_item , BibTeX::Parser::Entry $pure_item
# Output: BibTeX::Parser::Entry $merged_item ::  BibTeX::Parser::Entry;
sub bib_item_merge {
    local ($my_item, $pure_item) = @_;

    foreach my $key (keys %{$my_item}) {
	if (exists($pure_item->{$key})) {
	    push(@common, $key);
	} else {
	    push(@mine, $key);
	}
    }
    foreach my $key (keys %{$pure_item}) {
	if (exists($my_item->{$key})) {
	    # push(@common, $key);
	} else {
	    push(@pures, $key);
	}
    }
    print stderr "__ Common fields: ".join(",",@common)."\n";
    print stderr "__ My fields: ".join(",",@mine)."\n";
    print stderr "__ Pure's fields: ".join(",",@pures)."\n";

    my $merged_item = BibTeX::Parser::Entry->new($pure_item->type,$pure_item->key) ;
    # $merged_item->key = $pure_item->key;
    # $merged_item->type = $pure_item->type;
    # print "% key: ".$merged_item->key."\ttype: ".$merged_item->type."\n";
    foreach my $key (@common) {
	if ((exists($merge_advice{$key}) && ($merge_advice{$key} eq "pure")) || $merge_advice{"default"} eq "pure") {
	    print stderr "** Using Pure for field ".$key." on entry ".$pure_item->key."\n";
	    $merged_item->{$key} = $pure_item->{$key};
	} else {
	    $merged_item->{$key} = $my_item->{$key};
	} 
    }
    foreach my $key (@mine) {
	$merged_item->{$key} = $my_item->{$key};
    }
    foreach my $key (@pures) {
	$merged_item->{$key} = $pure_item->{$key};
    }
    return $merged_item;
}

sub show_fields {
    local ($obj) = @_;
    print stderr "entry @ ".$entry." has these fields \t ";
    $str = join(",",keys %{$obj});
    print stderr $str."\n";
}

sub show_entry {
    local ($obj) = @_;
    # print "Showing entry @ ".$entry."...\n";
    foreach my $key (keys %{$obj}) {
	print $key." => ".$obj->{$key}."\n";
    }
}

sub pretty_print {
    local ($obj) = @_;
    # print "Showing entry @ ".$entry."...\n";
    print "@".$obj->type."{".$obj->key.",\n";
    foreach my $key (keys %{$obj}) {
	if ($key =~ /^_/ || $obj->{$key} eq "") {
	    next;
	} else {
	    if ($key =~ /abstract/) { $quote = "\""; } else { $quote = ""; } 
	    print " ".$key." =\t "."{".$quote.$obj->{$key}.$quote."},\n";
	}
    }
    print "}\n\n";
}


# ## TFP 2009 
# $bibfile = "http://www-fp.dcs.st-and.ac.uk/tifp/TFP2009.bib";
# $bibimg = "./TFP2009_files/bibtex.gif";

    my $matches = 0;
    my $npure = 0;
    my $nbib = 0;

    my $pure_bib   = IO::File->new($pure_bib_file); 
    # Create parser object ...
    my $pure_parser = BibTeX::Parser->new($pure_bib);

    # $tit =~ tr/{}//;
    # ... and iterate over entries
    while (my $entry = $pure_parser->next ) {
	    $npure++;
            if ($entry->parse_ok) {
                    my $type    = $entry->type;
                    my $title   = $entry->field("title");
                    my $pages   = $entry->field("pages");

                    my @authors = $entry->author;
                    # or:
                    my @editors = $entry->editor;
                    
		    # # print "Searching for this paper in own bib-file: \n";
                    # foreach my $author (@authors) {
                    #         print $author->first . " "
                    #             . $author->von . " "
                    #             . $author->last . ", "
                    #             . $author->jr;
                    # }
		    # print ">> ".$title."\n";
		    $my_entry = &findbib($title);
		    if ($my_entry != null) {
			$matches++;
			# print stderr "MATCH for ".$entry->key." with title ".$title."\n";
			print stderr "++ ".$my_entry->key." -> ".$entry->key."\n";
			print "% ".$my_entry->key." --> ".$entry->key."\n";
			#&show_fields($my_entry);
			#&show_fields($entry);
			$merged_entry = &bib_item_merge($my_entry,$entry);
			# &show_entry($merged_entry);
			&pretty_print($merged_entry);
		    } else {
			print stderr "-- No match for ".$entry->key." with title '".$entry->field("title")."'\n";
		    }
            } else {
                    warn "Error parsing file: " . $entry->error;
            }
    }

    print stderr "== $nmine items in my bib file, $npure items in pure bib file, $matches matches\n";
