package Opals::ILL;

use Exporter;
@ISA       = qw(Exporter);

@EXPORT_OK = qw(

    ill_res_addLoan
    ill_res_returnLoan
    ill_res_returnLoan_illMsg
    ill_res_receiveLoan
    ill_res_receiveLoan_illMsg
    ill_res_lookup
    ill_res_lookup_union
    ill_res_lookupBy_loanId
    ill_res_lookupBy_illId
    ill_res_lookupBy_barcode



    ill_req_lookup
    ill_req_lookup_union
    ill_req_addLoan
    ill_req_returnLoan
    ill_req_returnLoan_illMsg
    ill_req_receiveLoan_illMsg
    ill_req_receiveLoan

    ill_getOpenIllReqCount
);
use Opals::MarcXml qw(
    mxml_del_rec_holding
);

use Opals::Circulation qw(
    circ_processLoan
    circ_processReturn
    circ_processReturn_ILL
    circ_getItemStatus
    
);
use Opals::User qw(
    user_getILLUser
);

use Opals::Template_ajax qw(
    tmpl_read
    tmpl_write
    tmpl_preference
);
use Opals::BarcodeMgmt qw(
    bcm_validateBc
);
use Opals::XML::SAX::IllSearchRsHandler;
use Opals::Date qw(
    date_now
);
use XML::Simple;
use XML::XPath;

# Version number
$VERSION   = 0.01;      
use Opals::Context;
use strict;
use Encode;
use constant    LOAN_FILLED   =>   'lFilled';
use constant    LOAN_RETURN   =>   'bReturned';
use constant    LOAN_RECEIVED =>   'lReceived';
use constant    LOAN_LOST     =>   'lost';
use constant    LOAN_FOUND    =>   'bFound';

use Opals::Constant;

my $ill_unionId     = Opals::Context->preference('unionId');
my $ill_host        = Opals::Context->preference('unionSvcUrl');
   $ill_host =~ s/^http:\/\///g;
   $ill_host =~ s/\/+$//g;




use LWP::UserAgent;
use LWP::Protocol::http; # to suppress the warning "possible typo" in the next statement
push(@LWP::Protocol::http::EXTRA_SOCK_OPTS, MaxLineLength => 0);
use HTTP::Request::Common;


my $url="http://$ill_host/bin/svc/illWebSvc";

$| = 1;


