#!/usr/bin/perl

#use utf8;
use strict;
use CGI;

use Opals::Context;use POSIX qw(
    floor
);

use Time::localtime;
use Opals::Constant;

use Opals::Template qw(
    tmpl_read
    tmpl_write
    tmpl_preference
);
use Opals::User qw(
    user_list
    user_getInformationById
    user_balance
);
use Opals::Circulation qw(
    circ_placeReserve
    circ_fillReserve
    circ_cancelReserve
    circ_cancelHold_all
    circ_placeHold
    circ_userListReserve
    circ_GetLostNumber
    circ_GetDamagedNumber
    circ_numActiveItem
    circ_getRecInfo
    circ_getReserveID
    circ_numItemsAvailable
    circ_getRecID
    Circ_validateFollettBarcode
    Circ_validateSpectrumBarcode
    Circ_validateLeadingZeroBc
    circ_cancelHoldReserve
    circ_getReserveInfo
);



use Opals::Date qw(
    date_parse
    date_today
    date_text
    date_validateWorkday
    date_deltaWorkDay
    date_addDeltaWorkday
    date_getDeadLineDate
);
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        => 'circ/reserve.tmpl',
            reqPermission   => 'circ_rsrv|circ_rsrv_self',
        }
);
my $syspref = tmpl_preference($dbh);
my $validateBc = $syspref->{'validateBarcode'};
my $barcodeType = $syspref->{'barcodeType'}; 
my $circulationSound = $syspref->{'circulationSound'}; 
my @cookieList = ($cookie);

my $tm = localtime;
my $todayStr = sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);

my ($bc,$rid,@ridArr, @ncrArr,$op, $dateExpiry);
$bc             = $cgi->param('bc');
$op             = $cgi->param('op');
$dateExpiry     = $cgi->param('dExpiry');
@ridArr         = ($cgi->param('rid'));
@ncrArr         = ($cgi->param('ncr'));

