use strict;
use warnings;

package Net::Amazon::Route53::ResourceRecordSet;
BEGIN {
  $Net::Amazon::Route53::ResourceRecordSet::VERSION = '0.111300';
}
use Mouse;
use XML::Bare;
use HTML::Entities;

=head2 SYNOPSIS

    my $resource = Net::Amazon::Route53::ResourceRecordSet->new(...);
    # use methods on $resource

=cut

=head2 ATTRIBUTES

=cut

=head3 route53

A L<Net::Amazon::Route53> object, needed and used to perform requests
to Amazon's Route 53 service

=head3 hostedzone

The L<Net::Amazon::Route53::HostedZone> object this hosted zone refers to

=cut

has 'route53' => ( is => 'rw', isa => 'Net::Amazon::Route53', required => 1, );
has 'hostedzone' =>
  ( is => 'rw', isa => 'Net::Amazon::Route53::HostedZone', required => 1 );

=head3 name

The name for this resource record

=head3 ttl

The TTL associated with this resource record

=head3 type

The type of this resource record (C<A>, C<AAAA>, C<NS>, etc)

=head3 values

The values associated with this resource record.

=cut

has 'name' => ( is => 'rw', isa => 'Str', required => 1 );
has 'ttl'  => ( is => 'rw', isa => 'Int', required => 1 );
has 'type' => ( is => 'rw', isa => 'Str', required => 1 );
has 'values' =>
  ( is => 'rw', isa => 'ArrayRef', required => 1, default => sub { [] } );

=head2 METHODS

=cut

=head3 create

    my $record = Net::Amazon::Route53::ResourceRecordSet->new( ... );
    $record->create;

Creates a new record. Needs all the attributes (name, ttl, type and values).

Takes an optional boolean parameter, C<wait>, to indicate whether the request should
return straightaway (default, or when C<wait> is C<0>) or it should wait until the
request is C<INSYNC> according to the Change's status.

Returns a L<Net::Amazon::Route53::Change> object representing the change requested.

=cut

sub create {
    my $self = shift;
    my $wait = shift;
    $wait = 0 if !defined $wait;
    $self->name =~ /\.$/
      or die "Zone name needs to end in a dot, to be created\n";
    my $request_xml_str = <<'ENDXML';
<?xml version="1.0" encoding="UTF-8"?>
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2010-10-01/">
   <ChangeBatch>
      <Comment>This change batch creates the %s record for %s</Comment>
      <Changes>
        <Change>
            <Action>CREATE</Action>
            <ResourceRecordSet>
               <Name>%s</Name>
               <Type>%s</Type>
               <TTL>%s</TTL>
               <ResourceRecords>
                  %s
               </ResourceRecords>
            </ResourceRecordSet>
         </Change>
        </Changes>
   </ChangeBatch>
</ChangeResourceRecordSetsRequest>
ENDXML
    my $request_xml = sprintf(
        $request_xml_str,
        map { $_ } $self->type,
        $self->name,
        $self->name,
        $self->type,
        $self->ttl,
        join( "\n",
            map { "<ResourceRecord><Value>$_</Value></ResourceRecord>" }
              @{ $self->values } )
    );
    my $resp = $self->route53->request(
        'post',
        'https://route53.amazonaws.com/2010-10-01/'
          . $self->hostedzone->id
          . '/rrset',
        Content => $request_xml
    );
    my $change = Net::Amazon::Route53::Change->new(
        route53 => $self->route53,
        (
            map { lc($_) => decode_entities( $resp->{ChangeInfo}{$_} ) }
              qw/Id Status SubmittedAt/
        ),
    );
    $change->refresh();
    return $change if !$wait;

    while ( lc( $change->status ) ne 'insync' ) {
        sleep 2;
        $change->refresh();
    }
    return $change;
}

=head3 delete

    $rrs->delete();

Asks Route 53 to delete the associated record. This should be used only when
you want to delete the resource, not when changing a resource. In that case,
use the C<change> method instead, which takes care of creating a unique change
in which the record is first deleted with the current details and then created
with the new details.

Takes an optional boolean parameter, C<wait>, to indicate whether the request should
return straightaway (default, or when C<wait> is C<0>) or it should wait until the
request is C<INSYNC> according to the Change's status.

Returns a L<Net::Amazon::Route53::Change> object representing the change requested.

=cut

sub delete {
    my $self = shift;
    my $wait = shift;
    $wait = 0 if !defined $wait;
    my $request_xml_str = <<'ENDXML';
<?xml version="1.0" encoding="UTF-8"?>
<ChangeResourceRecordSetsRequest xmlns="https://route53.amazonaws.com/doc/2010-10-01/">
   <ChangeBatch>
      <Comment>This change batch deletes the %s record for %s</Comment>
      <Changes>
        <Change>
            <Action>DELETE</Action>
            <ResourceRecordSet>
               <Name>%s</Name>
               <Type>%s</Type>
               <TTL>%s</TTL>
               <ResourceRecords>
                  %s
               </ResourceRecords>
            </ResourceRecordSet>
         </Change>
        </Changes>
   </ChangeBatch>
</ChangeResourceRecordSetsRequest>
ENDXML
    my $request_xml = sprintf(
        $request_xml_str,
        (
            map { $_ } (
                $self->type, $self->name, $self->name, $self->type, $self->ttl
            )
        ),
        join(
            "\n",
            map { "<ResourceRecord><Value>" . $_ . "</Value></ResourceRecord>" }
              @{ $self->values }
        )
    );
    my $resp = $self->route53->request(
        'post',
        'https://route53.amazonaws.com/2010-10-01/'
          . $self->hostedzone->id
          . '/rrset',
        Content => $request_xml
    );
    my $change = Net::Amazon::Route53::Change->new(
        route53 => $self->route53,
        (
            map { lc($_) => decode_entities( $resp->{ChangeInfo}{$_} ) }
              qw/Id Status SubmittedAt/
        ),
    );
    $change->refresh();
    return $change if !$wait;

    while ( lc( $change->status ) ne 'insync' ) {
        sleep 2;
        $change->refresh();
    }
    return $change;
}

no Mouse;

=head1 AUTHOR

Marco FONTANI <mfontani@cpan.org>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2011 by Marco FONTANI.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut

1;
