package SIP::User;

# Version number
our $VERSION = 0.01;

use strict;
use Digest::SHA qw(
  sha1_base64
);

use Opals::Constant;
use Opals::User qw(
  user_getUserCircInfo
);

use SIP::Map;
################################################################################

sub new {
  my $class = shift;
  my (%param) = (@_);

  my $dbh = $param{'dbh'};

  return unless $dbh;

  my $this = { dbh => $dbh, };

  bless $this, $class;

  $this->setInfo(%param);

  return $this;
}
################################################################################

sub init {
  my $this = shift;

  foreach my $k (keys %{$this}) {
    delete $this->{$k} unless ($k eq 'dbh');
  }
}
############################################################

sub setInfo {
  my $this = shift;

  return unless (@_);

  my (%id) = @_;

  return unless ($id{'uid'} || $id{'patron_id'});

  $this->init();

  my $dbh = $this->{'dbh'};
  my @val = ();
  my $where_statement;
  if ($id{'uid'}) {
    @val             = ($id{'uid'});
    $where_statement = "where uid = ?";
  }
  else {
    @val = ($id{'patron_id'}, $id{'patron_id'}, $id{'patron_id'});
    $where_statement = "where userbarcode = ? || sid = ? || username = ?";
  }

  my $info = $dbh->selectrow_hashref(<<_SQL_, undef, @val);
select  *, if (expirydate > '0000-00-00' && expirydate < now(), 1, 0) as expired
from    opl_user
$where_statement
_SQL_

  if ($info) {
    if ($info->{'expired'} == 1) {
      $info->{'status'} = USER_BLOCK;#EXPIRED;
    }

    @val = ($info->{'categorycode'});
    ($info->{'maxloans'}, $info->{'authenticateBySID'}, $info->{'catname'}) =
      $dbh->selectrow_array(<<_SQL_, undef, @val);
select  maxloans, authenticateBySID, catname
from    opl_category
where   catid = ?
_SQL_

    my $db_access_passwd = 'db_access_passwd';
    @val = ($db_access_passwd);
    ($info->{$db_access_passwd}) =
      $dbh->selectrow_array(<<_SQL_, undef, @val);
select  val
from    opl_preference
where   var = ?
_SQL_

    $this->{'id'} =
         $id{'patron_id'}
      || $info->{'userbarcode'}
      || $info->{'sid'}
      || $info->{'username'};

    #        if ($info->{'authenticateBySID'}) {
    #            $info->{'password'} = sha1_base64($this->{'id'});
    #        }

    foreach my $k (keys %{$info}) {
      $this->{$k} = $info->{$k};
    }
  }
}
############################################################

sub getUID {
  my $this = shift;

  return $this->{'uid'};
}
############################################################

sub getPatronIdentifier {
  my $this = shift;

  return $this->{'id'};
}
############################################################

