package C4::CourseReserves;

# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Koha is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Koha; if not, see <http://www.gnu.org/licenses>.

use Modern::Perl;

use C4::Context;
use C4::Items qw(GetItem ModItem);
use C4::Biblio qw(GetBiblioFromItemNumber);
use C4::Circulation qw(GetOpenIssue);

use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG @FIELDS);

BEGIN {
    require Exporter;
    @ISA       = qw(Exporter);
    @EXPORT_OK = qw(
      &GetCourse
      &ModCourse
      &GetCourses
      &DelCourse

      &GetCourseInstructors
      &ModCourseInstructors

      &GetCourseItem
      &ModCourseItem

      &GetCourseReserve
      &ModCourseReserve
      &GetCourseReserves
      &DelCourseReserve

      &SearchCourses

      &GetItemCourseReservesInfo
    );
    %EXPORT_TAGS = ( 'all' => \@EXPORT_OK );

    $DEBUG = 0;
    @FIELDS = ( 'itype', 'ccode', 'holdingbranch', 'location' );
}

=head1 NAME

C4::CourseReserves - Koha course reserves module

=head1 SYNOPSIS

use C4::CourseReserves;

=head1 DESCRIPTION

This module deals with course reserves.

=head1 FUNCTIONS

=head2 GetCourse

    $course = GetCourse( $course_id );

=cut

sub GetCourse {
    my ($course_id) = @_;
    warn whoami() . "( $course_id )" if $DEBUG;

    my $query = "SELECT * FROM courses WHERE course_id = ?";
    my $dbh   = C4::Context->dbh;
    my $sth   = $dbh->prepare($query);
    $sth->execute($course_id);

    my $course = $sth->fetchrow_hashref();

    $query = "
        SELECT b.* FROM course_instructors ci
        LEFT JOIN borrowers b ON ( ci.borrowernumber = b.borrowernumber )
        WHERE course_id =  ?
    ";
    $sth = $dbh->prepare($query);
    $sth->execute($course_id);
    $course->{'instructors'} = $sth->fetchall_arrayref( {} );

    return $course;
}

=head2 ModCourse

    ModCourse( [ course_id => $id ] [, course_name => $course_name ] [etc...] );

=cut

sub ModCourse {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $dbh = C4::Context->dbh;

    my $course_id;
    if ( defined $params{'course_id'} ) {
        $course_id = $params{'course_id'};
        delete $params{'course_id'};
    }

    my @query_keys;
    my @query_values;

    my $query;

    $query .= ($course_id) ? ' UPDATE ' : ' INSERT ';
    $query .= ' courses SET ';

    foreach my $key ( keys %params ) {
        push( @query_keys,   "$key=?" );
        push( @query_values, $params{$key} );
    }
    $query .= join( ',', @query_keys );

    if ($course_id) {
        $query .= " WHERE course_id = ?";
        push( @query_values, $course_id );
    }

    $dbh->do( $query, undef, @query_values );

    $course_id = $course_id
      || $dbh->last_insert_id( undef, undef, 'courses', 'course_id' );

    EnableOrDisableCourseItems(
        course_id => $course_id,
        enabled   => $params{'enabled'}
    );

    return $course_id;
}

=head2 GetCourses

  @courses = GetCourses( [ fieldname => $value ] [, fieldname2 => $value2 ] [etc...] );

=cut

sub GetCourses {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my @query_keys;
    my @query_values;

    my $query = "
        SELECT courses.*
        FROM courses
        LEFT JOIN course_reserves ON course_reserves.course_id = courses.course_id
        LEFT JOIN course_items ON course_items.ci_id = course_reserves.ci_id
    ";

    if ( keys %params ) {

        $query .= " WHERE ";

        foreach my $key ( keys %params ) {
            push( @query_keys,   " $key LIKE ? " );
            push( @query_values, $params{$key} );
        }

        $query .= join( ' AND ', @query_keys );
    }

    $query .= " GROUP BY courses.course_id ";

    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);
    $sth->execute(@query_values);

    my $courses = $sth->fetchall_arrayref( {} );

    foreach my $c (@$courses) {
        $c->{'instructors'} = GetCourseInstructors( $c->{'course_id'} );
    }

    return $courses;
}

