#!/usr/bin/perl

#use utf8;
use strict;
use CGI;

use Opals::Context;
use Opals::Constant;
use POSIX qw(
    floor
);
use Time::localtime;
use Opals::Template qw(
    tmpl_read
    tmpl_write
    tmpl_preference
);
use Opals::Circulation qw(
    circ_getItemStatus
    circ_getItemInfo
    circ_getRecID
    circ_processLoan
    circ_processReturn
    circ_placeHold
    circ_cancelHold
    circ_cancelReserve
    circ_updateItemStatus
    circ_setAvailable
    circ_processRenew
    circ_userListLoan
    circ_userListReserve
    circ_GetLostNumber
    circ_GetDamagedNumber
    circ_lostDeclarating

    circ_record_ODL
    Circ_validateFollettBarcode
    Circ_validateSpectrumBarcode
    Circ_validateLeadingZeroBc

    circ_record_ODL_ext
);
use Opals::Transaction qw(
    trans_doReverseLost
    
);

use Opals::Date qw(
    date_parse
    date_today
    date_text
    date_validateWorkday
    date_deltaWorkDay
    date_addDeltaWorkday

    dateTime_parse
    date_now
    date_deltaWorkDayHour
);
use Opals::User qw(
    user_getInformation
    user_getInformationById
    user_balance
);
use Opals::Locale qw(
    loc_getMsgFile
    loc_write
);

use Opals::BarcodeMgmt qw(
    bcm_validateBc
);


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/inlibrary.tmpl',
            reqPermission   => 'circ_loan',
        }
);

my $syspref = tmpl_preference($dbh);
my $validateBc = $syspref->{'validateBarcode'}; 
my $barcodeType = $syspref->{'barcodeType'}; 
my $barcode = $input->{'bc'};
$barcode    =~ s/^\s+|\s+$//g;
if($validateBc eq '1'){
    $barcode= bcm_validateBc($dbh,$barcode,$barcodeType);
}

my $uid=$input->{'uid'};
        
my $loginuid = $template->param('curUserId');
unless ($permission && $permission->{'circ_loan'})
{
    $template->param(
        input => [
                    {name => 'bc', value => $barcode,},
                 ],
    );
    goto __END_OF_FILE;
}
 
#my $tm = localtime;
#my $todayStr = sprintf("%04d-%02d-%02d", $tm->year+1900, ($tm->mon)+1, $tm->mday);
my $todayStr = date_now() ;
if($barcode){
    processRecord($dbh,$barcode);
}

my $inLibraryMsgMap =loc_getMsgFile('circ/inLibrary.msg');
   loc_write($template,$inLibraryMsgMap);

$template->param(hlpUrl     => Opals::Constant->getHlpUrl('inlibrary') );
$template->param(circulation =>1);

__END_OF_FILE:

tmpl_write($dbh, $cgi, $cookie, $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 processRecord{
    my($dbh,$barcode)=@_;
    my $uid      =0;
        my $rid            = circ_getRecID($dbh,$barcode);
        my $itemInfo       = circ_getItemInfo($dbh, $barcode, 0);
        if($rid){
            my $itemCircStatus = circ_getItemStatus($dbh, $barcode, $uid);
            my $itemMsgCode    = getMsgCode_item($itemCircStatus,$uid);

           if($itemMsgCode eq '00' || $itemMsgCode eq '01' ) {
              $template->param('retInvalidItem' =>1);
            }
           elsif($itemMsgCode ge '11' &&  $itemMsgCode le '16'){
              my $return       = doReturn($dbh,$itemCircStatus->{'l_uid'}, $barcode,$todayStr);
           }
           elsif($itemMsgCode eq '03' ){
               circ_setAvailable($dbh,$barcode,IT_STAT_LOST);
               trans_doReverseLost($dbh,$barcode,$loginuid);
               $template->param('retLostItem' =>1);

           }
           elsif($itemMsgCode eq '02' ){
               circ_setAvailable($dbh,$barcode,IT_STAT_MISSING);
               $template->param('retMissingItem' =>1);
           }

           my $sth = $dbh->prepare(<<_SQL);
insert into opl_loan
set     uid         = 0,
        barcode     = ?,
        dateLoan    = timestamp(?),
        dateReturn  = timestamp(?),
        dateDue     = timestamp(?)
_SQL
      my $r_val = $sth->execute($barcode,$todayStr, $todayStr, $todayStr);
      $sth->finish;  
  

         }
        else{
            $template->param('msgItem_00' =>1,
                                msgCode=>1);
        }  
}
#-------------------------------------------------------------------------------
sub getMsgCode_item{
    my ($itemCircStatus,$uid)=@_;
    my $retCode="";
    my $reserveList=$itemCircStatus->{'reserveList'};
    my $holdList=$itemCircStatus->{'holdList'};
    if($itemCircStatus->{'status'}==IT_STAT_NOEXIST){
        $retCode="00";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_UNAVAIL){
        $retCode="01";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_MISSING){
        $retCode="02";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_LOST){
        $retCode="03";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_DAMAGED){
        $retCode="04";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_ONHOLD){
           if(getReserveId($uid,$holdList)>0){
               $retCode="05";}
           elsif(getReserveId($uid,$reserveList)>0){
                $retCode="06";}
           else{
                $retCode="07";}
    }
    elsif($itemCircStatus->{'status'}==IT_STAT_FULL_AVAIL && getReserveId($uid,$holdList)>0 ){
          $retCode="05";
    }    
    elsif($itemCircStatus->{'status'}==IT_STAT_HAVE_RSVR ){
        if(scalar(@$reserveList)){
            my $topReserveUID = @$reserveList[0]->{'uid'};
            if($itemCircStatus->{'inLibrary'}){
                if($uid ==$topReserveUID){
                    $retCode="08";            }
                elsif(getReserveId($uid,$reserveList)>0){
                    $retCode="09";            }
                else{
                    $retCode="10";            }
            }
            else{
                if($uid == $itemCircStatus->{'l_uid'}){
                    $retCode="11";  
                }
                elsif($uid ==$topReserveUID){
                    $retCode="12";            }
                elsif(getReserveId($uid,$reserveList)>0){
                    $retCode="13";            }
                else{
                    $retCode="14";            }
            }
        }
    }
    elsif($itemCircStatus->{'status'}==IT_STAT_ONLOAN && $uid eq $itemCircStatus->{'l_uid'}){
        $retCode="15";    }
    elsif($itemCircStatus->{'status'}==IT_STAT_ONLOAN && $uid ne $itemCircStatus->{'l_uid'}){
        $retCode="16";    }
    else{ # fully available
        $retCode="17";    }
    return $retCode;    
}
            
#-------------------------------------------------------------------------------
sub doReturn_bk{
    my ($dbh,$uid,$barcode,$dateReturn)=@_;
    
    my $sth = $dbh->prepare("select idloan,finerate, dateDue from opl_loan where uid=? && barcode=? && dateReturn is null");
    $sth->execute($uid,$barcode);
    my $rec = $sth->fetchrow_hashref;
    my $idloan   = $rec->{'idloan'};
    my $finerate   = $rec->{'finerate'};
    my $dateDue    = date_parse($rec->{'dateDue'});
    my $dateRet = date_parse($dateReturn);
    my $NumOfOverdue = date_deltaWorkDay($dateDue, $dateRet);
    my $OverdueFine  = $NumOfOverdue * $finerate;

    # Even overduefine = 0, it is still recorded to keep track how many times
    # user make overdue
    if ($NumOfOverdue>0)
    {
        $sth = $dbh->prepare("insert into opl_overdue set idloan=?, ondate=now(), amount=?");
        $sth->execute($idloan, $OverdueFine) || return FALSE;
        my $odl_id = circ_record_ODL($dbh,$idloan ,'overdue',$NumOfOverdue);
    }

    return  circ_processReturn($dbh,$barcode,$dateReturn);
   
}

#-------------------------------------------------------------------------------
sub doReturn{
    my ($dbh,$uid,$barcode,$dateReturn)=@_;
    my $loanType='daily'; 
    my $sth = $dbh->prepare("select idloan,finerate, dateDue from opl_loan where uid=? && barcode=? && dateReturn is null");
    $sth->execute($uid,$barcode);
    my $rec         = $sth->fetchrow_hashref;
    my $idloan      = $rec->{'idloan'};
    my $finerate    = $rec->{'finerate'};
    my $dateDue     = dateTime_parse($rec->{'dateDue'});
    my $dateRet     = dateTime_parse($dateReturn);
    my $timeDd      = "23:59:59";
    if($rec->{'dateDue'} =~ m/(\d\d\d\d-\d\d-\d\d) (\d\d:\d\d:\d\d)/g){
       $timeDd =$2;
    }
    if($timeDd ne "23:59:59"){ #Case: Hourly Circ
        $loanType='hourly';
    }

    my ($mumOfDaysOD , $mumOfHoursOD)= date_deltaWorkDayHour($dateDue, $dateRet);
    
       $mumOfDaysOD = 0 if ($mumOfDaysOD<=0);
       $mumOfHoursOD= 0 if ($mumOfHoursOD<=0);
    my $odl_id      = 0;

    # Even overduefine = 0, it is still recorded to keep track how many times
    # user make overdue
    if ($mumOfDaysOD>0 || $mumOfHoursOD>0)
    {
        my $odl_id = circ_record_ODL_ext($dbh,$idloan ,'overdue',$mumOfDaysOD,$mumOfHoursOD);
    }

   my $return={lid      =>$idloan,
               loanType =>$loanType,
               overdue  =>{day=>$mumOfDaysOD,hour=>$mumOfHoursOD},
               odl_id   =>$odl_id
              };
   circ_processReturn($dbh,$barcode,$dateReturn);
   return $return;
   
}

#----------------------------------------------------------------------------------
#       this function is mainly used to check if a given uid is in the
#       reserve list or hold list and return its idReserve.
#----------------------------------------------------------------------------------
sub getReserveId{
    my($uid,$list)=@_;
    if(!$list){
        return 0;
    }
    for(my $i=0; $i < scalar(@$list); $i++){
        if(@$list[$i]->{'uid'} == $uid){
            return @$list[$i]->{'idReserve'};
        }
    }
    return 0;
}

#----------------------------------------------------------------------------------
sub getTopReserveId{
    my($list)=@_;
    if(!$list){
        return 0;
    }
   return @$list[0]->{'idReserve'};
}
#----------------------------------------------------------------------------------
sub getLastReserveId{
    my($list)=@_;
    if(!$list){
        return 0;
    }
    my $i =scalar(@$list) -1;
    return @$list[$i]->{'idReserve'};
}
#-------------------------------------------------------------------------------


