#!/usr/bin/perl

use strict;
use CGI;

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

use POSIX qw(
    floor
);

use Opals::Date qw(
    date_text
);

use Time::localtime;

use Opals::Constant;

use Opals::User qw(
    user_getInformationById
);


use Opals::Tb_Circulation qw(
    
    circ_getItemInfo
    circ_getItemStatus
    circ_processReturn
    circ_getUserListLoan

    circ_setAvailable
    circ_updateItemStatus
    circ_record_ODL
);
use Opals::Date qw(
    date_getDeadLineDate
    date_deltaWorkDay   
    date_parse

);

use Opals::HTMLComponents qw(
    hc_getQuickUserEntryFormHTML
);

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

my $cgi = CGI->new;
my $input = $cgi->Vars();
my ($permission, $cookieList, $template) = tmpl_read(
    {
        dbh             => $dbh,
        cgi             => $cgi,
        tmplFile        => 'txtbk/return.tmpl',
        reqPermission   => 'tb_circ_return',
    }
);

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

my $barcode = $input->{'bc'};
$barcode    =~ s/^\s+|\s+$//g;
my $uid = $input->{'uid'};
my $qeUserForm =hc_getQuickUserEntryFormHTML($dbh);
    $template->param(qeUserForm=>$qeUserForm);

if ($barcode){
    my ($retRS, $return) = processReturn($dbh, $barcode);
    if($input->{'condition'} =~ /^damaged$/i){
        circ_updateItemStatus($dbh,$barcode,ITEM_DAMAGED,$retRS->{'uid'});
        #circ_updateItemStatus($dbh, $barcode, ITEM_DAMAGED);
        if($retRS->{'idLoan'}){
            my $idloan = $retRS->{'idLoan'};
            my $damaged_odl_id = circ_record_ODL($dbh,$idloan,'damaged',0);
        }
    }
    my $retStatusCode   = 'retStatusCode_' .$retRS->{'retStatusCode'};
    $template->param(
        rid                     => $retRS->{'rid'},
        rname                   => $retRS->{'rname'},
        barcode                 => $barcode,
        $retStatusCode          => 1,
        returnOne               => 1,
        reserveUserUid          => $retRS->{'reserveUserUid'},
        reserveUserFirstname    => $retRS->{'reserveUserFirstname'},
        reserveUserLastname     => $retRS->{'reserveUserLastname'},
        reserveUserBarcode      => $retRS->{'reserveUserBarcode'},
        holdUserFirstname       => $retRS->{'holdUserFirstname'},
        holdUserLastname        => $retRS->{'holdUserLastname'},
        holdUserBarcode         => $retRS->{'holdUserBarcode'},
    );
    getUserInfo($dbh, $retRS->{'uid'});
}
elsif ($input->{'op'} eq 'return'){
    my @arrReturn = split /,/,$input->{'itemList'};
    my @retHoldRsList;
    my $retRS;
    for (my $i=0; $i<scalar(@arrReturn); $i++)
    {
        $retRS = processReturn($dbh, @arrReturn[$i]);
        if ($retRS->{'retStatusCode'} eq '20' || $retRS->{'retStatusCode'} eq '21' || $retRS->{'retStatusCode'} eq '22' ){
            push @retHoldRsList, $retRS;
        }
    }
    getUserInfo($dbh, $uid);
    $template->param(retHoldRsList=>\@retHoldRsList);
}
elsif($input->{'op'} eq 'renew'){
    my $rndateDue = "";
    if ( 'seldate' eq $input->{'renewDate'}){
        my $numb        = $input->{'rndateDue'};
        my $hourOrDay   = $input->{'rnhourOrDay'};
        if ($numb && $hourOrDay && $numb > 0){
            $rndateDue = formatStrDateDue($numb, $hourOrDay);  
        }
    }
    my $renewError = processRenew($dbh, $uid, $input->{'itemList'}, $rndateDue);
    if (scalar(@$renewError)){
        if (@$renewError[2] == 0){
            $template->param(renewalMaxError=>1);}
        $template->param(renewalError=>1, renewFailList=>\@$renewError);
    }
    getUserInfo($dbh, $uid);
}
tmpl_write($dbh, $cgi, $cookieList, $template);