=head2 DelCourse

  DelCourse( $course_id );

=cut

sub DelCourse {
    my ($course_id) = @_;

    my $course_reserves = GetCourseReserves( course_id => $course_id );

    foreach my $res (@$course_reserves) {
        DelCourseReserve( cr_id => $res->{'cr_id'} );
    }

    my $query = "
        DELETE FROM course_instructors
        WHERE course_id = ?
    ";
    C4::Context->dbh->do( $query, undef, $course_id );

    $query = "
        DELETE FROM courses
        WHERE course_id = ?
    ";
    C4::Context->dbh->do( $query, undef, $course_id );
}

=head2 EnableOrDisableCourseItems

  EnableOrDisableCourseItems( course_id => $course_id, enabled => $enabled );

  For each item on reserve for this course,
  if the course item has no active course reserves,
  swap the fields for the item to make it 'normal'
  again.

  enabled => 'yes' to enable course items
  enabled => 'no' to disable course items

=cut

sub EnableOrDisableCourseItems {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $course_id = $params{'course_id'};
    my $enabled = $params{'enabled'} || 0;

    my $lookfor = ( $enabled eq 'yes' ) ? 'no' : 'yes';

    return unless ( $course_id && $enabled );
    return unless ( $enabled eq 'yes' || $enabled eq 'no' );

    my $course_reserves = GetCourseReserves( course_id => $course_id );

    if ( $enabled eq 'yes' ) {
        foreach my $course_reserve (@$course_reserves) {
            if (CountCourseReservesForItem(
                    ci_id   => $course_reserve->{'ci_id'},
                    enabled => 'yes'
                )
              ) {
                EnableOrDisableCourseItem(
                    ci_id   => $course_reserve->{'ci_id'},
                    enabled => 'yes',
                );
            }
        }
    }
    if ( $enabled eq 'no' ) {
        foreach my $course_reserve (@$course_reserves) {
            unless (
                CountCourseReservesForItem(
                    ci_id   => $course_reserve->{'ci_id'},
                    enabled => 'yes'
                )
              ) {
                EnableOrDisableCourseItem(
                    ci_id   => $course_reserve->{'ci_id'},
                    enabled => 'no',
                );
            }
        }
    }
}

=head2 EnableOrDisableCourseItem

    EnableOrDisableCourseItem( ci_id => $ci_id, enabled => $enabled );

    enabled => 'yes' to enable course items
    enabled => 'no' to disable course items

=cut

sub EnableOrDisableCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id   = $params{'ci_id'};
    my $enabled = $params{'enabled'};

    return unless ( $ci_id && $enabled );
    return unless ( $enabled eq 'yes' || $enabled eq 'no' );

    my $course_item = GetCourseItem( ci_id => $ci_id );

    ## We don't want to 'enable' an already enabled item,
    ## or disable and already disabled item,
    ## as that would cause the fields to swap
    if ( $course_item->{'enabled'} ne $enabled ) {
        _SwapAllFields($ci_id);

        my $query = "
            UPDATE course_items
            SET enabled = ?
            WHERE ci_id = ?
        ";

        C4::Context->dbh->do( $query, undef, $enabled, $ci_id );

    }

}

=head2 GetCourseInstructors

    @$borrowers = GetCourseInstructors( $course_id );

=cut

sub GetCourseInstructors {
    my ($course_id) = @_;
    warn "C4::CourseReserves::GetCourseInstructors( $course_id )"
      if $DEBUG;

    my $query = "
        SELECT * FROM borrowers
        RIGHT JOIN course_instructors ON ( course_instructors.borrowernumber = borrowers.borrowernumber )
        WHERE course_instructors.course_id = ?
    ";

    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);
    $sth->execute($course_id);

    return $sth->fetchall_arrayref( {} );
}

