package Opals::WebServiceClient;

require Exporter;
@ISA       = qw(Exporter);

@EXPORT_OK = qw(
    wsc_sendNextUpdateRequest2Union
    wsc_sendCircData
    wsc_getCircData
    wsc_getLibInfo
    wsc_requestILL
    wsc_getIllLoanInfo
    wsc_updateHostURL

    wsc_ebookAuth
    wsc_uploadEbook
    wsc_getEbook
    wsc_getFile
    wsc_deleteEbook

    wsc_updateEbookLicense
    wsc_deleteEbookLicense
    wsc_getLicense
    wsc_getLicenseList
    wsc_searchEbook

);

# Version number
$VERSION   = 0.01;      

use strict;
use Encode;
use Opals::MarcXml qw(
    mxml_exportRecord
    mxml_exportHolding
);
use Opals::UnionRequest qw(
    urq_updateUnionRequestStatus
);



use Opals::XML::SAX::CircData;
use Opals::XML::SAX::ILL;
use Opals::XML::SAX::Library;
use Opals::XML::SAX::SolrRsHandler;
use Opals::XML::SAX::UploadRsHandler;
use Opals::XML::SAX::LicenseListHandler;
use Opals::XML::SAX::EbookDataHandler;

use LWP::UserAgent;
use HTTP::Request::Common;

my $zRoot       = Opals::Context->config('zRoot');
my $zPort       = Opals::Context->config('zPort');
my $zDatabase   = Opals::Context->config('zDatabase');
my $unionId     = Opals::Context->preference('unionId');
my $unionSvcUrl = Opals::Context->preference('unionSvcUrl');
   $unionSvcUrl =~ s/\/+$//g;


$| = 1;


#============================================================

#sub http_post{
#        my ($post_url,$unionId,$updateType,$reqId,$fileName,$totalRecord,$totalHolding) = @_;
#        my $ua = LWP::UserAgent->new();
#        $ua->agent('OPALS Union update user client');
#        $ua->timeout(120);
#        my $result={status=>0,error=>""};
#        my $response = $ua->request(POST "$post_url",
#            Content_Type => 'multipart/form-data', 
#            Content=>[unionId=>$unionId,
#                      requestId=>$reqId,
#                      updateType=>$updateType,
#                      totalRecord=>$totalRecord,
#                      totalHolding=>$totalHolding,
#                      datafile=>[$fileName]]
#            );
#        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;
#                   }
#                }
#            }
#         }
#         return $result;
#}


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

    my $ua = LWP::UserAgent->new();
    $ua->agent('OPALS 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;
                }
            }
        }
        elsif ($response->is_success) {
            $result->{'status'}= 1;
        }

        $result->{'content'} = $responseXml;
    }

    return $result;
}

