# ************************************************************************* 
# Copyright (c) 2014, SUSE LLC
# 
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 
# 3. Neither the name of SUSE LLC nor the names of its contributors may be
# used to endorse or promote products derived from this software without
# specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ************************************************************************* 

package App::Dochazka::REST::Model::Schedhistory;

use 5.012;
use strict;
use warnings FATAL => 'all';
use App::CELL qw( $CELL $log $meta $site );
use Carp;
use Data::Dumper;
use App::Dochazka::REST::Model::Shared qw( load cud );
use DBI;
use Params::Validate qw( :all );

use parent 'App::Dochazka::REST::dbh';


=head1 NAME

App::Dochazka::REST::Model::Schedhistory - schedule history functions




=head1 VERSION

Version 0.135

=cut

our $VERSION = '0.135';




=head1 SYNOPSIS

    use App::Dochazka::REST::Model::Schedhistory;

    ...



=head1 DESCRIPTION

A description of the schedhistory data model follows.


=head2 Schedhistory in the database

=head3 Table

Once we know the SID of the schedule we would like to assign to a given
employee, it is time to insert a record into the C<schedhistory> table:

      CREATE TABLE IF NOT EXISTS schedhistory (
        shid       serial PRIMARY KEY,
        eid        integer REFERENCES employees (eid) NOT NULL,
        sid        integer REFERENCES schedules (sid) NOT NULL,
        effective  timestamp NOT NULL,
        remark     text,
        stamp      json
      );

=head3 Stored procedures

This table also includes two stored procedures -- C<schedule_at_timestamp> and
C<current_schedule> -- which will return an employee's schedule as of a given
date/time and as of 'now', respectively. For the procedure definitions, see
C<dbinit_Config.pm>

See also L<When history changes take effect>.


=head2 Schedhistory in the Perl API

=over

=item * constructor (L<spawn>)

=item * L<reset> method (recycles an existing object)

=item * basic accessors (L<shid>, L<eid>, L<sid>, L<effective>, L<remark>)

=item * L<load_by_eid> method (load schedhistory record from EID and optional timestamp)

=item * L<load_by_shid> method (load schedhistory record by its SHID)

=item * L<insert> method (straightforward)

=item * L<delete> method (straightforward) -- not tested yet # FIXME

=back

For basic workflow, see C<t/007-schedule.t>.




=head1 EXPORTS

This module provides the following exports:

=over 

=back

=cut

use Exporter qw( import );
our @EXPORT_OK = qw( );




=head1 METHODS

=head2 spawn

Constructor. See Employee.pm->spawn for general comments.

=cut

BEGIN {
    no strict 'refs';
    *{"spawn"} = App::Dochazka::REST::Model::Shared::make_spawn();
}



=head2 reset

Boilerplate.

=cut

BEGIN {
    no strict 'refs';
    *{"reset"} = App::Dochazka::REST::Model::Shared::make_reset(
        'shid', 'eid', 'sid', 'effective', 'remark' 
    );
}



=head2 Accessor methods

Boilerplate.

=cut

BEGIN {
    foreach my $subname ( 'shid', 'eid', 'sid', 'effective', 'remark') {
        no strict 'refs';
        *{"$subname"} = App::Dochazka::REST::Model::Shared::make_accessor( $subname );
    }   
}

=head3 shid

Accessor method.


=head3 eid

Accessor method.


=head3 sid

Accessor method.


=head3 effective

Accessor method.


=head3 remark

Accessor method.



=head2 load_by_eid

Class method. Given an EID, and, optionally, a timestamp, attempt to 
look it up in the database. Generate a status object: if a schedhistory 
record is found, it will be in the payload and the code will be
'DISPATCH_RECORDS_FOUND'.

=cut

sub load_by_eid {
    my $self = shift;
    my ( $eid, $ts ) = validate_pos( @_, 
        { type => SCALAR },                # EID
        { type => SCALAR, optional => 1 }, # optional timestamp
    );

    if ( $ts ) {
        return load(
            class => __PACKAGE__,
            sql => $site->SQL_SCHEDHISTORY_SELECT_ARBITRARY,
            keys => [ $eid, $ts ],
        );
    }

    return load(
        class => __PACKAGE__,
        sql => $site->SQL_SCHEDHISTORY_SELECT_CURRENT,
        keys => [ $eid ],
    );
}
    


=head2 load_by_shid

Given a shid, load a single schedhistory record.

=cut

sub load_by_shid {
    my $self = shift;
    my ( $shid ) = validate_pos( @_, { type => SCALAR } );

    return load(
        class => __PACKAGE__,
        sql => $site->SQL_SCHEDHISTORY_SELECT_BY_SHID,
        keys => [ $shid ],
    );
}


=head2 insert

Instance method. Attempts to INSERT a record into the 'Schedhistory' table.
Field values are taken from the object. Returns a status object.

=cut

sub insert {
    my ( $self ) = @_;

    my $status = cud(
        object => $self,
        sql => $site->SQL_SCHEDHISTORY_INSERT,
        attrs => [ 'eid', 'sid', 'effective', 'remark' ],
    );

    return $status;
}


=head2 update

There is no update method for schedhistory records. Instead, delete and
re-create.


=head2 delete

Instance method. Deletes the record. Returns status object.

=cut

sub delete {
    my ( $self ) = @_;

    my $status = cud(
        object => $self,
        sql => $site->SQL_SCHEDHISTORY_DELETE,
        attrs => [ 'shid' ],
    );
    $self->reset( 'shid' => $self->{shid} ) if $status->ok;

    return $status;
}




=head1 EXAMPLES

In this section, some examples are presented to give an idea of how this
module is used.


=head2 Sam Wallace joins the firm

Let's say Sam's initial schedule is 09:00-17:00, Monday to Friday. To
reflect that, the C<schedintvls> table might contain the following intervals
for C<< sid = 9 >>

    '[2014-06-02 09:00, 2014-06-02 17:00)'
    '[2014-06-03 09:00, 2014-06-03 17:00)'
    '[2014-06-04 09:00, 2014-06-04 17:00)'
    '[2014-06-05 09:00, 2014-06-05 17:00)'
    '[2014-06-06 09:00, 2014-06-06 17:00)'

and the C<schedhistory> table would contain a record like this:

    shid      848 (automatically assigned by PostgreSQL)
    eid       39 (Sam's Dochazka EID)
    sid       9
    effective '2014-06-04 00:00'

(This is a straightfoward example.)


=head2 Sam goes on night shift

A few months later, Sam gets assigned to the night shift. A new
C<schedhistory> record is added:

    shid     1215 (automatically assigned by PostgreSQL)
    eid        39 (Sam's Dochazka EID)
    sid        17 (link to Sam's new weekly work schedule)
    effective  '2014-11-17 12:00'

And the schedule intervals for C<< sid = 17 >> could be:

    '[2014-06-02 23:00, 2014-06-03 07:00)'
    '[2014-06-03 23:00, 2014-06-04 07:00)'
    '[2014-06-04 23:00, 2014-06-05 07:00)'
    '[2014-06-05 23:00, 2014-06-06 07:00)'
    '[2014-06-06 23:00, 2014-06-07 07:00)'
    
(Remember: the date part in this case designates the day of the week)




=head1 AUTHOR

Nathan Cutler, C<< <presnypreklad@gmail.com> >>

=cut 

1;