#--------------------------------------
sub processReturn{
    my ($dbh, $barcode ) = @_;
    my $itemCircStatus  = circ_getItemStatus($dbh, $barcode);
    my $itemInfo        = circ_getItemInfo($dbh, $barcode, undef);
    my ($retVal,$return) ;

    $retVal->{'itemInfo'}   =  $itemInfo;
    my $overdue;

    if ($itemCircStatus->{'status'} == IT_STAT_ONLOAN 
            || $itemCircStatus->{'status'} == IT_STAT_HAVE_RSVR
            || $itemCircStatus->{'status'} == IT_STAT_HOLD_EXPIRE){
        if ($itemCircStatus->{'status'} == IT_STAT_ONLOAN 
            || $itemCircStatus->{'status'} == IT_STAT_HAVE_RSVR){
            $retVal->{'idLoan'} = $itemCircStatus->{'l_idLoan'};
            my $return = doReturn($dbh, $itemCircStatus->{'l_uid'}, $barcode, $todayStr);
            $overdue    = $itemCircStatus->{'l_duedate'} < $todayStr ? 1:0;
            $retVal->{'uid'} = $itemCircStatus->{'l_uid'};
        }
        my $reserveList = $itemCircStatus->{'reserveList'};
        #check if item is on reserved
        if (!$reserveList || scalar(@$reserveList) == 0){
            $retVal->{'retStatusCode'} = "1$overdue";
        }
        else{
            if ($itemCircStatus->{'status'} == IT_STAT_HOLD_EXPIRE){
                $retVal->{'retStatusCode'} = "22";  }
            else {
                $retVal->{'retStatusCode'} = "2$overdue";   }
            my ($idReserve, $uidReserve, $reserveExpiry, $dateExpiry);
            $idReserve      = $reserveList->[0]->{'idReserve'};
            $uidReserve     = $reserveList->[0]->{'uid'};
            $reserveExpiry  = $reserveList->[0]->{'dateExpiry'};
            
            $itemInfo   = circ_getItemInfo($dbh, $barcode, $uidReserve);
            $dateExpiry = getDeadLineDate($itemInfo->{'holdPeriod'}, $todayStr);
            #if ($dateExpiry >  $reserveExpiry){
            #    $dateExpiry = $reserveExpiry;  }
            circ_fillReserve($dbh, $uidReserve, $itemCircStatus->{'rid'});
            circ_placeHold($dbh, $idReserve, $todayStr, $dateExpiry);
            my ($reserveUser, $guardien) = user_getInformationById($dbh, $uidReserve);
            $retVal->{'reserveUserUid'}         = $uidReserve;
            $retVal->{'reserveUserLastname'}    = $reserveUser->{'lastname'};
            $retVal->{'reserveUserFirstname'}   = $reserveUser->{'firstname'};
            $retVal->{'reserveUserBarcode'}     = $reserveUser->{'userbarcode'};
        }
    }
    elsif ($itemCircStatus->{'status'} == IT_STAT_LOST) {
        $retVal->{'retStatusCode'} = "30";
        circ_setAvailable($dbh, $barcode, IT_STAT_LOST);
    }
    elsif ($itemCircStatus->{'status'} == IT_STAT_NOEXIST){
        $retVal->{'retStatusCode'} = "40";
    }
    elsif ( $itemCircStatus->{'status'} == IT_STAT_ONHOLD){
        $retVal->{'retStatusCode'} = "50";
        my $holdList = $itemCircStatus->{'holdList'};
        $retVal->{'holdUserFirstname'} = $holdList->[0]->{'firstname'};
        $retVal->{'holdUserLastname'} = $holdList->[0]->{'lastname'};
        $retVal->{'holdUserBarcode'} = $holdList->[0]->{'userbarcode'};
    }
    elsif( $itemCircStatus->{'status'} == IT_STAT_MISSING){
        $retVal->{'retStatusCode'} = "70";
        if ($input->{'Condition'} eq "Damaged"){
            circ_updateItemStatus($dbh, $barcode, ITEM_DAMAGED);
        }
        else{
            circ_setAvailable($dbh, $barcode, IT_STAT_MISSING);
        }
    }
    else{
        $retVal->{'retStatusCode'} = "60";
    }
    return ($retVal,$return);
}