#============================================================
sub wsc_sendNextUpdateRequest2Union{
    my ($dbh) = @_;
    #my ($dbh,$unionSvcUrl,$unionId)=@_;

    my ($autoUpdateUnion) = Opals::Context->preference('autoUpdateUnion');
#    my ($autoUpdateUnion) = $dbh->selectrow_array(<<_SQL_);
#select  val
#from    opl_preference
#where   var='autoUpdateUnion'
#_SQL_
#
#    my ($unionSvcUrl) = $dbh->selectrow_array(<<_SQL_);
#select  val
#from    opl_preference
#where   var='unionSvcUrl'
#_SQL_

#    my $unionId = Opals::Context->preference('unionId');

    if (!$autoUpdateUnion || !$unionSvcUrl ||
        $unionSvcUrl !~ m/^http:\/\/[A-z0-9_\-]+(\.[A-z0-9_\-])+/) {
        return;
    }

    my $url = "$unionSvcUrl/bin/svc/unionUpdateSvc";

    my $sth=$dbh->prepare(<<_SQL_);
select r.id ,r.reqType
from   opl_unionRequest r 
where  r.status='pending' 
order by r.id limit 1
_SQL_

    $sth->execute();
    if(my ($reqId,$reqType)=$sth->fetchrow_array){
        my ($fileName,$totalRecord,$totalHolding)=("",0,0);
        if($reqType eq 'deletion'){
             ($fileName,$totalHolding) = createUnionUpdateFile_deletion($dbh,$reqId)
        }
        else{
            ($fileName,$totalRecord,$totalHolding) = createUnionUpdateFile_import($dbh,$reqId);
        }
        if($fileName ne ""){
            #my $response =http_post($unionSvcUrl,$unionId,$reqType,$reqId,$fileName,$totalRecord,$totalHolding);
            my $postContent = [
                unionId     => Opals::Context->preference('unionId'),#$unionId,
                requestId   => $reqId,
                updateType  => $reqType,
                totalRecord => $totalRecord,
                totalHolding=> $totalHolding,
                datafile    => [$fileName]
            ];
            my $response = http_post($url, $postContent);
            my $errorMsg="";
             $errorMsg =$response->{'status'} . " : " . $response->{'error'} if($response->{'status'} ne '1');
             urq_updateUnionRequestStatus($dbh,$reqId,'sent',$response->{'error'});
                        
        }

    }


}
#============================================================
sub  createUnionUpdateFile_deletion{
     my ($dbh,$reqId)=@_;
     my $fileName="/tmp/$zDatabase" . "_unionUpdate_$reqId";
     my $totalHolding=0;
     open DEL_BC_FILE ,">$fileName";

 my $sth=$dbh->prepare(<<_SQL_);
select barcode
from   opl_unionRequestDetail
where  reqId= ?  
order by id 
_SQL_
    
   $sth->execute($reqId);
    while(my ($bc)=$sth->fetchrow_array){
        print  DEL_BC_FILE "$bc\n";
        $totalHolding++;
    }
     close DEL_BC_FILE;
    $sth->finish;
   return ($fileName,$totalHolding);
}
#============================================================
sub  createUnionUpdateFile_import{
     my ($dbh,$reqId)=@_;
     my $fileName="/tmp/$zDatabase" . "_unionUpdate_$reqId";
     open DEL_BC_FILE ,">$fileName";
     print DEL_BC_FILE "<collection>\n";

    my $sth=$dbh->prepare(<<_SQL_);
select distinct rid
from   opl_unionRequestDetail
where  reqId= ?  
order by id 
_SQL_

    $sth->execute($reqId);
    my ($rid,$marcXml)=(0,"");
    my ($totalRecord,$totalHolding)=(0,0);
    while ( ($rid)=$sth->fetchrow_array){
        $totalRecord++;
        my $sth_detail =$dbh->prepare("select barcode from opl_unionRequestDetail where
        rid=? && reqId=?");
        $sth_detail->execute($rid,$reqId);
        my $bcList;
        while(my ($bc) =$sth_detail->fetchrow_array){
            $bcList->{$bc}=1;
            $totalHolding++;
        }
        if(scalar(keys %{$bcList}) > 0 ){
            my ($xml,$cFixed)=mxml_exportRecord($zRoot, $zPort, $zDatabase, $rid);
            $marcXml = mxml_exportHolding($xml,$bcList); 
            print DEL_BC_FILE $marcXml,"\n" ;
        }

    }
    $sth->finish;
     print DEL_BC_FILE "</collection>\n";
     close DEL_BC_FILE;
     return ($fileName,$totalRecord,$totalHolding);
}


################################################################################
sub wsc_sendCircData {
    my ($dbh) = @_;

    my $unionCircUpdate = Opals::Context->preference('unionCircUpdate');

    if (!$unionCircUpdate || !$unionSvcUrl ||
        $unionSvcUrl !~ m/^http:\/\/[A-z0-9_\-]+(\.[A-z0-9_\-])+/) {
        return;
    }

    my $url = "$unionSvcUrl/bin/svc/updateLoan";

    my $loanList = getLoanList($dbh);
    if (!$loanList) {
        return;
    }

    my $xml = <<_STR_;
<?xml version="1.0" encoding="UTF-8"?>
<loanList>
$loanList
</loanList>
_STR_

#    print <<_STR_;
#$unionId
#$unionSvcUrl
#
#$xml
#_STR_

    my $postContent = [
        libKey  => $unionId,
        loanList=> $xml
    ];
    my $response = http_post($url, $postContent);

    if($response->{'status'} > 0){
           $dbh->do(<<_SQL_);
update  opl_preference
set     val = now()
where   var = 'unionCircUpdateDate'
_SQL_
    }
}


################################################################################
sub getLoanList {
    my ($dbh) = @_;

    my $unionCircUpdateDate = Opals::Context->preference('unionCircUpdateDate');
#    $dbh->do(<<_SQL_);
#update  opl_preference
#set     val = now()
#where   var = 'unionCircUpdateDate'
#_SQL_

    my $sql = <<_SQL_;
select  *
from    opl_loan
where   (dateLoan >= ? || dateReturn >= ?)
_SQL_
#     && type = 'Library'

    my $key = 'idloan';
    my @param = ($unionCircUpdateDate, $unionCircUpdateDate);
    my $loan = $dbh->selectall_hashref($sql, $key, undef, @param);

    my $xml_str = '';
    foreach my $id (sort keys %{$loan}) {
        my $l = $loan->{$id};
        foreach my $k (keys %{$l}) {
            (defined $l->{$k}) || ($l->{$k} = '');
        }
        $xml_str .= <<_STR_;
    <loan
        id="$l->{'idloan'}"
        uid="$l->{'uid'}"
        barcode="$l->{'barcode'}"
        maxRenewal="$l->{'maxRenewal'}"
        dLoan="$l->{'dateLoan'}"
        dDue="$l->{'dateDue'}"
        dRenewal="$l->{'dateRenewal'}"
        dReturn="$l->{'dateReturn'}"
        cRenewal="$l->{'renewalCount'}"
        fineRate="$l->{'finerate'}"
        status="$l->{'status'}"
    />
_STR_
    }

    return $xml_str;
}


################################################################################
sub wsc_getCircData {
    my ($host, $ridList) = @_;

    if (!$host ||
        $host !~ m/^[\w\-]+(\.[\w\-])+/) {
        return;
    }

    my $url = "http://$host/bin/svc/getCircData";

    my $postContent = [
        ridList => $ridList
    ];
    my $response = http_post($url, $postContent);
    my $circData = $response->{'content'} || return;

    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::CircData->new
    );
    $parser->parse_string($circData);

    return $parser->{'Handler'}->{'circData'};
}


