#!/usr/bin/perl

#use utf8;
use strict;
use CGI;
use Digest::SHA qw(
  sha1_base64
  sha1_hex
);

use Time::localtime;
use Opals::Context;
use Opals::Template_ajax qw(
  tmpl_read
  tmpl_write
  tmpl_preference
);
use Opals::BackgroundJobs qw(
  bgjob_create
  bgjob_execute
  bgjob_getStatus
  bgjob_getOutput
);
use JSON;

use POSIX qw(
  floor
);
use Opals::User qw(
  user_getInformationById
);
use Opals::Circulation qw(
  circ_getItemStatus
  circ_getItemInfo
  circ_placeHold
  circ_fillReserve
  circ_setAvailable
  Circ_validateFollettBarcode
  Circ_validateSpectrumBarcode
  Circ_validateLeadingZeroBc
  circ_record_ODL_ext
  circ_record_ODL
  circ_processReturn
  circ_updateItemStatus
);
use Opals::Date qw(
  date_getDeadLineDate
  date_deltaWorkDay
  date_deltaWorkDayHour
  date_parse
  dateTime_parse
  date_now
  date_calcHourOverdue

);
use Opals::MarcXml qw(
  mxml_delete
);
use Opals::Transaction qw(
  trans_doReverseLost

);
use Opals::BarcodeMgmt qw(
  bcm_validateBc
);
use Opals::Constant;

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

my $syspref = tmpl_preference($dbh);
my $cgi     = CGI->new;
my $input   = $cgi->Vars();

my ($status, $errorCode, $errorMsg);
my ($permission, $cookie, $template) = tmpl_read(
  {
    dbh           => $dbh,
    cgi           => $cgi,
    tmplFile      => 'ajax/circ/return.tmpl',
    reqPermission => 'circ_return',
  }
);

my $loginuid = $template->param('curUserId');

my $todayStr = date_now();
my @retRSArr = ();
if ($permission && $permission->{'circ_return'}) {
  my $validateBc  = $syspref->{'validateBarcode'};
  my $barcodeType = $syspref->{'barcodeType'};
  my @arrReturn   = split /,/, $input->{'bcList'};
  my @arrDelBc    = split /,/, $input->{'delBcList'};

  foreach my $barcode (@arrReturn) {
    $barcode =~ s/^\s+|\s+$//g;
    $barcode = bcm_validateBc($dbh, $barcode, $barcodeType)
      if ($validateBc eq '1');

    if ($barcode && $barcode ne '') {
      my ($overdue_odl_id, $daysOverdue, $damaged_odl_id) = (0, 0, 0);
      my ($retRS, $return) = processReturn($dbh, $barcode);
      if ($input->{'condition'} =~ m/^damaged$/i) {
        circ_updateItemStatus($dbh, $barcode, ITEM_DAMAGED);
        if ($retRS->{'idloan'}) {
          my $idloan = $retRS->{'idloan'};
          $damaged_odl_id = circ_record_ODL($dbh, $idloan, 'damaged', 0);
        }
      }
      my $retStatusCode = 'retStatusCode_' . $retRS->{'retStatusCode'};
      $retRS->{'lid'}            = $return->{'lid'};
      $retRS->{'retStatusCode'}  = $retStatusCode;
      $retRS->{'barcode'}        = $barcode;
      $retRS->{'overdue_odl_id'} = $return->{'odl_id'};
      $retRS->{'loanType'}       = $return->{'loanType'};
      $retRS->{'daysOverdue'}    = $return->{'overdue'}->{'day'};
      $retRS->{'hoursOverdue'}   = $return->{'overdue'}->{'hour'};
      $retRS->{'damaged_odl_id'} = $damaged_odl_id;
      push @retRSArr, $retRS;

      if (isInDelList($barcode, \@arrDelBc) || $retRS->{'isTempILL'}) {
        mxml_delete($dbh, $retRS->{'rid'});
      }
    }

  }
  $template->param(returnList => \@retRSArr);

}
tmpl_write($dbh, $cgi, $cookie, $template, 'application/json');
#########################################################################
sub isInDelList {
  my ($bc, $delBcList) = @_;
  for (my $i = 0 ; $i < scalar(@$delBcList) ; $i++) {
    if ($bc eq @$delBcList[$i]) {
      return 1;
    }
  }
  return 0;
}

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