# See patron status code description on page 22 in
# sip2_protocol_definition_2006.pdf.
sub getPatronStatus {
  my $this = shift;

  #    return unless $this->getUID();

  my $dbh = $this->{'dbh'};
  my @val = ($this->getUID());

# charged_privileges_denied
# renewal_privileges_denied
# recall_privileges_denied
# hold_privileges_denied
  my $crrh_privileges_denied = ' ';
#  if ($this->{'status'} == USER_BLOCK) {
  if ($this->{'status'} != USER_ACTIVE) {
    $crrh_privileges_denied = 'Y';
  }

  my ($loan_count) = $dbh->selectrow_array(<<_SQL_, undef, @val);
select count(*) from opl_loan where uid=? && dateReturn is null
_SQL_

  my ($overdue_count) = $dbh->selectrow_array(<<_SQL_, undef, @val);
select count(*) from opl_loan where uid=? && dateReturn is null && dateDue<now()
_SQL_

  my ($lost_count) = $dbh->selectrow_array(<<_SQL_, undef, @val);
select count(*) from opl_odl odl left join opl_loan l using (idloan) left join opl_charge c using (odl_id)
where l.uid=? && odl.type='lost' && creditRefund<0.00
_SQL_

  my ($outstanding_fines) = $dbh->selectrow_array(<<_SQL_, undef, @val);
select sum(balance) from opl_charge inner join opl_user using (uid) where uid=?
_SQL_

  ($loan_count)        || ($loan_count        = 0);
  ($overdue_count)     || ($overdue_count     = 0);
  ($lost_count)        || ($lost_count        = 0);
  ($outstanding_fines) || ($outstanding_fines = 0);

  my $status = {
    charged_privileges_denied   => $crrh_privileges_denied,
    renewal_privileges_denied   => $crrh_privileges_denied,
    recall_privileges_denied    => $crrh_privileges_denied,
    hold_privileges_denied      => $crrh_privileges_denied,
    too_many_items_charged      => ($loan_count >= $this->{'maxloans'}) ? 'Y' : ' ',
    too_many_items_overdue      => ($overdue_count > 20) ? 'Y' : ' ',
    too_many_items_lost         => ($lost_count > 20) ? 'Y' : ' ',
    excessive_outstanding_fines => ($outstanding_fines > 50.00) ? 'Y' : ' ',
  };

  my $ps = '';
  my $s;
  for (my $i = 0 ; $i < scalar((SIP::Map::PATRON_STATUS)) ; $i++) {
    $s = (SIP::Map::PATRON_STATUS)[$i]->{'status'};
    $ps .=
      (defined $status->{$s})
      ? $status->{$s}
      : (SIP::Map::PATRON_STATUS)[$i]->{'default'};
  }

  return $ps;
}
############################################################

sub updatePatronStatus {
  my $this = shift;

  my $uid = $this->getUID();

  return unless $uid && @_;

  my (%param) = @_;
  my ($status, $transaction_datetime, $msg) =
    ($param{'status'}, $param{'datetime'}, $param{'message'});

  my $dbh = $this->{'dbh'};
  my @val = ($status, $uid);

  $dbh->do(<<_SQL_, undef, @val);
update opl_user set status = ? where uid = ?
_SQL_

  $this->{'status'} = $status;

  my $status_text = {
    0 => 'deactivated',
    1 => 'activated',
    2 => 'suspended',
  };

  # log transaction
  @val = ($uid, $transaction_datetime, $status_text->{$status}, $msg);
  $dbh->do(<<_SQL_, undef, @val);
insert into opl_historyUser
set     uid = ?,
        ondate = ?,
        status = ?,
        note = ?
_SQL_
}
############################################################

sub isExpired {
  my $this = shift;

  return ($this->{'expired'}) ? 'true' : 'false';
}
############################################################

sub isValidPatron {
  my $this = shift;

  return (defined $this->{'id'} && !$this->{'expired'}) ? 'true' : 'false';
}
############################################################

sub isValidPatronPassword {
  my $this = shift;

  if ($this->{'authenticateBySID'}) {
    return 'true';
  }

  my $password = '';
  if (@_) {
    $password = shift;
  }

  return (
      $this->{'password'} eq sha1_base64($password)
   || $this->{'db_access_passwd'} eq $password
  ) ? 'true' : 'false';
}
############################################################

sub getPersonalName {
  my $this = shift;

  return (defined $this->{'id'})
    ? "$this->{'firstname'} $this->{'lastname'}"
    : '';
}
############################################################

sub getExpiryDate {
  my $this = shift;

  return $this->{'expirydate'};
}
############################################################

sub getBirthday {
  my $this = shift;

  return $this->{'birthday'};
}
############################################################

sub getPatronType {
  my $this = shift;

  return $this->{'catname'};
}
############################################################

sub getPermissions {
  my $this = shift;

  my $permissions = {};
  foreach my $p (split(/,/, $this->{'permissions'})) {
    $p = lc($p) if ($p =~ m/^U[1-9]$/);
    $permissions->{$p} = 1;
  }

  return $permissions;
}
############################################################

sub getBalance {
  my $this = shift;

  my $dbh = $this->{'dbh'};
  my $uid = $this->getUID();
  my $userCircInfo = user_getUserCircInfo($dbh, $uid);
  if ($userCircInfo && $userCircInfo->{'accountBalance'}) {
    return $userCircInfo->{'accountBalance'};
  }

  return 0.00;
}

1;