################################################################################
sub wsc_getLibInfo {
    my (%param) = @_;
    my $host        = $param{'host'};
    my $lidList     = $param{'lidList'};
    my $locationId  = $param{'locationId'};
#    my $sys_code    = $param{'sys_code'};
    my $loc_code    = $param{'loc_code'};

    if (!$host ||
        $host !~ m/^[\w\-]+(\.[\w\-])+/) {
        return;
    }

    my $url = "http://$host/bin/svc/getLibInfo";

    my $postContent = [
        lidList     => $lidList,
        locationId  => $locationId,
#        sys_code    => $sys_code,
        loc_code    => $loc_code
    ];
    my $response = http_post($url, $postContent);
    my $libInfo = $response->{'content'} || return;

    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::Library->new
    );
    $parser->parse_string($libInfo);

    return $parser->{'Handler'}->{'library'};
}


################################################################################
sub wsc_requestILL {
    my ($host, $requests) = @_;

    if (!$host ||
        $host !~ m/^[\w\-]+(\.[\w\-])+/) {
        return;
    }

    my $url = "http://$host/bin/svc/requestILL";

    my $postContent = [
        requests => $requests,
    ];
    my $response = http_post($url, $postContent);
    my $ILL_info = $response->{'content'} || return;

    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::ILL->new
    );
    $parser->parse_string($ILL_info);

    return $parser->{'Handler'}->{'requests'};
}


# EBOOK ###########