sub validateBc_bk {
  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 processReturn {
  my ($dbh, $barcode) = @_;
  my $itemCircStatus = circ_getItemStatus($dbh, $barcode);
  my $return;
  my $itemInfo = circ_getItemInfo($dbh, $barcode, undef);
  my $retval = {
    rid        => $itemInfo->{'rid'},
    title      => $itemInfo->{'title'},
    author     => $itemInfo->{'author'},
    pubName    => $itemInfo->{'pubName'},
    pubDate    => $itemInfo->{'pubDate'},
    price      => $itemInfo->{'price'},
    itemType   => $itemInfo->{'typeId'},
    callNumber => $itemInfo->{'callNumber'},
    isTempILL  => $itemCircStatus->{'isTempILL'},
    barcode    => $barcode

  };

  my $overdue = 0;
  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'};
      $return = doReturn($dbh, $itemCircStatus->{'l_uid'}, $barcode, $todayStr);
      $overdue =
        ($return->{'overdue'}->{'day'} > 0 || $return->{'overdue'}->{'hour'})
        ? 1
        : 0;
      $retval->{'uid'} = $itemCircStatus->{'l_uid'};
      my ($borrower, $guardian) =
        user_getInformationById($dbh, $retval->{'uid'});
      $retval->{'firstname'}    = $borrower->{'firstname'};
      $retval->{'lastname'}     = $borrower->{'lastname'};
      $retval->{'buildingcode'} = $borrower->{'buildingcode'};
      $retval->{'homeroom'}     = $borrower->{'homeroom'};
      $retval->{'grade'}        = $borrower->{'grade'};
      $retval->{'categorycode'} = $borrower->{'categorycode'};

    }

    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 = date_getDeadLineDate($itemInfo->{'holdPeriod'}, $todayStr);
      if ($dateExpiry > $reserveExpiry) {
        $dateExpiry = $reserveExpiry;
      }
      circ_fillReserve($dbh, $uidReserve, $itemCircStatus->{'rid'});    #Ha
      circ_placeHold($dbh, $idReserve, $todayStr, $dateExpiry);

      my ($reserveUser, $guardian) = user_getInformationById($dbh, $uidReserve);
      $retval->{'reserveUserUid'}          = $uidReserve;
      $retval->{'reserveUserFirstname'}    = $reserveUser->{'firstname'};
      $retval->{'reserveUserLastname'}     = $reserveUser->{'lastname'};
      $retval->{'reserveUserBuildingcode'} = $reserveUser->{'buildingcode'};
      $retval->{'reserveUserHomeroom'}     = $reserveUser->{'homeroom'};
      $retval->{'reserveUserTeacher'}      = $reserveUser->{'teacher'};
      $retval->{'reserveUserGrade'}        = $reserveUser->{'grade'};
    }
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_LOST) {
    $retval->{'retStatusCode'} = '30';
    circ_setAvailable($dbh, $barcode, IT_STAT_LOST);
    trans_doReverseLost($dbh, $barcode, $loginuid);
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_NOEXIST) {
    $retval->{'retStatusCode'} = '40';
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_ONHOLD) {
    $retval->{'retStatusCode'} = '50';

    my $holdList = $itemCircStatus->{'holdList'};

    $retval->{'holdUserUid'}          = $holdList->[0]->{'uid'};
    $retval->{'holdUserFirstname'}    = $holdList->[0]->{'firstname'};
    $retval->{'holdUserLastname'}     = $holdList->[0]->{'lastname'};
    $retval->{'holdUserBuildingcode'} = $holdList->[0]->{'buildingcode'};
    $retval->{'holdUserHomeroom'}     = $holdList->[0]->{'homeroom'};
    $retval->{'holdUserTeacher'}      = $holdList->[0]->{'teacher'};
    $retval->{'holdUserGrade'}        = $holdList->[0]->{'grade'};
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_MISSING) {
    $retval->{'retStatusCode'} = '70';
    if ($input->{'Condition'} eq "Damaged") {
      circ_updateItemStatus($dbh, $barcode, ITEM_DAMAGED);

      #???????????? opl_odl
    }
    else {
      circ_setAvailable($dbh, $barcode, IT_STAT_MISSING);
    }
  }

  # Wed, Sep 16, 2015 @ 16:22:56 EDT
  elsif ($itemCircStatus->{'status'} == IT_STAT_CLAIM_NEVER_LOAN) {
    $retval->{'retStatusCode'} = '80';
    circ_setAvailable($dbh, $barcode, IT_STAT_CLAIM_NEVER_LOAN);
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_CLAIM_RETURN) {
    $retval->{'retStatusCode'} = '90';
    circ_setAvailable($dbh, $barcode, IT_STAT_CLAIM_RETURN);
  }
  elsif ($itemCircStatus->{'status'} == IT_STAT_HOLD_EXPIRE) {
  }
  else {
    $retval->{'retStatusCode'} = '60';
  }

  return ($retval, $return);
}

