#!/usr/bin/perl

# echo -n "Enter merge option: [del|new|oton|ntoo] "; read OPTION; echo  -n "Enter site list: "; read SITELIST; echo -n "Enter SQL host: "; read SQLHOST; echo -n "Enter SQL user: "; read SQLUSER; echo -n "Enter SQL password: "; read PPP; DATE=`date +%Y%m%d`; for i in $SITELIST; do echo Backup XML files for $i...; sudo tar jcpf $i-$DATE.tbz /data/idzebra/210/record/$i; echo Backup SQL database $i...; mysqldump -h$SQLHOST -u$SQLUSER -p$PPP $i > $i-$DATE.sql; \cp /www/opals/script/util/merge merge.$i; perl -pi -e "s/_SITECODE_/$i/" merge.$i; ./merge.$i -c $OPTION; sudo /opt/opals/bin/zindex_update $i; done; unset SQLHOST SQLUSER PPP DATE SITELIST OPTION

use lib '/www/opals/module';
use strict;
use Getopt::Std;

my %options = ();
getopts("c:",\%options);
my $command = $options{c};
if (!$command || $command !~ m/(del|new|oton|ntoo)/) {
    print "Usage: $0 -c del|new|oton|ntoo\n";
    exit 1;
}

use Opals::Context('/etc/opals/conf/_SITECODE_');

use Opals::MarcXml qw(
    mxml_updateDbZebra
    mxml_addItemType
);
#    mxml_validateRid

use Opals::Marc21 qw(
    mc21_parseRecord
    mc21_maxBarcodeTmp
    mc21_maxBarcodeDup
);

use Opals::Search qw(
    srch_identicalCriteria
    srch_checkLocalDatabase
    srch_F852Default_marcxml
    srch_validateRid
);
use Opals::Utility qw(
    util_formatBarcode
    util_removeChar
);


my $dbh = Opals::Context->dbh();
END { $dbh->disconnect(); }


my $merge;
$merge->{'dbh'} = $dbh;
#$merge->{'iid'} = $input->{'iid'};
#$merge->{'mid'} = $input->{'mid'};
#$merge->{'rid'} = $input->{'rid'};
#$merge->{'op'}  = $input->{'op'};

my $sth = $dbh->prepare(<<_SQL_);
select  mid
from    opl_marcDuplicate
order by mid asc
_SQL_

$sth->execute() || return;
while (my $m = $sth->fetchrow_hashref) {
    $merge->{'mid'} = $m->{'mid'};
    $merge->{'op'} = $command;

    if ($merge->{'op'} eq 'del') {
        # Delete
        $merge = deleteRecord($merge);
    }
    else {
        # Previous/Next, then load duplicate record from pending queue
        $merge = LoadDuplicate($merge);

        # Add duplicate, merge old to new, merge new to old
        $merge = AddData($merge);
    }
}
$sth->finish;

exit 0;


################################################################################

############################################################
sub AddData {
    my ($merge) = @_;
    
    if ($merge->{'op'} && $merge->{'op'} =~ m/^(new|oton|ntoo)$/i) {
        if ($merge->{'op'} =~ m/^(oton|ntoo)$/i) {
            $merge = mergeRecords($merge);
        }
        else {
            $merge = addRecord($merge);
        }

        #delete $merge->{'rid'};
        $merge = deleteRecord($merge);
        #$merge = LoadDuplicate($merge);
    }

    #return $merge;
}


############################################################
sub mergeRecords {
    my ($merge) = @_;
    my $dbh = $merge->{'dbh'};
    my $rid;# = $merge->{'rid'};

    my $criteria = srch_identicalCriteria($merge->{'duplicate'}->{'content'});
    my @recordList = srch_checkLocalDatabase($dbh, $criteria);

    foreach my $rec (@recordList) {
        if ($rec->{'content'}) {
            $rid                = $rec->{'rid'};
            $merge->{'content'} = $rec->{'content'};
            print "MID/RID: ".$merge->{'mid'}."/$rid\n";
            last;
        }
    }

    if ($merge->{'content'}) {
        my $oldxml = $merge->{'content'};
        my $newxml = $merge->{'duplicate'}->{'content'};
        if ($merge->{'op'} =~ m/^oton$/i) {
            $newxml = processNewHolding($dbh, $newxml, $rid, "3");
            $newxml = UpdateRecord($dbh, $oldxml, $newxml);
            $newxml = Merge($dbh, $rid, $oldxml, $newxml, "3");
        }
        else {
            $newxml = processNewHolding($dbh, $newxml, $rid, "3");
            $oldxml = Merge($dbh, $rid, $newxml, $oldxml, "3");
        }

        $dbh->do(<<_STH_);
update  opl_marcImport
set     countMerged = countMerged + 1
where   iid = $merge->{'duplicate'}->{'iid'}
_STH_

        $merge->{'op'} = 'del';
    }
    else {
        #$merge->{'ridGone'} = 1;
        $merge->{'ridGone'} = $rid;
        delete $merge->{'rid'};

        $merge->{'op'} = 'new';
        $merge = addRecord($merge);
        print "Can not merge record, new RID: ", $merge->{'newRid'},"\n";
    }

    return $merge;
}