################################################################################
#  Wed, Jun 12, 2013 @ 10:08:08 EDT
#
sub wsc_ebookAuth{
    my($authInfo)=@_;
    my $ebs_host        = $authInfo->{'ebs_host'};
    $authInfo->{'serviceName'}="authenticate";
    my $url="http://$ebs_host/bin/ws/eService";
    my $response = http_post($url, $authInfo);
    my $rs = $response->{'content'} || return undef;
    my $sessionID="";
    if($rs =~ m/<status>(.*?)<\/status>/){
        if($1==1){
            if($rs =~ m/<sessionID>(.*?)<\/sessionID>/){
                $sessionID=$1;
            }
        }
    }
    return $sessionID;

}

################################################################################
# Wed, Jun 12, 2013 @ 10:08:20 EDT
# 
sub wsc_uploadEbook{
    my($params)=@_;
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="uploadEpub";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::UploadRsHandler->new
    );
    $parser->parse_string($rs);
    return $parser->{'Handler'};



}
################################################################################
sub wsc_updateEbookLicense{
    my($params)=@_;
    my $ret={};
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="updateLicense";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
    if($rs =~ m/<errorCode>(.*?)<\/errorCode>/){
        $ret->{'errorCode'}=$1;
        if($1==0){
            if($rs =~ m/<licenseID>(.*?)<\/licenseID>/){
                $ret->{'licenseID'}=$1;
            }
        }
    }
    return $ret;
}

################################################################################
sub wsc_deleteEbookLicense{
    my($params)=@_;
    my $ret={};
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="deleteLicense";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
    if($rs =~ m/<errorCode>(.*?)<\/errorCode>/){
        $ret->{'errorCode'}=$1;
        if($1==0){
            if($rs =~ m/<licenseID>(.*?)<\/licenseID>/){
                $ret->{'licenseID'}=$1;
            }
        }
    }
    return $ret;

}

################################################################################
sub wsc_getLicense{
   my($params)=@_;
    my $ret={};
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="getLicense";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
    if($rs =~ m/<errorCode>(.*?)<\/errorCode>/){
        $ret->{'errorCode'}=$1;
        if($1==0){
            if($rs =~ m/<licenseType>(.*?)<\/licenseType>/){
                $ret->{'licenseType'}=$1;
            }
            if($rs =~ m/<totalLicense>(.*?)<\/totalLicense>/){
                $ret->{'totalLicense'}=$1;
            }
        }
    }
    return $ret;

}
################################################################################
sub wsc_getLicenseList{
   my($params)=@_;
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="getLicenseList";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
   
    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::LicenseListHandler->new
    );
    $parser->parse_string($rs);
    return $parser->{'Handler'}->{'licenseList'};

}
#################################################################################
sub wsc_deleteEbook{
    my($params)=@_;
    my $ret={};
    my $ebs_host        = $params->{'ebs_host'};
    my $url="http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="deleteEbook";
    my $response = http_post($url, $params);
    my $rs = $response->{'content'} || return undef;
    if($rs =~ m/<errorCode>(.*?)<\/errorCode>/){
        $ret->{'errorCode'}=$1;
        if($1==0){
            if($rs =~ m/<lid>(.*?)<\/lid>/){
                $ret->{'lid'}=$1;
            }
            if($rs =~ m/<bid>(.*?)<\/bid>/){
                $ret->{'bid'}=$1;
            }
        }
    }
    return $ret;

  }