sub doReturn{
    
    my ($dbh, $uid, $barcode, $dateReturn) = @_;
    my $sth = $dbh->prepare("select id, dateDue from tb_loan where uid=? && barcode=? && dateReturn is null");
    $sth->execute($uid,$barcode);
    my $rec = $sth->fetchrow_hashref;
    my $idloan   = $rec->{'id'};
    my $dateDue    = date_parse($rec->{'dateDue'});
    my $dateRet = date_parse($dateReturn);
    my $NumOfOverdue = date_deltaWorkDay($dateDue, $dateRet);
    $NumOfOverdue=0 if ($NumOfOverdue<=0);
    my $odl_id =0;
    # Even overduefine = 0, it is still recorded to keep track how many times
    # user make overdue
    if ($NumOfOverdue>0)
    {
        $odl_id = circ_record_ODL($dbh,$idloan ,'overdue',$NumOfOverdue);
    }
    my $return={lid=>$idloan,overdue=>$NumOfOverdue,odl_id=>$odl_id};
    circ_processReturn($dbh, $uid, $barcode, $dateReturn);
    return $return;
}

sub processRenew{
    my ($dbh, $uid, $bcList, $inDueDate) = @_;    
    my @arrRenew = split /,/,$bcList;
    my @renewFailList = ();
    my $renewStatus;
    my $renewable;
    for (my $i = 0; $i < scalar(@arrRenew); $i++){
        my $itemCircStatus  = circ_getItemStatus($dbh, {barcode=>$arrRenew[$i]});
        my $itemInfo        = circ_getItemInfo($dbh, $arrRenew[$i], $uid);
        $renewStatus = 0;
        $renewable = ($itemCircStatus->{'renewalCount'} < $itemCircStatus->{'maxRenewal'})?1:0;
        if ($itemCircStatus->{'l_uid'} == $uid && $renewable){
            my $dateDue = ($inDueDate ne '')? $inDueDate : getDeadLineDate($itemInfo->{'renewalPeriod'}, $itemCircStatus->{'l_duedate'});
            $renewStatus = circ_processRenew($dbh, {uid=>$uid, barcode=>$arrRenew[$i],rnDate=>$dateDue});
        }
        if (! $renewStatus){
            push @renewFailList, {bc=>$arrRenew[$i], rname=>$itemInfo->{'rname'}};
        }
    }
    return \@renewFailList;
}

sub getUserInfo{
    my ($dbh, $uid) = @_;
    my ($userInfo, $guardian) = user_getInformationById($dbh, $uid);
    getItemLoanList($dbh, $template,$uid);
    my $balance = 0;
    $balance = floor($balance*100  + 0.50)/100;
    $balance = sprintf("%.2f",$balance);

    $template->param(
        user_uid        => $userInfo->{'uid'},
        user_barcode    => $userInfo->{'userbarcode'},
        user_username   => $userInfo->{'username'},
        user_firstname  => $userInfo->{'firstname'},
        user_lastname   => $userInfo->{'lastname'},
        homeroom        => $userInfo->{'homeroom'},
        teacher         => $userInfo->{'teacher'},
        grade           => $userInfo->{'grade'},
        notes           => $userInfo->{'notes'},
        hiddenid        => $userInfo->{'uid'},
        balance         => $balance,
    );
}

sub getItemLoanList{

    my ($dbh, $template, $uid) = @_;
    my $loanList = circ_getUserListLoan($dbh,$uid);
    my $count = 0;
    my $odCount = 0;

    foreach my $loan(@$loanList){
        if ($loan->{'overdue'}) {$odCount++;}
        $loan->{'dateLoan'} = date_text($loan->{'dateLoan'}, 0);
        $loan->{'dateDue'}  = date_text($loan->{'dateDue'}, 0);
        $loan->{'number'} = $count++;
    }
    $template->param(loanList => \@$loanList);
    $template->param(LoanCount => scalar(@$loanList));
    $template->param(NumOfOverdue => $odCount);
}


sub getDeadLineDate{
    my ($length, $dateStr) = @_;
    my $retDate;

    if ($length <= 0){
        return $retDate =  `date -d'+%Y-%m-%d %H:%M:%S'`;
    }
    return $retDate =  `date -d '$length hour' '+%Y-%m-%d %H:%M:%S'`;
}

sub formatStrDateDue{
    my ($n,$h_d) = @_;
    my $retDD;
    return if ($n eq '' || $h_d eq '');
    if ($h_d eq 'd' ){
         $n = $n * 24;
    }
    return $retDD = `date -d '$n hour' '+%Y-%m-%d %H:%M:%S'`;
}