#-------------------------------------------------------------------------------
sub doReturn {
  my ($dbh, $uid, $barcode, $dateReturn) = @_;
  my $loanType = 'daily';
  my $sth      = $dbh->prepare(
"select idloan, dateDue from opl_loan where uid=? && barcode=? && dateReturn is null"
  );
  $sth->execute($uid, $barcode);
  my $rec     = $sth->fetchrow_hashref;
  my $idloan  = $rec->{'idloan'};
  my $dateRet = dateTime_parse($dateReturn);
  my $dateDue = dateTime_parse($rec->{'dateDue'});
  my $timeDd  = "23:59:59";
  my ($mumOfDaysOD, $mumOfHoursOD, $mumOfMinuteOD) = (0, 0, 0);

  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';
    ($mumOfHoursOD, $mumOfMinuteOD) = date_calcHourOverdue($dateDue, $dateRet);
  }
  else {
    ($mumOfDaysOD, $mumOfHoursOD, $mumOfMinuteOD) =
      date_deltaWorkDayHour($dateDue, $dateRet);
  }
  my $odl_id = 0;

  #Wed, Jul 06, 2011 @ 10:38:41 EDT
  # check grace period

  my $itemInfo = circ_getItemInfo($dbh, $barcode, $uid);
  my ($graceDay, $graceHour, $graceiMinute) = (0, 0, 0);
  if (defined $itemInfo->{'gracePeriod'} && defined $itemInfo->{'graceUnit'}) {
    if ($itemInfo->{'graceUnit'} eq 'day') {
      $graceDay = $itemInfo->{'gracePeriod'};
    }
    elsif ($itemInfo->{'graceUnit'} eq 'minute') {
      $graceiMinute = $itemInfo->{'gracePeriod'};
    }
    else {
      $graceHour = $itemInfo->{'gracePeriod'};
    }
  }

  if (60 * (24 * $mumOfDaysOD + $mumOfHoursOD) + $mumOfMinuteOD >
    (60 * (24 * $graceDay + $graceHour) + $graceiMinute))
  {
    $mumOfHoursOD += 1 if ($mumOfMinuteOD > 0);
    if ($loanType ne 'hourly') {
      $mumOfDaysOD += 1 if ($mumOfHoursOD > 0);
      $mumOfHoursOD = 0;
    }

  }
  else {
    $mumOfDaysOD  = 0;
    $mumOfHoursOD = 0;
  }

  #/check grace period

  # Even overduefine = 0, it is still recorded to keep track how many times
  # user make overdue
  if ($mumOfDaysOD > 0 || $mumOfHoursOD > 0) {
    $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);
  my ($revertLocation) = $dbh->selectrow_array(
    "select resetLocOnReturn from opl_tmpLocation where locName=?",
    undef, $itemInfo->{"location"});
  if (defined $revertLocation && $revertLocation == 1) {
    my $jobInfo = {};
    $jobInfo->{"type"}    = "revertShelfLoc";
    $jobInfo->{"reqDate"} = date_now();
    my $itemList = [ { rid => $itemInfo->{'rid'}, barcode => $barcode } ];
    my $jId = bgjob_create($dbh, to_json($jobInfo), $itemList);
    bgjob_execute($dbh, $jId);

  }
  return $return;

}