############################################################
sub addRecord {
    my ($merge) = @_;
    if ($merge->{'op'} && $merge->{'op'} =~ m/^new$/i) {
        my $dbh = $merge->{'dbh'};
#open qqq, ">/tmp/qqq";
        my $newxml = $merge->{'duplicate'}->{'content'};
#print qqq "1###################\n$newxml\n";
        my $rid = srch_validateRid($dbh, 0);
        my $oldxml = <<_MARCXML_;
<record>
  <leader></leader>
  <controlfield tag="001">$rid</controlfield>
  <controlfield tag="005">11112233445566.1</controlfield>
</record>
_MARCXML_
        $newxml = UpdateRecord($dbh, $oldxml, $newxml);
#print qqq "2###################\n$newxml\n";
        Update_marcRecord($dbh, $newxml, $rid);
        $newxml = processNewHolding($dbh, $newxml, $rid, "3");
#print qqq "3###################\n$newxml\n";
#close qqq;
        mxml_updateDbZebra($dbh, $rid, $newxml);
        $dbh->do(<<_STH_);
update  opl_marcImport
set     countImported = countImported + 1
where   iid = $merge->{'duplicate'}->{'iid'}
_STH_

        $merge->{'newRid'} = $rid;
        $merge->{'op'} = 'del';
    }

    return $merge;
}


############################################################
sub deleteRecord {
    my ($merge) = @_;

    if ($merge->{'op'} && $merge->{'op'} =~ m/^del$/i) {
        my $dbh = $merge->{'dbh'};

        $dbh->do(<<_STH_);
delete from opl_marcDuplicate
where mid = $merge->{'mid'}
_STH_

        delete $merge->{'rid'};
        $merge->{'op'} = 'next';
    }

    return $merge;
}


############################################################
sub changeRecord {
    my ($merge) = @_;
    
    if ($merge->{'op'} && $merge->{'op'} =~ m/^(prev|next)$/i) {
        delete $merge->{'rid'};

        my $dbh = $merge->{'dbh'};
        my $sth;

        if ($merge->{'op'} =~ m/^prev$/i) {
            $sth = <<_STH_;
select  mid
from    opl_marcDuplicate
where   mid < $merge->{'mid'}
_STH_
            
            if ($merge->{'iid'}) {
                $sth .= <<_STH_;
&& iid = $merge->{'iid'}
_STH_
            }
            
            $sth .= <<_STH_;
order by mid desc
limit 1
_STH_
        }
        else {
            $sth = <<_STH_;
select  mid
from    opl_marcDuplicate
where   mid > $merge->{'mid'}
_STH_
            
            if ($merge->{'iid'}) {
                $sth .= <<_STH_;
&& iid = $merge->{'iid'}
_STH_
            }
            
            $sth .= <<_STH_;
order by mid asc
limit 1
_STH_
        }
        ($merge->{'mid'}) = $dbh->selectrow_array($sth);

        if (!$merge->{'mid'}) {
            $merge->{'op'} = 'up';
        }
    }

# Fri, Jul 25, 2008 @ 11:29:12 EDT
# Updated: Thien
# Remove comment to jump to the current page of the current pending record.
#
#    ($merge->{'pNum'}) = $dbh->selectrow_array(<<_SQL_);
#select  ceil(count(mid)/$merge->{'pSize'})
#from    opl_marcDuplicate
#where   mid <= $merge->{'mid'}
#_SQL_

    return $merge;
}


############################################################
sub LoadDuplicate {
    my ($merge) = @_;
    
    if ($merge->{'op'} && $merge->{'op'} =~ m/^(prev|next)$/i) {
        $merge = changeRecord($merge);
    }
    
    if ($merge->{'op'} !~ m/^up$/i) {
        $merge->{'duplicate'} = $dbh->selectrow_hashref(<<_STH_);
select  * 
from    opl_marcDuplicate
where   mid = $merge->{'mid'}
_STH_
    }

    return $merge;
}