=head2 ModCourseInstructors

    ModCourseInstructors( mode => $mode, course_id => $course_id, [ cardnumbers => $cardnumbers ] OR [ borrowernumbers => $borrowernumbers  );

    $mode can be 'replace', 'add', or 'delete'

    $cardnumbers and $borrowernumbers are both references to arrays

    Use either cardnumbers or borrowernumber, but not both.

=cut

sub ModCourseInstructors {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $course_id       = $params{'course_id'};
    my $mode            = $params{'mode'};
    my $cardnumbers     = $params{'cardnumbers'};
    my $borrowernumbers = $params{'borrowernumbers'};

    return unless ($course_id);
    return
      unless ( $mode eq 'replace'
        || $mode eq 'add'
        || $mode eq 'delete' );
    return unless ( $cardnumbers || $borrowernumbers );
    return if ( $cardnumbers && $borrowernumbers );

    my ( @cardnumbers, @borrowernumbers );
    @cardnumbers = @$cardnumbers if ( ref($cardnumbers) eq 'ARRAY' );
    @borrowernumbers = @$borrowernumbers
      if ( ref($borrowernumbers) eq 'ARRAY' );

    my $field  = (@cardnumbers) ? 'cardnumber' : 'borrowernumber';
    my @fields = (@cardnumbers) ? @cardnumbers : @borrowernumbers;
    my $placeholders = join( ',', ('?') x scalar @fields );

    my $dbh = C4::Context->dbh;

    $dbh->do( "DELETE FROM course_instructors WHERE course_id = ?", undef, $course_id )
      if ( $mode eq 'replace' );

    my $query;

    if ( $mode eq 'add' || $mode eq 'replace' ) {
        $query = "
            INSERT INTO course_instructors ( course_id, borrowernumber )
            SELECT ?, borrowernumber
            FROM borrowers
            WHERE $field IN ( $placeholders )
        ";
    } else {
        $query = "
            DELETE FROM course_instructors
            WHERE course_id = ?
            AND borrowernumber IN (
                SELECT borrowernumber FROM borrowers WHERE $field IN ( $placeholders )
            )
        ";
    }

    my $sth = $dbh->prepare($query);

    $sth->execute( $course_id, @fields ) if (@fields);
}

=head2 GetCourseItem {

  $course_item = GetCourseItem( itemnumber => $itemnumber [, ci_id => $ci_id );

=cut

sub GetCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id      = $params{'ci_id'};
    my $itemnumber = $params{'itemnumber'};

    return unless ( $itemnumber || $ci_id );

    my $field = ($itemnumber) ? 'itemnumber' : 'ci_id';
    my $value = ($itemnumber) ? $itemnumber  : $ci_id;

    my $query = "SELECT * FROM course_items WHERE $field = ?";
    my $dbh   = C4::Context->dbh;
    my $sth   = $dbh->prepare($query);
    $sth->execute($value);

    my $course_item = $sth->fetchrow_hashref();

    if ($course_item) {
        $query = "SELECT * FROM course_reserves WHERE ci_id = ?";
        $sth   = $dbh->prepare($query);
        $sth->execute( $course_item->{'ci_id'} );
        my $course_reserves = $sth->fetchall_arrayref( {} );

        $course_item->{'course_reserves'} = $course_reserves
          if ($course_reserves);
    }
    return $course_item;
}

=head2 ModCourseItem {

  ModCourseItem( %params );

  Creates or modifies an existing course item.

=cut

sub ModCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $itemnumber    = $params{'itemnumber'};
    my $itype         = $params{'itype'};
    my $ccode         = $params{'ccode'};
    my $holdingbranch = $params{'holdingbranch'};
    my $location      = $params{'location'};

    return unless ($itemnumber);

    my $course_item = GetCourseItem( itemnumber => $itemnumber );

    my $ci_id;

    if ($course_item) {
        $ci_id = $course_item->{'ci_id'};

        _UpdateCourseItem(
            ci_id       => $ci_id,
            course_item => $course_item,
            %params
        );
    } else {
        $ci_id = _AddCourseItem(%params);
    }

    return $ci_id;

}

=head2 _AddCourseItem

    my $ci_id = _AddCourseItem( %params );

=cut

sub _AddCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my ( @fields, @values );

    push( @fields, 'itemnumber = ?' );
    push( @values, $params{'itemnumber'} );

    foreach (@FIELDS) {
        if ( $params{$_} ) {
            push( @fields, "$_ = ?" );
            push( @values, $params{$_} );
        }
    }

    my $query = "INSERT INTO course_items SET " . join( ',', @fields );
    my $dbh = C4::Context->dbh;
    $dbh->do( $query, undef, @values );

    my $ci_id = $dbh->last_insert_id( undef, undef, 'course_items', 'ci_id' );

    return $ci_id;
}

=head2 _UpdateCourseItem

  _UpdateCourseItem( %params );

=cut

sub _UpdateCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id         = $params{'ci_id'};
    my $course_item   = $params{'course_item'};
    my $itype         = $params{'itype'};
    my $ccode         = $params{'ccode'};
    my $holdingbranch = $params{'holdingbranch'};
    my $location      = $params{'location'};

    return unless ( $ci_id || $course_item );

    $course_item = GetCourseItem( ci_id => $ci_id )
      unless ($course_item);
    $ci_id = $course_item->{'ci_id'} unless ($ci_id);

    ## Revert fields that had an 'original' value, but now don't
    ## Update the item fields to the stored values from course_items
    ## and then set those fields in course_items to NULL
    my @fields_to_revert;
    foreach (@FIELDS) {
        if ( !$params{$_} && $course_item->{$_} ) {
            push( @fields_to_revert, $_ );
        }
    }
    _RevertFields(
        ci_id       => $ci_id,
        fields      => \@fields_to_revert,
        course_item => $course_item
    ) if (@fields_to_revert);

    ## Update fields that still have an original value, but it has changed
    ## This necessitates only changing the current item values, as we still
    ## have the original values stored in course_items
    my %mod_params;
    foreach (@FIELDS) {
        if (   $params{$_}
            && $course_item->{$_}
            && $params{$_} ne $course_item->{$_} ) {
            $mod_params{$_} = $params{$_};
        }
    }
    ModItem( \%mod_params, undef, $course_item->{'itemnumber'} ) if %mod_params;

    ## Update fields that didn't have an original value, but now do
    ## We must save the original value in course_items, and also
    ## update the item fields to the new value
    my $item = GetItem( $course_item->{'itemnumber'} );
    my %mod_params_new;
    my %mod_params_old;
    foreach (@FIELDS) {
        if ( $params{$_} && !$course_item->{$_} ) {
            $mod_params_new{$_} = $params{$_};
            $mod_params_old{$_} = $item->{$_};
        }
    }
    _ModStoredFields( 'ci_id' => $params{'ci_id'}, %mod_params_old );
    ModItem( \%mod_params_new, undef, $course_item->{'itemnumber'} ) if %mod_params_new;

}

