#
#  Copyright 2014 MongoDB, Inc.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#

use strict;
use warnings;
package MongoDB::WriteConcern;

# ABSTRACT: Encapsulate and validate a write concern

use version;
our $VERSION = 'v1.6.0';

use Moo;
use MongoDB::Error;
use MongoDB::_Types qw(
    Booleanpm
);
use Types::Standard qw(
    Bool
    ArrayRef
    Num
    Str
    Maybe
);
use Scalar::Util qw/looks_like_number/;
use namespace::clean -except => 'meta';

#pod =attr w
#pod
#pod Specifies the desired acknowledgement level. Defaults to '1'.
#pod
#pod =cut

has w => (
    is        => 'ro',
    isa       => Maybe [Str],
    predicate => '_has_w',
);

#pod =attr wtimeout
#pod
#pod Specifies how long to wait for the write concern to be satisfied (in
#pod milliseconds).  Defaults to 1000.
#pod
#pod =cut

has wtimeout => (
    is        => 'ro',
    isa       => Num,
    predicate => '_has_wtimeout',
    default   => 1000,
);

#pod =attr j
#pod
#pod The j option confirms that the mongod instance has written the data to the
#pod on-disk journal.  Defaults to false.
#pod
#pod B<Note>: specifying a write concern that set j to a true value may result in an
#pod error with a mongod or mongos running with --nojournal option now errors.
#pod
#pod =cut

has j => (
    is        => 'ro',
    isa       => Booleanpm,
    coerce    => Booleanpm->coercion,
    predicate => '_has_j',
);

has _is_acknowledged => (
    is      => 'lazy',
    isa     => Bool,
    reader  => 'is_acknowledged',
    builder => '_build_is_acknowledged',
);

has _as_args => (
    is      => 'lazy',
    isa     => ArrayRef,
    reader  => 'as_args',
    builder => '_build_as_args',
);

sub _build_is_acknowledged {
    my ($self) = @_;
    return !!( $self->j || $self->_w_is_acknowledged );
}

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

    my $wc = {
        ( $self->_has_w        ? ( w        => $self->w )           : () ),
        ( $self->_has_wtimeout ? ( wtimeout => 0+ $self->wtimeout ) : () ),
        ( $self->_has_j        ? ( j        => $self->j )           : () ),
    };

    return ( (defined $self->w || defined $self->j) ? [writeConcern => $wc] : [] );
}

sub BUILD {
    my ($self) = @_;
    if ( ! $self->_w_is_acknowledged && $self->j ) {
        MongoDB::UsageError->throw("can't use write concern w=0 with j=" . $self->j );
    }
    return;
}

sub _w_is_acknowledged {
    my ($self) = @_;
    return ($self->_has_w
      && ( looks_like_number( $self->w ) ? $self->w > 0 : length $self->w ))
      || !defined $self->w;
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

MongoDB::WriteConcern - Encapsulate and validate a write concern

=head1 VERSION

version v1.6.0

=head1 SYNOPSIS

    $rp = MongoDB::WriteConcern->new(); # w:1, wtimeout: 1000

    $rp = MongoDB::WriteConcern->new(
        w        => 'majority',
        wtimeout => 10000, # milliseconds
    );

=head1 DESCRIPTION

A write concern describes the guarantee that MongoDB provides when reporting on
the success of a write operation.

For core documentation on read preference see
L<http://docs.mongodb.org/manual/core/read-preference/>.

=head1 ATTRIBUTES

=head2 w

Specifies the desired acknowledgement level. Defaults to '1'.

=head2 wtimeout

Specifies how long to wait for the write concern to be satisfied (in
milliseconds).  Defaults to 1000.

=head2 j

The j option confirms that the mongod instance has written the data to the
on-disk journal.  Defaults to false.

B<Note>: specifying a write concern that set j to a true value may result in an
error with a mongod or mongos running with --nojournal option now errors.

=head1 AUTHORS

=over 4

=item *

David Golden <david@mongodb.com>

=item *

Rassi <rassi@mongodb.com>

=item *

Mike Friedman <friedo@friedo.com>

=item *

Kristina Chodorow <k.chodorow@gmail.com>

=item *

Florian Ragwitz <rafl@debian.org>

=back

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2016 by MongoDB, Inc.

This is free software, licensed under:

  The Apache License, Version 2.0, January 2004

=cut