# Hmm, 'GetFieldStr' should be named 'stripFieldStr'
############################################################
sub GetFieldStr
{
    my ($xml, $field) = @_;
    my $fieldStr;
    
    if ($field =~ m/leader/) {
        while ($xml =~ s/([\s]*<leader>(.*)<\/leader>)//) {
            $fieldStr = $1;
        }
    }
    elsif ($field =~ m/00\d/) {
        while ($xml =~ s/([\s]*<controlfield tag="$field">.*<\/controlfield>)//) {
            $fieldStr .= $1;
        }
    }
    else {
        while ($xml =~ s/([\s]*<datafield tag="$field" ind1="[\d ]" ind2="[\d ]">([\s]*<subfield code=".">.*<\/subfield>)*[\s]*<\/datafield>)//) {
            $fieldStr .= $1;
        }
    }
    
    return ($fieldStr, $xml);
}


############################################################
sub GetSubField {
    my ($xml, $tag, $sfcode) = @_;
    my $data;
    if ($xml =~ m/([\s]*<datafield tag="$tag" ind1="[\d ]" ind2="[\d ]">([\s]*<subfield code=".">.*<\/subfield>)+[\s]*<\/datafield>)/) {
        if ($1 =~ m/<subfield code="$sfcode">(.*)<\/subfield>/) {
            $data = $1;
        }
    }

    return $data;
}


############################################################
sub Merge
{
    my ($dbh, $rid, $srcxml, $dstxml) = @_;
    my ($f852src, $f852dst);
#    open ttt, ">/tmp/ttt";
    ($f852src, $srcxml) = GetFieldStr($srcxml, "852");
    ($f852dst, $dstxml) = GetFieldStr($dstxml, "852");
#    print ttt "1 ########\n$f852src\n2 ########\n$f852dst\n";
#    $f852dst .= $f852src;
#    print ttt "3 ########\n$f852src\n4 ########\n$f852dst\n";
    $dstxml =~ s/[\s]*<\/record>/$f852dst$f852src\n<\/record>/;
#    close ttt;
    
#    $dstxml =~ s/[\n]+/\n/g;
    mxml_updateDbZebra($dbh, $rid, $dstxml);
    return $dstxml;
}

############################################################
sub UpdateRecord
{
    my ($dbh, $oldxml, $newxml) = @_;
    my ($field001, $field005);
    ($field001, $oldxml) = GetFieldStr($oldxml, "001");
    ($field005, $oldxml) = GetFieldStr($oldxml, "005");

#    $field001 =~ s/[\n]+$//;
#    $field005 =~ s/[\n]+$//;

    $newxml =~ s/<\/leader>/<\/leader>$field005/;
    $newxml =~ s/<\/leader>/<\/leader>$field001/;

    return $newxml;
}


############################################################
sub Update_marcRecord {
    my ($dbh, $xml, $rid) = @_;

    my ($title, $author, $pubPlace, $pubName, $pubDate);
    my $dummyStr;

    # title
    $dummyStr = GetSubField($xml, '245', 'a');
    $dummyStr = util_removeChar($dummyStr);
    $title    = $dummyStr if $dummyStr;
    $dummyStr = GetSubField($xml, '245', 'b');
    $dummyStr = GetSubField($xml, '245', 'p') unless $dummyStr;
    $dummyStr = util_removeChar($dummyStr);
    $title   .= ': ' .$dummyStr if $dummyStr;

    # author
    $dummyStr = GetSubField($xml, '100', 'a');
    $dummyStr =~ s/&apos;/'/g;
    $dummyStr = util_removeChar($dummyStr);
    $author   = $dummyStr if $dummyStr;

    # pubPlace
    $dummyStr = GetSubField($xml, '260', 'a');
    $dummyStr =~ s/&apos;/'/g;
    $dummyStr = util_removeChar($dummyStr);
    $pubPlace = $dummyStr if $dummyStr;

    # pubName
    $dummyStr = GetSubField($xml, '260', 'b');
    $dummyStr =~ s/&apos;/'/g;
    $dummyStr = util_removeChar($dummyStr);
    $pubName  = $dummyStr if $dummyStr;

    # pubDate
    $pubDate  = GetSubField($xml, '260', 'c');
    
    my $sth = $dbh->prepare(<<_STH_);
replace into opl_marcRecord
set rid      = ?,
    title    = ?,
    author   = ?,
    pubPlace = ?,
    pubName  = ?,
    pubDate  = ?
_STH_
    my $rv = $sth->execute(
        $rid,
        $title,
        $author,
        $pubPlace,
        $pubName,
        $pubDate
    );
    $sth->finish;
    
    return $rv;
}