if ($permission && ($permission->{'circ_rsrv_self'} || $permission->{'circ_rsrv'})) {
    my ($uid, $reserve);
    # user has permission to reserve for others
    if ($permission->{'circ_rsrv'}) {
        $template->param(circ_rsrv => 1);
        $uid=getUID();
    }
    # self-reserve only
    else {
        $uid = $template->param('curUserId');
    }
  
    if($bc ne '' ){
        $bc    =~ s/^\s+|\s+$//g;
        $bc= validateBc($dbh,$bc,$barcodeType) if($validateBc eq '1');
        $rid = circ_getRecID($dbh,$bc);
        my $recInfo  = circ_getRecInfo($dbh, $rid, $uid);
        if($recInfo->{'reservePeriod'}>0){
                push @ridArr,$rid ;
                push @ncrArr,1;
        }
        else{
           $template->param(
                reserveNotAllow =>1,
                title        => $recInfo->{'title'},      
                author       => $recInfo->{'author'},
                pubName      => $recInfo->{'pubName'},
                pubDate      => $recInfo->{'pubDate'}
           ); 
        }
    }
  
    # Do operation 
    my ($reserveExist,$reserveStatus,$reserveExpiry,$numHold,$holdExpiry)=(0,0,"",0,"" );
    if ($op eq 'placeReserve'  && $uid && $uid >= 0 && scalar(@ridArr)) {
        my @reserveRsList=();
        my ($reserveMsg1,$reserveMsg2,$reserveMsg3)=(0,0,0);
        for(my $i=0; $i < scalar(@ridArr); $i++){
            ($reserveMsg1,$reserveMsg2,$reserveMsg3)=(0,0,0);
            my $recInfo  = circ_getRecInfo($dbh, @ridArr[$i], $uid);
            if(!$recInfo->{'title'} || $recInfo->{'title'} eq ''){
                next;
            }

            my $idReserve= circ_getReserveID($dbh,@ridArr[$i],$uid);
            if($idReserve) {
              $reserveExist=1;
            }
            else{
                 if(!@ncrArr[$i] || @ncrArr[$i] eq '' ) {
                     @ncrArr[$i]=1;
                 }
                 ($reserveStatus,$reserveExpiry,$numHold,$holdExpiry) =doReserve($dbh, $uid, $recInfo, @ncrArr[$i],$dateExpiry);
                
                if($numHold==0){
                    $reserveMsg1= 1;
                }
                elsif($numHold==@ncrArr[$i]){
                    $reserveMsg2= 1 ;
                }
                else{
                    $reserveMsg3= 1;
                }
            }    
            my $msgValMap={
                    reserve_msg_04=>{dueDate=>$holdExpiry},
                    reserve_msg_05=>{noReserve=>@ncrArr[$i]-$numHold,dueDate=>$reserveExpiry},
                    reserve_msg_06=>{noHold=>$numHold,dueDate=>$holdExpiry},
                    };
            my $reserveMsgMap =loc_getMsgFile('circ/reserve.msg',$msgValMap);

            push @reserveRsList, {
                reserveExist => $reserveExist,
                reserveFail  =>$reserveStatus?0:1,
                title        => $recInfo->{'title'},      
                author       => $recInfo->{'author'},
                pubName      => $recInfo->{'pubName'},
                pubDate      => $recInfo->{'pubDate'},
                numReserve   => $ncrArr[$i]-$numHold,
                reserveExpiry   => $reserveExpiry,
                reserveHold  => $numHold?1:0,
                numHold      => $numHold,
                holdExpiry   => $holdExpiry,
                reserveMsg_01=>$reserveMsg1,
                reserveMsg_02=>$reserveMsg2,
                reserveMsg_03=>$reserveMsg3,
                reserve_msg_04=>$reserveMsgMap->{'reserve_msg_04'},
                reserve_msg_05=>$reserveMsgMap->{'reserve_msg_05'},
                reserve_msg_06=>$reserveMsgMap->{'reserve_msg_06'},
                dateExpiry =>$dateExpiry,
            };
        }

        $template->param(reserveRsList=> \@reserveRsList );
    }
    elsif ($op eq 'cancelReserve') {
        my @cancelRs=();
        for (my $i=0; $i < $input->{'totalid'}; $i++ ) {
                my $idReserve=$input->{'idrsrv' . $i};
                my $reserveInfo = circ_getReserveInfo($dbh,$idReserve );
                if($idReserve>0){
                    my $recInfo  = circ_getRecInfo($dbh, $reserveInfo->{'rid'} );
                    my $userOnholdList =circ_cancelHoldReserve($dbh,$idReserve,$todayStr);
                    $recInfo->{'holdList'}=$userOnholdList;
                    push @cancelRs,$recInfo;
                }
        }

        $template->param(rCancel => 1,cancelRs=>\@cancelRs);
    }
    if (scalar(@ridArr)) {
        my $itemList =get2ReserveItemList($dbh,\@ridArr,\@ncrArr);
        $template->param(itemList =>$itemList);
    }


    if ($op eq 'placeReserve' && !$template->param('rError')) {
        $rid = 0; $template->param(result => 1);
    }

    my $sortField = 'title';
    if( $input->{'sortField'}) {
       $sortField  = $input->{'sortField'};
    }

    my $sortDir   =  '';
    if( $input->{'sortDir'}){
       $sortDir = "$input->{'sortDir'}";
    };
    $template->param(
       sortField => $sortField,
       sortDir   => $sortDir,
    );


    if($sortDir eq 'desc' ){
        $template->param(sortDown =>1 );
    }
    else{
        $template->param(sortUp =>1 );
    }
  
    if ($uid && $uid>=0) {
        getUserInfo($dbh, $uid,$sortField,$sortDir);
    }
    if ($uid>=0 ) { $template->param(checkid => 1); }
}
else {
    $template->param(
        input => [
            {name => 'rid', value => $ridArr[0],},
            {name => 'op',  value => $op,},
            {name => 'de',  value => $dateExpiry,},
            {name => 'ncr', value => $ncrArr[0]},
        ],
    );
}
   if($circulationSound){
        $template->param(circSound     =>1); 
    }

    my $user_firstname = $template->param('user_firstname');
    my $user_lastname = $template->param('user_lastname');
    my $numReserve    = $template->param('numReserve');
    my $holdExpiry    = $template->param('holdExpiry');
    my $reserveExpiry = $template->param('reserveExpiry');
    my $numHold    = $template->param('numHold');
    my $msgValMap={
                    reserve_msg_04=>{dueDate=>$holdExpiry},
                    reserve_msg_05=>{noReserve=>$numReserve,dueDate=>$reserveExpiry},
                    reserve_msg_06=>{noHold=>$numHold,dueDate=>$holdExpiry},
                    reserve_msg_07=>{user_firstname=>$user_firstname,user_lastname=>$user_lastname}
                    };
    my $reserveMsgMap =loc_getMsgFile('circ/reserve.msg',$msgValMap);
    loc_write($template,$reserveMsgMap);


    