=head2 _ModStoredFields

    _ModStoredFields( %params );

    Updates the values for the 'original' fields in course_items
    for a given ci_id

=cut

sub _ModStoredFields {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    return unless ( $params{'ci_id'} );

    my ( @fields_to_update, @values_to_update );

    foreach (@FIELDS) {
        if ( $params{$_} ) {
            push( @fields_to_update, $_ );
            push( @values_to_update, $params{$_} );
        }
    }

    my $query = "UPDATE course_items SET " . join( ',', map { "$_=?" } @fields_to_update ) . " WHERE ci_id = ?";

    C4::Context->dbh->do( $query, undef, @values_to_update, $params{'ci_id'} )
      if (@values_to_update);

}

=head2 _RevertFields

    _RevertFields( ci_id => $ci_id, fields => \@fields_to_revert );

=cut

sub _RevertFields {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id       = $params{'ci_id'};
    my $course_item = $params{'course_item'};
    my $fields      = $params{'fields'};
    my @fields      = @$fields;

    return unless ($ci_id);

    $course_item = GetCourseItem( ci_id => $params{'ci_id'} )
      unless ($course_item);

    my $mod_item_params;
    my @fields_to_null;
    foreach my $field (@fields) {
        foreach (@FIELDS) {
            if ( $field eq $_ && $course_item->{$_} ) {
                $mod_item_params->{$_} = $course_item->{$_};
                push( @fields_to_null, $_ );
            }
        }
    }
    ModItem( $mod_item_params, undef, $course_item->{'itemnumber'} ) if $mod_item_params && %$mod_item_params;

    my $query = "UPDATE course_items SET " . join( ',', map { "$_=NULL" } @fields_to_null ) . " WHERE ci_id = ?";

    C4::Context->dbh->do( $query, undef, $ci_id ) if (@fields_to_null);
}

