package OpenILS::Application::Courses;

use strict;
use warnings;

use OpenSRF::AppSession;
use OpenILS::Application;
use base qw/OpenILS::Application/;

use OpenILS::Utils::CStoreEditor qw/:funcs/;
use OpenILS::Utils::Fieldmapper;
use OpenILS::Application::AppUtils;
my $U = "OpenILS::Application::AppUtils";

use OpenSRF::Utils::Logger qw/$logger/;

__PACKAGE__->register_method(
    method          => 'attach_electronic_resource_to_course',
    api_name        => 'open-ils.courses.attach.electronic_resource',
    signature => {
        desc => 'Attaches a bib record for an electronic resource to a course',
        params => [
            {desc => 'Authentication token', type => 'string'},
            {desc => 'Record id', type => 'number'},
            {desc => 'Course id', type => 'number'},
            {desc => 'Relationship', type => 'string'}
        ],
        return => {desc => '1 on success, event on failure'}
    });
sub attach_electronic_resource_to_course {
    my ($self, $conn, $authtoken, $record, $course, $relationship) = @_;
    my $e = new_editor(authtoken=>$authtoken, xact=>1);
    return $e->die_event unless $e->checkauth;
    return $e->die_event unless
        $e->allowed('MANAGE_RESERVES');

    my $located_uris = $e->search_asset_call_number({
        record => $record,
        deleted => 'f',
        label => '##URI##' })->[0];
    my $bib = $e->retrieve_biblio_record_entry([
        $record, {
            flesh => 1,
            flesh_fields => {'bre' => ['source']}
        }
    ]);
    return $e->event unless (($bib->source && $bib->source->transcendant) || $located_uris);
    _attach_bib($e, $course, $record, $relationship, 0);

    return 1;
}

__PACKAGE__->register_method(
    method          => 'attach_brief_bib_to_course',
    api_name        => 'open-ils.courses.attach.biblio_record',
    signature => {
        desc => 'Creates a new bib record with the provided XML, and attaches it to a course',
        params => [
            {desc => 'Authentication token', type => 'string'},
            {desc => 'XML', type => 'string'},
            {desc => 'Course id', type => 'number'},
            {desc => 'Relationship', type => 'string'}
        ],
        return => {desc => '1 on success, event on failure'}
    });
sub attach_brief_bib_to_course {
    my ($self, $conn, $authtoken, $marcxml, $course, $relationship) = @_;
    my $e = new_editor(authtoken=>$authtoken, xact=>1);
    return $e->die_event unless $e->checkauth;
    return $e->die_event unless $e->allowed('MANAGE_RESERVES');
    return $e->die_event unless $e->allowed('CREATE_MARC');

    my $bib_source_id = $U->ou_ancestor_setting_value($self->{ou}, 'circ.course_materials_brief_record_bib_source');
    my $bib_source_name;
    if ($bib_source_id) {
        $bib_source_name = $e->retrieve_config_bib_source($bib_source_id)->source;
    } else {
        # The default value from the seed data
        $bib_source_name = 'Course materials module';
    }

    my $bib_create = OpenSRF::AppSession
        ->create('open-ils.cat')
        ->request('open-ils.cat.biblio.record.xml.create',
            $authtoken, $marcxml, $bib_source_name)
        ->gather(1);
    _attach_bib($e, $course, $bib_create->id, $relationship, 1) if ($bib_create);
    return 1;
}

# Shared logic for both e-resources and brief bibs
sub _attach_bib {
    my ($e, $course, $record, $relationship, $temporary) = @_;
    my $acmcm = Fieldmapper::asset::course_module_course_materials->new;
    $acmcm->course($course);
    $acmcm->record($record);
    $acmcm->relationship($relationship);
    $acmcm->temporary_record($temporary);
    $e->create_asset_course_module_course_materials( $acmcm ) or return $e->die_event;
    $e->commit;
}

__PACKAGE__->register_method(
    method          => 'fetch_course_materials',
    autoritative    => 1,
    stream          => 1,
    api_name        => 'open-ils.courses.course_materials.retrieve',
    signature       => q/
        Returns an array of course materials.
        @params args     : Supplied object to filter search.
    /);

__PACKAGE__->register_method(
    method          => 'fetch_course_materials',
    autoritative    => 1,
    stream          => 1,
    api_name        => 'open-ils.courses.course_materials.retrieve.fleshed',
    signature       => q/
        Returns an array of course materials, each fleshed out with information
        from the item and the course_material object.
        @params args     : Supplied object to filter search.
    /);

sub fetch_course_materials {
    my ($self, $conn, $args) = @_;
    my $e = new_editor();
    my $materials;

    if ($self->api_name =~ /\.fleshed/) {
        my $fleshing = {
            'flesh' => 2, 'flesh_fields' => {
                'acmcm' => ['item', 'record', 'original_circ_modifier',
                    'original_location', 'original_status'],
                'acp' => ['call_number', 'circ_lib', 'location', 'status'],
                'bre' => ['wide_display_entry'],
            }
        };
        $materials = $e->search_asset_course_module_course_materials([$args, $fleshing]);
    } else {
        $materials = $e->search_asset_course_module_course_materials($args);
    }
    $conn->respond($_) for @$materials;
    $conn->respond_complete();
    return undef;
}