#################################################################################
sub wsc_getEbook{
    my($params)=@_;
    my $ret=undef;
    my $ebs_host    = $params->{'ebs_host'};
    my $url     = "http://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="getEbook";
    my $response = http_post($url, $params);
    my $rsXml = $response->{'content'} || return undef;
    
    if($rsXml =~ m/<errorCode>(.*?)<\/errorCode>/){
         my $parser = XML::SAX::ParserFactory->parser(
                Handler => Opals::XML::SAX::EbookDataHandler->new
               );
        $parser->parse_string($rsXml);
        $ret->{'metadata'}=$parser->{'Handler'}->{'metadata'};
        $ret->{'TOC'}=$parser->{'Handler'}->{'TOC'};
        my @spineArr=@{$parser->{'Handler'}->{'spine'}};
        my $spine=[];
        foreach my $s(@spineArr){
            push @$spine,{spineItem=>$s};
        }
        $ret->{'spine'}=$spine;
    }
    return $ret;
}
#################################################################################
sub wsc_getFile{
    my($params)=@_;
    my $ebs_host    = $params->{'ebs_host'};
    my $url     = "https://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="getFile";
    my $response = http_post($url, $params);
    my $rsXml = $response->{'content'} || return (undef,undef);
    my $mineType=$response->{'content-type'}  ;
    return ($rsXml,$mineType);
}

#################################################################################
sub wsc_searchEbook{
    my($params)=@_;
    my $ebs_host    = $params->{'ebs_host'};
    my $url     = "https://$ebs_host/bin/ws/eService";
    $params->{'serviceName'}="searchEbook";
    my $response = http_post($url, $params);
    my $rs = _parseSearchRs($response->{'content'}) || return undef;
}
#////////////////////////////////////////////////////////////////////////////
sub _parseSearchRs{
    my($rsXml)=@_;
    my $parser = XML::SAX::ParserFactory->parser(
        Handler => Opals::XML::SAX::SolrRsHandler->new
    );
     $parser->parse_string($rsXml);
     my $hits=$parser->{'Handler'}->getHits();
     my $result=$parser->{'Handler'}->getResult();
     my $facet=$parser->{'Handler'}->getFacetFields();
     my $license=$parser->{'Handler'}->getLicense();
     foreach  my $r(@$result){
        $r->{'licenseType'} =$license->{$r->{'bid'}}->{'type'};
        $r->{'totalLicense'}=$license->{$r->{'bid'}}->{'total'};
     }
    return  { hits=>$hits,recordList=>$result,facet=>$facet};

}
###############################################################################
sub wsc_getIllLoanInfo {
    my ($dbh,$loanId) = @_;
    my $illLoanInfo={};
    my $url = "$unionSvcUrl/bin/svc/illWebSvc";
    my $illMsgXmlTmpl="<illMsg><serviceName>illInfo</serviceName><unionId>%s</unionId><loanId>%s</loanId></illMsg>";
    my $unionId = Opals::Context->preference('unionId');
    my $illMsgXml = sprintf $illMsgXmlTmpl,$unionId,$loanId;
    my $postContent = [illMsg=> $illMsgXml];

    my $response = http_post($url,$postContent);

      #  open debug, ">/tmp/dd";print debug $response->{'status'};close debug;
    if($response->{'status'} eq '1'){
        my $xml=$response->{'content'};
        if($xml =~ m/<illLoanInfo>(.*)<\/illLoanInfo>/gs){
            my $tmp=$1;
            foreach my $f(qw(libarayId libraryName title author isbn 
                             pubDate pubPlace pubName sf852k sf852h sf852i)){
                if($tmp =~ m/<$f>(.*)<\/$f>/){
                    $illLoanInfo->{$f}=$1;
                }
            }
        }
    }
    return $illLoanInfo;
}
###############################################################################
sub wsc_updateHostURL {
    my ($dbh,$host) = @_;
    my $url = "$unionSvcUrl/bin/svc/illWebSvc";
    my $illMsgXmlTmpl="<illMsg><serviceName>updateHostURL</serviceName><unionId>%s</unionId><host>%s</host></illMsg>";
    my $unionId = Opals::Context->preference('unionId');
    my $illMsgXml = sprintf $illMsgXmlTmpl,$unionId,$host;
    my $postContent = [illMsg=> $illMsgXml];

    my $response = http_post($url,$postContent);

    #  open debug, ">/tmp/dd";print debug $response->{'status'};close debug;
    return ($response->{'status'} eq '1');
}
#////////////////////////////////////////////////////////////////////////////



1;
