#!/usr/bin/perl

#use utf8;
use strict;
use CGI;

use Opals::Context;
use Opals::Template qw(
    tmpl_read
    tmpl_write
    tmpl_rangedPageList
);

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_F852Default_marcxml
    srch_validateRid
    srch_getIdenticalRIDs
);
use Opals::Utility qw(
    util_formatBarcode
    util_removeChar
    util_getXmlRecord
);

use Opals::Locale qw(
    loc_getMsgFile
    loc_write
);

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

my $cgi = CGI->new;
my $input = $cgi->Vars();

my ($permission, $cookie, $template) = tmpl_read(
        {
            dbh             => $dbh,
            cgi             => $cgi,
            tmplFile        => 'record/merge.tmpl',
            reqPermission   => 'marc_edit|marc_merge',
        }
);

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

($merge->{'pNum'}) || ($merge->{'pNum'} = 1);
$merge->{'pSize'} = 20;

# Delete
$merge = deleteRecord($merge);

# 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);
$template->param(hlpUrl     => Opals::Constant->getHlpUrl('merge') );
# List/View
my $mid = $merge->{'mid'};
if ($merge->{'op'} !~ m/^up$/i && $mid && $mid =~ m/^[\d]+$/) {
    $merge = ListDuplicateLocal($merge);
    $template->param(
        mid     => $merge->{'mid'},
        rid     => $merge->{'rid'},
        ridGone => $merge->{'ridGone'},
    );
    if ($merge->{'ridList'} && scalar(@{$merge->{'ridList'}}) > 1) {
        $template->param(
            ridList => $merge->{'ridList'},
        );
    }
}
else {
    my $sql = <<_SQL_;
select  count(*)
from opl_marcDuplicate
_SQL_
    if ($merge->{'iid'}) {
        $sql .= <<_SQL_;
where iid = $merge->{'iid'}
_SQL_
    }
    my ($pendingItemCount) = $dbh->selectrow_array($sql);
    my @rangedPageList = tmpl_rangedPageList($pendingItemCount, $merge->{'pNum'}, $merge->{'pSize'}, 10);
    
    $template->param(
        ListItems => GetMergeList($dbh, $merge->{'iid'}, $merge->{'pNum'}, $merge->{'pSize'}),
        rangedPageList      => \@rangedPageList,
    );
}
$template->param(
    iid => $merge->{'iid'},
    pNum => $merge->{'pNum'},
);

#Mon, Jan 11, 2010 @ 15:13:16 EST
my $msgValMap ={};
my $stdMsgMap            =loc_getMsgFile('item/merge.msg',$msgValMap);
loc_write($template,$stdMsgMap);

tmpl_write($dbh, $cgi, $cookie, $template);
#$dbh->disconnect();
################################################################################

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'};

    $merge->{'content'} = util_getXmlRecord($rid);

    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->{'iid'}
_STH_

        $dbh->do(<<_SQL_);
update  opl_marcRecord
set     zIndexed = 0
where   rid = $rid
_SQL_

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

    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->{'iid'}
_STH_

        $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;
}


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

    my $dbh = $merge->{'dbh'};
    my $mid = $merge->{'mid'};
    my $rid = $merge->{'rid'};
    
    my $duplicate = $dbh->selectrow_hashref(<<_STH_);
select  *
from    opl_marcDuplicate
where   mid = $mid
_STH_

    my $marc = Opals::Marc::Record::newFromXml($duplicate->{'content'});
    my $ridGroups = srch_getIdenticalRIDs($dbh, $marc);

    my $ridList;
    foreach my $id (@Opals::Search::RECORD_IDENTIFIERS) {
        my $sf = $id->{'tag'} . $id->{'code'};

        foreach my $row (@{$ridGroups->{$sf}}) {
            $ridList->{$row->{'rid'}} = 1;
        }
    }

    my @rids = sort keys %{$ridList};
    if (!$rid && scalar(@rids) > 0) {
        $merge->{'rid'} = $rids[0];
    }

    foreach my $rec_id (@rids) {
        push @{$merge->{'ridList'}}, {
            ridLocal=> $rec_id,
            sel     => ($rid && $rid == $rec_id) ? 1 : 0,
        };
    }

    return $merge;
}