=head2 _SwapAllFields

    _SwapAllFields( $ci_id );

=cut

sub _SwapAllFields {
    my ($ci_id) = @_;
    warn "C4::CourseReserves::_SwapFields( $ci_id )" if $DEBUG;

    my $course_item = GetCourseItem( ci_id => $ci_id );
    my $item = GetItem( $course_item->{'itemnumber'} );

    my %course_item_fields;
    my %item_fields;
    foreach (@FIELDS) {
        if ( $course_item->{$_} ) {
            $course_item_fields{$_} = $course_item->{$_};
            $item_fields{$_}        = $item->{$_};
        }
    }

    ModItem( \%course_item_fields, undef, $course_item->{'itemnumber'} ) if %course_item_fields;
    _ModStoredFields( %item_fields, ci_id => $ci_id );
}

=head2 GetCourseItems {

  $course_items = GetCourseItems(
      [course_id => $course_id]
      [, itemnumber => $itemnumber ]
  );

=cut

sub GetCourseItems {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $course_id  = $params{'course_id'};
    my $itemnumber = $params{'itemnumber'};

    return unless ($course_id);

    my @query_keys;
    my @query_values;

    my $query = "SELECT * FROM course_items";

    if ( keys %params ) {

        $query .= " WHERE ";

        foreach my $key ( keys %params ) {
            push( @query_keys,   " $key LIKE ? " );
            push( @query_values, $params{$key} );
        }

        $query .= join( ' AND ', @query_keys );
    }

    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);
    $sth->execute(@query_values);

    return $sth->fetchall_arrayref( {} );
}

=head2 DelCourseItem {

  DelCourseItem( ci_id => $cr_id );

=cut

sub DelCourseItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id = $params{'ci_id'};

    return unless ($ci_id);

    _RevertFields( ci_id => $ci_id, fields => \@FIELDS );

    my $query = "
        DELETE FROM course_items
        WHERE ci_id = ?
    ";
    C4::Context->dbh->do( $query, undef, $ci_id );
}