############################################################
sub processNewHolding {
    my ($dbh, $xml, $rid, $itemType_sfCode) = @_;

    my $f852 = '';
    my $sth_barcode = $dbh->prepare(<<_STH_);
select  count(*)
from    opl_item
where   barcode = ?
_STH_

    my $sth_insertItem = $dbh->prepare(<<_STH_);
insert into opl_item
set     rid         = $rid,
        barcode     = ?,
        typeId      = ?,
        callNumber  = ?,
        dateImport  = now()
_STH_

    my $f852Default = srch_F852Default_marcxml($dbh, 0);
    if ($xml !~ m/<datafield tag="852"/) {
        $xml =~ s/[\s]*<\/record>/$f852Default\n<\/record>/;
    }

    my @newSubFields;
    while ($xml =~ s/([\s]*<datafield tag="852" ind1="[\d ]" ind2="[\d ]">([\s]*<subfield code="[\w]">.*<\/subfield>)+[\s]*<\/datafield>)//) {
        my $fsub = $1;
        my ($bc, $newbc, $newSubfield);
        if ($fsub =~ s/[\s]*<subfield code="p">(.*)<\/subfield>/_fdsa_/) {
            $newSubfield = $1;
            $bc = $newSubfield;
            #$bc =~ s/ *[:\/] *$//;
            $bc =~ s/(^[\s]+|[\s]+$)//;
            if ($bc) {
                $sth_barcode->execute($bc) || return;
                my ($cBarcode) = $sth_barcode->fetchrow_array;
                if ($cBarcode) { # duplicate
                    if ($bc =~ m/TMP\_/) {
                        $newbc  = mc21_maxBarcodeTmp($dbh);
                    }
                    else {
                        $newbc = mc21_maxBarcodeDup($dbh, $bc);
                    }
                }
                else {
                    $newbc = $bc;
                }
            }
            else {
                $newbc  = mc21_maxBarcodeTmp($dbh);
            }
        }
        else {
            $fsub =~ s/[\s]*<\/datafield>/_fdsa_\n  <\/datafield>/;
            $newbc  = mc21_maxBarcodeTmp($dbh);
        }

        $fsub =~ s/_fdsa_/\n    <subfield code="p">$newbc<\/subfield>/;

        # The code duplicating item type into zebra is for nothing
        my $typeId;
        if ($fsub =~ s/[\s]*<subfield code="$itemType_sfCode">(.*)<\/subfield>/_asdf_/) {
            $typeId = $1;
            $typeId =~ s/ *[:\/] *$//;
            mxml_addItemType($dbh, $typeId);
        }
        else {
            $fsub =~ s/[\s]*<\/datafield>/_asdf_\n  <\/datafield>/;
            ($typeId) = $dbh->selectrow_array("select id from opl_itemType where defaultType=1");
        }

        $fsub =~ s/_asdf_/\n    <subfield code="3">$typeId<\/subfield>/;

        my $callNumber  = GetSubField($fsub, '852', 'k') . ' ' .
                          GetSubField($fsub, '852', 'h') . ' ' .
                          GetSubField($fsub, '852', 'i') . ' ' .
                          GetSubField($fsub, '852', 'm');
        $callNumber =~ s/ +/ /g;
        $callNumber =~ s/(^ | $)//g;
        $sth_insertItem->execute($newbc, $typeId, $callNumber);

        $f852 .= $fsub;
        addItemInfo($dbh, $fsub, $newbc);
    }

    $sth_barcode->finish;

    $xml =~ s/[\s]*<\/record>/$f852\n<\/record>/;
    return $xml;
}


############################################################
sub addItemInfo {
    my ($dbh, $f852, $barcode) = @_;
    my $sth = $dbh->prepare(<<_SQL_);
insert into opl_itemInfo
set barcode    = ?,
    sf852Code  = ?,
    sf852Data  = ?
_SQL_
    while ($f852 =~ s/[\s]*<subfield code="([\w])">(.*)<\/subfield>//) {
        $sth->execute($barcode, $1, $2);
    }
    $sth->finish;
}