#---------------------------------------------------------------
sub GetMergeList {
    my ($dbh, $iid, $pNum, $pSize) = @_;
    ($pNum && $pNum!~m/[\D]/) || ($pNum = 1);

    my $offset = ($pNum - 1) * $pSize;

    my @arrItems;
    
    my $sql = "select * from opl_marcDuplicate";
    if ($iid && $iid =~ m/^[\d]+$/ && $iid > 0) {
        $sql .= " where iid = $iid";
    }
    $sql .= " order by mid asc limit $offset, $pSize";
    my $query = $dbh->prepare($sql);
    $query->execute();
    while (my $rec = $query->fetchrow_hashref) {
        push @arrItems, {
            title   => GetSubField($rec->{'content'}, "245", "a"),
            author  => GetSubField($rec->{'content'}, "100", "a"),
            isbn    => GetSubField($rec->{'content'}, "020", "a"),
            OCoLC   => GetSubField($rec->{'content'}, "035", "a"),
            mid     => $rec->{'mid'},
        };
    }
    $query->finish;
    
    return \@arrItems;
}

#----------------------------------------------------------
#sub GetSubField
#{
#    my ($xml, $field, $subfield) = @_;
#    my $rec;
#    my @arrSubFields;
#
#    if ($xml =~ m/(([\s]*<datafield tag="$field" ind1="[\d ]" ind2="[\d ]">\n([\s]*<subfield code="[\w\d]">.*<\/subfield>\n)*[\s]*<\/datafield>\n)+)/) 
#    {
#        my $fsub = $1;
#        while ($fsub =~ s/<subfield code="$subfield">(.*)<\/subfield>//) 
#        {
#            $rec = $1;
#            $rec =~ s/ *[:\/] *$//;
#            push @arrSubFields, $rec;
#        }
#    }
#    return @arrSubFields;
#}

#----------------------------------------------------------
# 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;
    my $tmp=$xml;
    while($tmp =~ s/([\s]*<datafield tag="$tag" ind1="[\d ]" ind2="[\d ]">([\s]*<subfield code=".">.*<\/subfield>)+[\s]*<\/datafield>)//g) {
        if ($1 =~ m/<subfield code="$sfcode">(.*)<\/subfield>/) {
            $data = $1;
            last;
        }
    }

    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;
}


#sub addItemType {
#    my ($dbh, $itemTypeId) = @_;
#    if (!$dbh->do("insert into opl_itemType set id = ?", undef, $itemTypeId)) {
#        return;
#    }
#
#    my $sth;
#    my $defItemType;
#
#    my ($defaultItemTypeId) = $dbh->selectrow_array(<<_SQL_);
#select  id
#from    opl_itemType
#where   defaultType = 1
#_SQL_
#    $sth = $dbh->prepare(<<_STH_);
#select  *
#from    opl_itemTypeParam
#where   itemTypeId = ?
#_STH_
#    $sth->execute($defaultItemTypeId) || return;
#    while (my $itemType = $sth->fetchrow_hashref) {
#        $defItemType->{$itemType->{'userTypeId'}} = {
#            loanPeriod    => $itemType->{'loanPeriod'},
#            renewalPeriod => $itemType->{'renewalPeriod'},
#            reservePeriod => $itemType->{'reservePeriod'},
#            holdPeriod    => $itemType->{'holdPeriod'},
#            gracePeriod   => $itemType->{'gracePeriod'},
#            maxRenewal    => $itemType->{'maxRenewal'},
#        };
#    }
#    $sth->finish;
#
#    $sth = $dbh->prepare(<<_STH_);
#select  catid
#from    opl_category
#_STH_
#
#    my $sth_itemTypeParam = $dbh->prepare(<<_STH_);
#insert into opl_itemTypeParam
#set     itemTypeId    = ?,
#        userTypeId    = ?,
#        loanPeriod    = ?,
#        renewalPeriod = ?,
#        reservePeriod = ?,
#        holdPeriod    = ?,
#        gracePeriod   = ?,
#        maxRenewal    = ?
#_STH_
#
#    $sth->execute() || return;
#    while (my ($userTypeId) = $sth->fetchrow_array) {
#        $sth_itemTypeParam->execute(
#            $itemTypeId,
#            $userTypeId,
#            $defItemType->{$userTypeId}->{'loanPeriod'},
#            $defItemType->{$userTypeId}->{'renewalPeriod'},
#            $defItemType->{$userTypeId}->{'reservePeriod'},
#            $defItemType->{$userTypeId}->{'holdPeriod'},
#            $defItemType->{$userTypeId}->{'gracePeriod'},
#            $defItemType->{$userTypeId}->{'maxRenewal'}
#        );
#    }
#    $sth_itemTypeParam->finish;
#    $sth->finish;
#}