=head2 GetCourseReserve {

  $course_item = GetCourseReserve( %params );

=cut

sub GetCourseReserve {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $cr_id     = $params{'cr_id'};
    my $course_id = $params{'course_id'};
    my $ci_id     = $params{'ci_id'};

    return unless ( $cr_id || ( $course_id && $ci_id ) );

    my $dbh = C4::Context->dbh;
    my $sth;

    if ($cr_id) {
        my $query = "
            SELECT * FROM course_reserves
            WHERE cr_id = ?
        ";
        $sth = $dbh->prepare($query);
        $sth->execute($cr_id);
    } else {
        my $query = "
            SELECT * FROM course_reserves
            WHERE course_id = ? AND ci_id = ?
        ";
        $sth = $dbh->prepare($query);
        $sth->execute( $course_id, $ci_id );
    }

    my $course_reserve = $sth->fetchrow_hashref();
    return $course_reserve;
}

=head2 ModCourseReserve

    $id = ModCourseReserve( %params );

=cut

sub ModCourseReserve {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $course_id   = $params{'course_id'};
    my $ci_id       = $params{'ci_id'};
    my $staff_note  = $params{'staff_note'};
    my $public_note = $params{'public_note'};

    return unless ( $course_id && $ci_id );

    my $course_reserve = GetCourseReserve( course_id => $course_id, ci_id => $ci_id );
    my $cr_id;

    my $dbh = C4::Context->dbh;

    if ($course_reserve) {
        $cr_id = $course_reserve->{'cr_id'};

        my $query = "
            UPDATE course_reserves
            SET staff_note = ?, public_note = ?
            WHERE cr_id = ?
        ";
        $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
    } else {
        my $query = "
            INSERT INTO course_reserves SET
            course_id = ?,
            ci_id = ?,
            staff_note = ?,
            public_note = ?
        ";
        $dbh->do( $query, undef, $course_id, $ci_id, $staff_note, $public_note );
        $cr_id = $dbh->last_insert_id( undef, undef, 'course_reserves', 'cr_id' );
    }

    my $course = GetCourse($course_id);
    EnableOrDisableCourseItem(
        ci_id   => $params{'ci_id'},
        enabled => $course->{'enabled'}
    );

    return $cr_id;
}

=head2 GetCourseReserves {

  $course_reserves = GetCourseReserves( %params );

  Required:
      course_id OR ci_id
  Optional:
      include_items   => 1,
      include_count   => 1,
      include_courses => 1,

=cut

sub GetCourseReserves {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $course_id       = $params{'course_id'};
    my $ci_id           = $params{'ci_id'};
    my $include_items   = $params{'include_items'};
    my $include_count   = $params{'include_count'};
    my $include_courses = $params{'include_courses'};

    return unless ( $course_id || $ci_id );

    my $field = ($course_id) ? 'course_id' : 'ci_id';
    my $value = ($course_id) ? $course_id  : $ci_id;

    my $query = "
        SELECT cr.*, ci.itemnumber
        FROM course_reserves cr, course_items ci
        WHERE cr.$field = ?
        AND cr.ci_id = ci.ci_id
    ";
    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);
    $sth->execute($value);

    my $course_reserves = $sth->fetchall_arrayref( {} );

    if ($include_items) {
        foreach my $cr (@$course_reserves) {
            $cr->{'course_item'} = GetCourseItem( ci_id => $cr->{'ci_id'} );
            $cr->{'item'}        = GetBiblioFromItemNumber( $cr->{'itemnumber'} );
            $cr->{'issue'}       = GetOpenIssue( $cr->{'itemnumber'} );
        }
    }

    if ($include_count) {
        foreach my $cr (@$course_reserves) {
            $cr->{'reserves_count'} = CountCourseReservesForItem( ci_id => $cr->{'ci_id'} );
        }
    }

    if ($include_courses) {
        foreach my $cr (@$course_reserves) {
            $cr->{'courses'} = GetCourses( itemnumber => $cr->{'itemnumber'} );
        }
    }

    return $course_reserves;
}

=head2 DelCourseReserve {

  DelCourseReserve( cr_id => $cr_id );

=cut

sub DelCourseReserve {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $cr_id = $params{'cr_id'};

    return unless ($cr_id);

    my $dbh = C4::Context->dbh;

    my $course_reserve = GetCourseReserve( cr_id => $cr_id );

    my $query = "
        DELETE FROM course_reserves
        WHERE cr_id = ?
    ";
    $dbh->do( $query, undef, $cr_id );

    ## If there are no other course reserves for this item
    ## delete the course_item as well
    unless ( CountCourseReservesForItem( ci_id => $course_reserve->{'ci_id'} ) ) {
        DelCourseItem( ci_id => $course_reserve->{'ci_id'} );
    }

}

=head2 GetReservesInfo

    my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );

    For a given item, returns an arrayref of reserves hashrefs,
    with a course hashref under the key 'course'

=cut

sub GetItemCourseReservesInfo {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $itemnumber = $params{'itemnumber'};

    return unless ($itemnumber);

    my $course_item = GetCourseItem( itemnumber => $itemnumber );

    return unless ( keys %$course_item );

    my $course_reserves = GetCourseReserves( ci_id => $course_item->{'ci_id'} );

    foreach my $cr (@$course_reserves) {
        $cr->{'course'} = GetCourse( $cr->{'course_id'} );
    }

    return $course_reserves;
}

=head2 CountCourseReservesForItem

    $bool = CountCourseReservesForItem( %params );

    ci_id - course_item id
    OR
    itemnumber - course_item itemnumber

    enabled = 'yes' or 'no'
    Optional, if not supplied, counts reserves
    for both enabled and disabled courses

=cut

sub CountCourseReservesForItem {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $ci_id      = $params{'ci_id'};
    my $itemnumber = $params{'itemnumber'};
    my $enabled    = $params{'enabled'};

    return unless ( $ci_id || $itemnumber );

    my $course_item = GetCourseItem( ci_id => $ci_id, itemnumber => $itemnumber );

    my @params = ( $course_item->{'ci_id'} );
    push( @params, $enabled ) if ($enabled);

    my $query = "
        SELECT COUNT(*) AS count
        FROM course_reserves cr
        LEFT JOIN courses c ON ( c.course_id = cr.course_id )
        WHERE ci_id = ?
    ";
    $query .= "AND c.enabled = ?" if ($enabled);

    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);
    $sth->execute(@params);

    my $row = $sth->fetchrow_hashref();

    return $row->{'count'};
}