__PACKAGE__->register_method(
    method          => 'fetch_courses',
    autoritative    => 1,
    api_name        => 'open-ils.courses.courses.retrieve',
    signature       => q/
        Returns an array of course materials.
        @params course_id: The id of the course we want to retrieve
    /);

sub fetch_courses {
    my ($self, $conn, @course_ids) = @_;
    my $e = new_editor();

    return unless @course_ids;
    my $targets = ();
    foreach my $course_id (@course_ids) {
        my $target = $e->retrieve_asset_course_module_course($course_id);
        push @$targets, $target;
    }

    return $targets;
}

__PACKAGE__->register_method(
    method          => 'fetch_course_users',
    autoritative    => 1,
    api_name        => 'open-ils.courses.course_users.retrieve',
    signature       => q/
        Returns an array of course users.
        @params course_id: The id of the course we want to retrieve from
    /);
__PACKAGE__->register_method(
    method          => 'fetch_course_users',
    autoritative    => 1,
    api_name        => 'open-ils.courses.course_users.retrieve.staff',
    signature       => q/
        Returns an array of course users.
        @params course_id: The id of the course we want to retrieve from
    /);

sub fetch_course_users {
    my ($self, $conn, $course_id) = @_;
    my $e = new_editor();

    return $e->json_query({
        select => {
            acmcu => ['id'],
            acmr => [{column => 'name', alias => 'usr_role'}],
            au => [{column => 'id', alias => 'patron_id'},
                'first_given_name', 'second_given_name',
                'family_name', 'pref_first_given_name',
                'pref_second_given_name', 'pref_family_name',
                'pref_suffix', 'pref_prefix'],
        },
        from => { acmcu => {'acmr' => {}, 'au' => {}} },
        where => {
            '+acmcu' => { course => $course_id },
            '+acmr' => {'is_public' => 't'}
        },
    });

}

__PACKAGE__->register_method(
    method          => 'detach_material',
    api_name        => 'open-ils.courses.detach_material',
    signature => {
        desc => 'Detaches a material from a course',
        params => [
            {desc => 'Authentication token', type => 'string'},
            {desc => 'Course material id', type => 'number'},
        ],
        return => {desc => '1 on success, event on failure'}
    });
sub detach_material {
    my ($self, $conn, $authtoken, $acmcm_id) = @_;
    my $e = new_editor(authtoken=>$authtoken, xact=>1);
    return $e->die_event unless $e->checkauth;
    return $e->die_event unless
        $e->allowed('MANAGE_RESERVES');
    my $acmcm = $e->retrieve_asset_course_module_course_materials($acmcm_id)
        or return $e->die_event;
    my $bre_id_to_delete = $acmcm->temporary_record ? $acmcm->record : 0;
    if ($bre_id_to_delete) {
        # delete any attached located URIs
        my $located_uri_cn_ids = $e->search_asset_call_number(
            {record=>$bre_id_to_delete}, {idlist=>1});

        for my $cn_id (@$located_uri_cn_ids) {
            $e->delete_asset_call_number(
                $e->retrieve_asset_call_number($cn_id))
                or return $e->die_event;
        }
        OpenSRF::AppSession
            ->create('open-ils.cat')
            ->request('open-ils.cat.biblio.record_entry.delete',
                $authtoken, $bre_id_to_delete);
    }
    if ($acmcm->item) {
        _resetItemFields($e, $authtoken, $acmcm);
    } 

    $e->delete_asset_course_module_course_materials($acmcm) or return $e->die_event;
    $e->commit;
    return 1;
}

sub _resetItemFields {
    my ($e, $authtoken, $acmcm) = @_;
    my $cat_sess = OpenSRF::AppSession->connect('open-ils.cat');
    my $acp = $e->retrieve_asset_copy($acmcm->item);
    my $course_lib = $e->retrieve_asset_course_module_course($acmcm->course)->owning_lib;
    if ($acmcm->original_status) {
        $acp->status($acmcm->original_status);
    }
    if ($acmcm->original_circ_modifier) {
        $acp->circ_modifier($acmcm->original_circ_modifier);
    }
    if ($acmcm->original_location) {
        $acp->location($acmcm->original_location);
    }
    $e->update_asset_copy($acmcm);
    if ($acmcm->original_callnumber) {
        my $existing_acn = $e->retrieve_asset_call_number($acp->call_number);
        my $orig_acn = $e->retrieve_asset_call_number($acmcm->original_callnumber);
        # Let's attach to an existing call number, if one exists with the original label
        # and other appropriate specifications
        my $dest_acn = $cat_sess->request('open-ils.cat.call_number.find_or_create',
            $authtoken, $orig_acn->label,
            $existing_acn->record, $course_lib,
            $existing_acn->prefix, $existing_acn->suffix,
            $existing_acn->label_class)->gather(1);
        my $acn_id = $dest_acn->{acn_id};
        $cat_sess->request('open-ils.cat.transfer_copies_to_volume',
            $authtoken, $acn_id, [$acp->id]);
    }
}



1;