$template->param(circulation=>1);
$template->param(hlpUrl     => Opals::Constant->getHlpUrl('reserve') );
tmpl_write($dbh, $cgi, \@cookieList, $template);
#########################################################################

sub validateBc{
    my($dbh,$barcode,$barcodeType) =@_;
   if($barcodeType eq '1'){#follett
        $barcode  = Circ_validateFollettBarcode($dbh,$barcode );
    }
    elsif($barcodeType eq '2'){#spectrum
        $barcode  = Circ_validateSpectrumBarcode($dbh,$barcode );
    }
    elsif($barcodeType eq '3'){#leading zero
        $barcode  = Circ_validateLeadingZeroBc($dbh,$barcode );
    }

    #else{#follett
    #    $barcode  = Circ_validateFollettBarcode($dbh,$barcode );
    #}
    return $barcode;
   
}
################################################################################
sub doReserve{
    my($dbh, $uid, $recInfo, $numCopyReserve,$dateExpiry)=@_;
    
    my $rid=$recInfo->{'rid'};
    my $numHold=0;
    my $holdExpiry="";

    if(!$dateExpiry || $dateExpiry eq''){
        $dateExpiry = date_getDeadLineDate($recInfo->{'reservePeriod'}, $todayStr);
    }

  
    my $reserve = circ_placeReserve($dbh, $uid, $rid, $numCopyReserve, $todayStr, $dateExpiry );
    
    if(!$reserve ){
        return (0,$dateExpiry,$numHold,$holdExpiry);
    }
    my $numItemAvailable = circ_numItemsAvailable($dbh,$rid);
    if($numItemAvailable) {
        my $idReserve  = circ_getReserveID($dbh, $rid, $uid);
        $holdExpiry = date_getDeadLineDate($recInfo->{'holdPeriod'}, $todayStr);
        my $loopEnd = $numItemAvailable < $numCopyReserve ? $numItemAvailable:$numCopyReserve;
        $numHold=$loopEnd;
        for(my $i=0; $i<$loopEnd;$i++){
            circ_fillReserve($dbh,$uid,$rid);
            circ_placeHold($dbh, $idReserve,$todayStr,$holdExpiry);
        }
        $dateExpiry=$numHold==$numCopyReserve?"":$dateExpiry;
    }
    $dateExpiry =~ s/\s23:59:59$//g;
    $holdExpiry =~ s/\s23:59:59$//g;
    return (1,$dateExpiry,$numHold,$holdExpiry);
}


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


sub getUID{
    my $uid=-1;
    if ( $input->{'uInput'}) {
        # my @uList = user_list($dbh,  $input->{'uInput'}, USER_ACTIVE);
        my @uList = user_list($dbh,  $input->{'uInput'}, '');
        if(scalar(@uList)==1){
            #$uid = $uList[0]->{'uid'};
           if( @uList[0]->{'status'}==1 ){
               $uid = $uList[0]->{'uid'};
               $template->param(block =>0);
               @uList[0]->{'block'}=  0;
           }
           else {
               $template->param(block =>1);
           }
            $template->param(uPerson => 1);
        }
        elsif(scalar(@uList)>=1){
            for(my $i=0; $i < scalar(@uList) ; $i++){
                @uList[$i]->{'block'}= @uList[$i]->{'status'}==1 ? 0:1;
            }
           # $template->param(uList => \@uList);
        } 
     $template->param(uList => \@uList);
    }
    elsif ( $input->{'InputFromList'}){
        $uid = $input->{'InputFromList'};
    }
    else{
        if ( $input->{'hiddenid'} ) { 
            $uid = $input->{'hiddenid'}; 
        }
        else { $uid = $cgi->cookie('borrower');
        }
    }    return $uid;
}