=head2 SearchCourses

    my $courses = SearchCourses( term => $search_term, enabled => 'yes' );

=cut

sub SearchCourses {
    my (%params) = @_;
    warn identify_myself(%params) if $DEBUG;

    my $term = $params{'term'};

    my $enabled = $params{'enabled'} || '%';

    my @params;
    my $query = "SELECT c.* FROM courses c";

    $query .= "
        LEFT JOIN course_instructors ci
            ON ( c.course_id = ci.course_id )
        LEFT JOIN borrowers b
            ON ( ci.borrowernumber = b.borrowernumber )
        LEFT JOIN authorised_values av
            ON ( c.department = av.authorised_value )
        WHERE
            ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
            AND
            (
                department LIKE ? OR
                course_number LIKE ? OR
                section LIKE ? OR
                course_name LIKE ? OR
                term LIKE ? OR
                public_note LIKE ? OR
                CONCAT(surname,' ',firstname) LIKE ? OR
                CONCAT(firstname,' ',surname) LIKE ? OR
                lib LIKE ? OR
                lib_opac LIKE ?
           )
           AND
           c.enabled LIKE ?
        GROUP BY c.course_id
    ";

    $term //= '';
    $term   = "%$term%";
    @params = ($term) x 10;

    $query .= " ORDER BY department, course_number, section, term, course_name ";

    my $dbh = C4::Context->dbh;
    my $sth = $dbh->prepare($query);

    $sth->execute( @params, $enabled );

    my $courses = $sth->fetchall_arrayref( {} );

    foreach my $c (@$courses) {
        $c->{'instructors'} = GetCourseInstructors( $c->{'course_id'} );
    }

    return $courses;
}

sub whoami  { ( caller(1) )[3] }
sub whowasi { ( caller(2) )[3] }

sub stringify_params {
    my (%params) = @_;

    my $string = "\n";

    foreach my $key ( keys %params ) {
        $string .= "    $key => " . $params{$key} . "\n";
    }

    return "( $string )";
}

sub identify_myself {
    my (%params) = @_;

    return whowasi() . stringify_params(%params);
}

1;

=head1 AUTHOR

Kyle M Hall <kyle@bywatersolutions.com>

=cut