################################################################################
sub ill_res_addLoan{
    my($dbh,$loanMsg,$autoCreateLoanTrans)=@_;

    my $sth =$dbh->prepare("insert into opl_ILL_out 
                                   set ILL_id=? ,ILL_lid=?, ILL_lName=?, 
                                   ILL_loanId=?,barcode=?,status='loan' ,
                                   dateLoan=?, dateDue=?");
    my $rv;
    my $pLoan;
    my $loanList =  $loanMsg->{'loanList'};
    my $syspref  = tmpl_preference($dbh);
    my $validateBc  = $syspref->{'validateBarcode'};
    my $barcodeType = $syspref->{'barcodeType'};

    foreach my $l (@$loanList){   
        $l->{'barcode'}=bcm_validateBc($dbh,$l->{'barcode'},$barcodeType) if($validateBc eq '1');
        $rv = $sth->execute(
                       $loanMsg->{'illId'},
                       $loanMsg->{'lid'},
                       $loanMsg->{'lName'},
                       $l->{'loanId'},
                       $l->{'barcode'},
                       $l->{'loanDate'},
                       $l->{'dueDate'}
                       ) ||  0;
        my $id= $dbh->{'mysql_insertid'} if($rv);              
        if($autoCreateLoanTrans){
            my $uid=user_getILLUser($dbh,$loanMsg->{'lid'},$loanMsg->{'lName'});
            next if(!$uid);
            my $itemStatus =circ_getItemStatus($dbh,$l->{'barcode'}) ;
            if($itemStatus->{'status'}==IT_STAT_FULL_AVAIL){
                $pLoan = circ_processLoan($dbh, $uid, $l->{'barcode'}, $l->{'loanDate'},$l->{'dueDate'},'');
                $dbh->do("update opl_ILL_out set uid=? where id=?",undef,$uid,$id);
            }
        }
    }
    $sth->finish;
    return $rv ;

}
################################################################################
#sub ill_res_returnLoan{
#    my($dbh,$loanMsg)=@_;
#
#    my $sth =$dbh->prepare("update  opl_ILL_out 
#                            set     dateReturn=? , status='return'
#                            where   ILL_loanId=? ");
#    my $rv;
#    my $loanList =  $loanMsg->{'loanList'};
#    my $pStatus;
#
#    foreach my $l (@$loanList){   
#        $rv =$sth->execute(
#                       $l->{'dateReturn'},
#                       $l->{'loanId'}
#                       )||  0;
#         circ_processReturn($dbh,$l->{'barcode'});              
#    }
#
#    return $rv;
#}
#
################################################################################
sub ill_res_returnLoan_illMsg{
    my($dbh,$loanMsg)=@_;

    my $loanList =  $loanMsg->{'loanList'};
    my $pStatus;
    foreach my $l (@$loanList){
        $pStatus=ill_res_returnLoan($dbh,$l->{'loanId'},$l->{'dateReturn'});
        $l->{'procsessStatus'}= $pStatus;
    }
    return $loanList;
}

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



sub ill_res_returnLoan{
    my($dbh,$loanId,$dateReturn)=@_;

    my $sth =$dbh->prepare("update  opl_ILL_out 
                            set     dateReturn=? , status='return'
                            where   ILL_loanId=?  ");
    my $rv;
    $rv =$sth->execute($dateReturn,$loanId)||  0;

    $sth->finish;
    return $rv;
}

################################################################################
sub ill_res_receiveLoan_illMsg{
    my($dbh,$loanMsg)=@_;

    my $loanList =  $loanMsg->{'loanList'};
    my $pStatus;
    my $syspref  = tmpl_preference($dbh);
    my $validateBc  = $syspref->{'validateBarcode'};
    my $barcodeType = $syspref->{'barcodeType'};
   
    foreach my $l (@$loanList){
        $l->{'barcode'}=bcm_validateBc($dbh,$l->{'barcode'},$barcodeType) if($validateBc eq '1');
        $pStatus=ill_res_receiveLoan($dbh,$l->{'loanId'},$l->{'barcode'},$l->{'dateReturn'});
        $l->{'procsessStatus'}= $pStatus;
    }
    return $loanList;
}
################################################################################
sub ill_res_receiveLoan{
    my($dbh,$loanId,$barcode,$dateReturn)=@_;

    my $sth =$dbh->prepare("update  opl_ILL_out 
                            set     dateReturn=? , status='receive'
                            where   ILL_loanId=?");
    my $rv;
    $rv =$sth->execute(
                   $dateReturn,
                   $loanId
                   )||  0;
    circ_processReturn_ILL($dbh,$loanId,$barcode) if($rv);              

    $sth->finish;
    return $rv;
}


################################################################################
sub ill_res_LostItem{
    my($dbh,$loanMsg)=@_;

    my $sth =$dbh->prepare("update  opl_ILL_out 
                            set     dateLost=? , status='lost'
                            where   ILL_id=? &&  barcode=?");
  
    my $rv =$sth->execute(
                   $loanMsg->{'dateLost'},
                   $loanMsg->{'illId'},
                   $loanMsg->{'barcode'}
                   )||  0;
    $sth->finish;
    return $rv;
}


################################################################################
sub ill_req_receiveLoan_illMsg{
    my($dbh,$loanMsg)=@_;

    my $loanList =  $loanMsg->{'loanList'};
    my $pStatus;
    my $syspref  = tmpl_preference($dbh);
    my $validateBc  = $syspref->{'validateBarcode'};
    my $barcodeType = $syspref->{'barcodeType'};
   
    foreach my $l (@$loanList){
        $l->{'barcode'}=bcm_validateBc($dbh,$l->{'barcode'},$barcodeType) if($validateBc eq '1');
        $pStatus=ill_req_receiveLoan($dbh,$l->{'loanId'},$l->{'dateReturn'});
        $l->{'procsessStatus'}= $pStatus;
    }
    return $loanList;
}
################################################################################
sub ill_req_receiveLoan{
    my($dbh,$loanId,$dateReturn)=@_;
    if(!$dateReturn || $dateReturn!~ m/(\d{4}-\d{1,2}-\d{1,2})( (\d{1,2}:\d{1,2}:\d{1,2})){0,1}/g){
        $dateReturn=date_now();
    }

    my $sth =$dbh->prepare("update  opl_ILL_in 
                            set     dateReturn=? , status='receive'
                            where   ILL_loanId=?");
    my $rv;
    $rv =$sth->execute(
                   $dateReturn,
                   $loanId
                   )||  0;

    $sth->finish;
    return $rv;
}


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


sub  ill_req_addLoan{
    my($dbh,$illMsg)=@_;

    my $rv;
    my $sth =$dbh->prepare("insert into opl_ILL_in 
                                   set ILL_id    =?,ILL_lid=?, ILL_lName=?, 
                                       title=?, author=?, pubDate=?,pubPlace=?, pubName=?,
                                       isbn=?,sf852k=?, sf852h=?, sf852i=?, status='loan' ,
                                       ILL_loanId=?,dateLoan=?, ILL_itemBc=?");
    my $loanList =  $illMsg->{'loanList'};
    foreach my $l (@$loanList){
      $rv = $sth->execute(
                   $illMsg->{'illId'},
                   $illMsg->{'lid'},
                   $illMsg->{'lName'},
                   $illMsg->{'title'},
                   $illMsg->{'author'},
                   $illMsg->{'pubDate'},
                   $illMsg->{'pubPlace'},
                   $illMsg->{'pubName'},
                   $illMsg->{'isbn'},
                   $illMsg->{'sf852k'},
                   $illMsg->{'sf852h'},
                   $illMsg->{'sf852i'},
                   $l->{'loanId'},
                   $l->{'dateLoan'},
                   $l->{'barcode'}
                   ) ||  0;
    }
    $sth->finish;
    return $rv;
}
################################################################################
sub ill_req_returnLoan_illMsg{
    my($dbh,$illMsg)=@_;

    my $loanList =  $illMsg->{'loanList'};
    my $pStatus;
   
    foreach my $l (@$loanList){
        $pStatus=ill_req_returnLoan($dbh,$l->{'loanId'},$l->{'dateReturn'});
        $l->{'procsessStatus'}= $pStatus;
    }
    return $loanList;

}


################################################################################
sub ill_req_returnLoan{
    my($dbh,$loanId,$dateReturn)=@_;

    my $sth =$dbh->prepare("update  opl_ILL_in 
                            set     dateReturn=? , status='return'
                            where   ILL_loanId=? ");
  
    my $rv =$sth->execute($dateReturn,$loanId)||  0;
    $sth->finish;
    my ($rid,$barcode) =ill_getLocalBarcode($dbh,$loanId);
    if($barcode){
        circ_processReturn($dbh,$barcode,$dateReturn);   
        mxml_del_rec_holding($dbh,{$rid=>{$barcode=>1}},1);
    }

    return $rv;
}
################################################################################
sub ill_getLocalBarcode{
    my($dbh,$loanId)=@_;
    my ($rid,$bc) =$dbh->selectrow_array("select i.rid,l.local_bc 
                                    from opl_item i inner join opl_ILL_in l on i.barcode=l.local_bc 
                                    where   ILL_loanId='$loanId'");
  
    return ($rid,$bc);
}

#////////////////////////////////////////////////////////////////////////////

sub http_post {
    my ($postURL, $postContent) = @_;

    my $ua = LWP::UserAgent->new();
    $ua->agent('OPALS ILL Web Service Client');
    $ua->timeout(120);
    my $result = {
        status  => 0,
        error   => '',
        content => '',
    };

    my $response = $ua->request(
        POST "$postURL",
        Content_Type => 'multipart/form-data', 
        Content => $postContent
    );

    if ($response->is_error() || !$response->is_success){
        $result->{'error'} = "connection error";
    }
    else {
        my $responseXml = $response->content;
        if ($responseXml =~ m/<status>(.*)<\/status>/i){
            $result->{'status'}= $1;
            if ($result->{'status'} ne '1'){
                if ($responseXml =~ m/<error>(.*)<\/error>/i){
                    $result->{'error'}= $1;
                }
            }
        }

        $result->{'content'} = $responseXml;
    }
    return $result;
}
#===========================================================================
#  
sub ill_req_lookup{
    my ($dbh,$inputVal,$status)=@_;
    my $statusCond="";
    if(defined $status && scalar(@$status)>0){
        foreach my $s(@$status){
            $s= "status='$s'";
        }
        $statusCond=" && (" . join(" || ",@$status) .")";
    }

    my $sql = <<_SQL_;
SELECT     distinct ill_id,ILL_lid,  ILL_lName, title,author,isbn,local_bc,ILL_itemBc,ILL_loanId,dateLoan
FROM       opl_ILL_in  
WHERE      (ILL_loanId =? || cast(ILL_id as char) ='$inputVal' || local_bc =? || ILL_itemBc=?) $statusCond
ORDER BY    id
_SQL_

    my $sth = $dbh->prepare($sql);
    $inputVal=~ s/^[\s]+|[\s]+$//g;
    $sth->execute($inputVal,$inputVal,$inputVal);
    my $prevIllId=-1;
    my $illInfoList=[];
    my $i=-1;    
    while (my $rec = $sth->fetchrow_hashref) {
        if($prevIllId != $rec->{'ill_id'}){
            $i++;
            $rec->{"bookcover"}="/bin/search/frontcover?size=m&isbn=" .$rec->{"isbn"};
            $illInfoList->[$i]=$rec;
            $illInfoList->[$i]->{'totalLoan'}=0;
            $illInfoList->[$i]->{'loanList'}=[];
            $prevIllId = $rec->{"ill_id"};
        }
        push @{$illInfoList->[$i]->{'loanList'}},{loanId    =>$rec->{'ILL_loanId'},
                                                  loanDate=>$rec->{'dateLoan'},
                                                  local_itembc  =>$rec->{'local_bc'},  
                                                  local_bc      =>$rec->{'local_bc'},
                                                  ILL_itemBc=>$rec->{'ILL_itemBc'},
                                                  res_lid=>$rec->{'ILL_lid'},
                                                  res_lName=>$rec->{'ILL_lName'}
                                                  };
        $illInfoList->[$i]->{'totalLoan'} +=1;
    }
    $sth->finish;
    
    return $illInfoList;


}
#===========================================================================
sub ill_getOpenIllReqCount{
    my ($dbh)=@_;
    my $count=0;
    my $svcName="res_getOpenIllReqCount";
    my $msgXml= sprintf "<illMsg><serviceName>%s</serviceName><unionId>%s</unionId></illMsg>",
                            $svcName,$ill_unionId;
   my $rs=http_post($url,[illMsg=>$msgXml]); 
   if($rs->{'status'} eq '1'){
        my $xmlObj =XML::XPath->new(xml=>$rs->{'content'});
        if($xmlObj->exists("openIllRequest/count")){
            my $nTxt=$xmlObj->getNodeText("openIllRequest/count");
            if($nTxt && $nTxt=~ m/\d+/){
                $count=int($nTxt);
            }
        }
        
   }
   return $count;
                           
}

#===========================================================================
sub ill_req_lookup_union{
    my ($dbh,$input)=@_;
    my $illInfoList=[];
    my $illId=$input->{'illId'}|| '';
    my $loanId=$input->{'loanId'}|| '';
    my $barcode=$input->{'barcode'}|| '';
    my $status=$input->{'status'}|| '';
    my $svcName="req_illInfoLookup";
    
    my $msgXml= sprintf "<illMsg><serviceName>%s</serviceName><unionId>%s</unionId><loanStatus>%s</loanStatus>"
                        ."<illId>%s</illId><loanId>%s</loanId><barcode>%s</barcode></illMsg>",
                            $svcName,$ill_unionId,$status,$illId,$loanId,$barcode;
   my $rs=http_post($url,[illMsg=>$msgXml]); 
   if($rs->{'status'} eq '1'){
       $illInfoList= _illRsParser($rs->{'content'});
       foreach my $ill(@$illInfoList){
            $ill->{'bookcover'}="/bin/search/frontcover?size=m&isbn=" .$ill->{"isbn"};
       }
   }
   return $illInfoList;
                           
}
#===========================================================================
sub _illRsParser {
    my ($xml)=@_;
    my $illList=[];
    $xml=decode("utf-8",$xml);
    if($xml){
       $xml =~ s/&amp;/&/g;  
       $xml =~ s/&/&amp;/g;  
        my $parser = XML::SAX::ParserFactory->parser(
                Handler => Opals::XML::SAX::IllSearchRsHandler->new
                );
        $parser->parse_string($xml);
        $illList  =$parser->{'Handler'}->getIllList();
    }
    return $illList;
}


#===========================================================================
#  
sub ill_res_lookup{
    my ($dbh,$inputVal,$status)=@_;
    my $statusCond="";
    $inputVal=~ s/^[\s]+|[\s]+$//g;
    if(scalar(@$status)>0){
        foreach my $s(@$status){
            $s= "status='$s'";
        }
        $statusCond=" && (" . join(" || ",@$status) .")";
    }

    my $sql = <<_SQL_;
SELECT     distinct l.ILL_id,ILL_lName,l.ILL_loanId, l.barcode,m.title,m.author  ,m.isbn,dateLoan
FROM       opl_ILL_out l inner join opl_item i using(barcode) inner join opl_marcRecord m using(rid)
WHERE      (ILL_loanId =? || ILL_id =? || barcode =? ) $statusCond
ORDER BY    id
_SQL_

    my $sth = $dbh->prepare($sql);
    $sth->execute($inputVal,$inputVal,$inputVal);
    my $prevIllId=-1;
    my $illInfoList=[];
    my $i=-1;
    while (my $rec = $sth->fetchrow_hashref) {
        if($prevIllId != $rec->{'ILL_id'}){
            $i++;
            $rec->{"bookcover"}="/bin/search/frontcover?size=m&isbn=" .$rec->{"isbn"};
            $illInfoList->[$i]=$rec;
            $illInfoList->[$i]->{'totalLoan'}=0;
            $illInfoList->[$i]->{'loanList'}=[];
             $prevIllId = $rec->{"ILL_id"};
        }
        push @{$illInfoList->[$i]->{'loanList'}},{loanId=>$rec->{'ILL_loanId'},
                                                  loanDate=>$rec->{'dateLoan'},
                                                  req_lName=>$rec->{'ILL_lName'},
                                                  ILL_itemBc=>$rec->{'barcode'}};
        $illInfoList->[$i]->{'totalLoan'} +=1;

    }
    
    $sth->finish;
    return $illInfoList;
    
}

#===========================================================================
sub ill_res_lookup_union{
    my ($dbh,$input)=@_;
    my $illInfoList=[];
    my $illId=$input->{'illId'}|| '';
    my $loanId=$input->{'loanId'}|| '';
    my $barcode=$input->{'barcode'}|| '';
    my $status=$input->{'status'}|| '';

    my $svcName="res_illInfoLookup";
    my $msgXml= sprintf "<illMsg><serviceName>%s</serviceName><unionId>%s</unionId><loanStatus>%s</loanStatus><illId>%s</illId><loanId>%s</loanId><barcode>%s</barcode></illMsg>",
                            $svcName,$ill_unionId,$status,$illId,$loanId,$barcode;
   my $rs=http_post($url,[illMsg=>$msgXml]); 
   if($rs->{'status'} eq '1'){
       $illInfoList= _illRsParser($rs->{'content'});
       foreach my $ill(@$illInfoList){
            $ill->{'bookcover'}="/bin/search/frontcover?size=m&isbn=" .$ill->{"isbn"};
       }
   }
   return $illInfoList;
                           
}

#===========================================================================
#  
sub ill_res_lookupBy_illId{
    my ($dbh,$inputVal,$status)=@_;
    my $statusCond="";
    if(scalar(@$status)>0){
        foreach my $s(@$status){
            $s= "status='$s'";
        }
        $statusCond=" && (" . join(" || ",@$status) .")";
    }
    my $sql = <<_SQL_;
SELECT     l.*, m.title,m.author  
FROM       opl_ILL_out l inner join opl_item i using(barcode) inner join opl_marcRecord m using(rid)
WHERE      ILL_id =?  $statusCond
ORDER BY    id
_SQL_

    my $sth = $dbh->prepare($sql);
    $sth->execute($inputVal);
    my @retVal;
    while (my $rec = $sth->fetchrow_hashref) {
          push @retVal, $rec;
    }
    
    $sth->finish;
    return \@retVal;
    
}
#===========================================================================
#  
sub ill_res_lookupBy_loanId{
    my ($dbh,$inputVal)=@_;
    my $ret=undef;
    my $sql = <<_SQL_;
SELECT     l.*, m.title,m.author  
FROM       opl_ILL_out l inner join opl_item i using(barcode) inner join opl_marcRecord m using(rid)
WHERE      ILL_loanId =? 
ORDER BY    id
_SQL_

    my $sth = $dbh->prepare($sql);
    $sth->execute($inputVal);
    if(my $rec = $sth->fetchrow_hashref) {
          $ret=$rec;
    }
    
    $sth->finish;
    return $ret;
    
}

#===========================================================================
#  
sub ill_res_lookupBy_barcode{
    my ($dbh,$inputVal)=@_;
    my $ret=undef;

    my $sql = <<_SQL_;
SELECT     l.*, m.title,m.author  
FROM       opl_ILL_out l inner join opl_item i using(barcode) inner join opl_marcRecord m using(rid)
WHERE       barcode =? 
ORDER BY    id
_SQL_

    my $sth = $dbh->prepare($sql);
    $sth->execute($inputVal);
    if(my $rec = $sth->fetchrow_hashref) {
          $ret=$rec;
    }
    
    $sth->finish;
    return $ret;
    
}

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

1;