##########################################################
sub getUID_bk{
    my $uid=-1;
    if ( $input->{'uInput'}) {
        my @uList = user_list($dbh,  $input->{'uInput'}, USER_ACTIVE);
        if(scalar(@uList)==1){
            $uid = $uList[0]->{'uid'};
        }
        elsif(scalar(@uList)>1){
            $template->param(uList => \@uList);
        }
     }
    elsif ( $input->{'InputFromList'}){
        $uid = $input->{'InputFromList'};
    }
    else{
        if ( $input->{'hiddenid'} ) { 
            $uid = $input->{'hiddenid'}; 
        }
        else { $uid = $cgi->cookie('borrower'); }
    }
    return $uid;
}

##########################################################
sub getUserInfo{
    my ($dbh, $uid,$sortField,$sortDir)=@_;

    my ($userInfo, $guardian) = user_getInformationById($dbh, $uid);
    my $balance = user_balance($dbh, $userInfo->{'uid'});
    $balance = floor($balance*100 + 0.5)/100; 
    my $showFine = ($syspref->{'charge_overdue'} || $balance) ? 1:0;
    
    GetReservedItems($dbh, $template, $userInfo->{'uid'},$sortField,$sortDir);
    
    $template->param(
        user_uid        => $userInfo->{'uid'},
        user_barcode    => $userInfo->{'userbarcode'},
        user_username   => $userInfo->{'username'},
        user_firstname  => $userInfo->{'firstname'},
        user_lastname   => $userInfo->{'lastname'},
        balance         => $balance,
        lost            => circ_GetLostNumber($dbh, $userInfo->{'uid'}),
        damaged         => circ_GetDamagedNumber($dbh, $userInfo->{'uid'}),
        hiddenid        => $userInfo->{'uid'},
        showfine        => $showFine,
    );
}


###########################################################
sub GetReservedItems
{
    my ($dbh, $template, $uid,$sortField,$sortDir) = @_;
    
    my $reserveList = circ_userListReserve($dbh, $uid);
    my $order = 0;
    foreach my $reserve (@$reserveList) 
    {
        $reserve->{'order'} = $order++;
        $reserve->{'dateReserve'} = date_text($reserve->{'dateReserve'}, 0);
        $reserve->{'dateExpiry'}  = date_text($reserve->{'dateExpiry'}, 0);
        if($reserve->{'numCopyReserve'}==0){
            $reserve->{'dateExpiry'}  ='';
        }
    }
    @$reserveList = sort {
            if ($sortField eq 'title'){
                 if ($sortDir eq 'desc'){
                      $b->{'titleSort'} <=> $a->{'titleSort'}
                   || lc($b->{'titleSort'}) cmp lc($a->{'titleSort'})
                 }
                 else{
                      $a->{'titleSort'} <=> $b->{'titleSort'}
                   || lc($a->{'titleSort'}) cmp lc($b->{'titleSort'})
                }
            }
    } @$reserveList;
    $template->param(NumOfReserves => scalar(@$reserveList));
    $template->param(reserveList => \@$reserveList);
}


##########################################################
sub getDeadLineDate{
    my ($lengthDay,$dateStr)= @_;
    my $retDate;
    
    my $ddate = date_parse($dateStr);
    $ddate = date_today() unless ($ddate);
    $ddate = date_addDeltaWorkday($ddate, $lengthDay);
    $ddate = date_validateWorkday($ddate,$lengthDay);
    my ($year,$month,$day) = $ddate->date();
    $retDate = sprintf("%04d-%02d-%02d 23:59:59",$year,$month,$day);
    return $retDate;
}

##########################################################
# Mon, Jan 03, 2011 @ 14:47:26 EST

sub get2ReserveItemList{
    my ($db,$ridArr,$ncrArr)=@_;
    my $itemList=[];
    if(scalar(@$ridArr)>0){
        my $ridList=join(",", @$ridArr);
        my $sth=$dbh->prepare(<<_SQL_);
select r.rid, title,author,pubName,pubDate,count(barcode) numItem 
from opl_marcRecord r inner join opl_item using(rid)  
where rid =? group by rid 
_SQL_

        for(my $i=0; $i<scalar(@$ridArr);$i++){
           $sth->execute(@$ridArr[$i]);
           if(my $item=$sth->fetchrow_hashref){
               $item->{"ncr"}=@$ncrArr[$i];
               push @$itemList,$item;
           }
        }
        $sth->finish;
    }
    return $itemList;
    
}
