package MMM::Mirror;

use strict;
use warnings;
use URI;
use POSIX qw(strftime);
use MMM::Host;

=head1 NAME

MMM::Mirror

=head1 DESCRIPTION

An object to retain per mirror information

=head1 METHODS

=head2 new

Create a MMM::Mirror object from information found in hash passed
as arguments.

    my $mirror MMM::Mirror->new( url => 'rsync://host/foo/' );

=cut

sub _rev {
    strftime( '%Y%m%d%H%M%S', gmtime(time) );
}

sub new {
    my ( $class, %infos ) = @_;
    $infos{url} or return;
    $infos{uri} ||= URI->new( $infos{url} );
    $infos{uri} && $infos{uri}->can('host') or return;
    my $path = $infos{uri}->path;
    $path =~ s://*:/:g;
    $infos{url} = sprintf( "%s://%s%s%s",
        $infos{uri}->scheme, lc( $infos{uri}->authority ),
        $path, ( $infos{uri}->query ? '?' . $infos{uri}->query : '' ) );
    $infos{host} = lc( $infos{uri}->host() );
    $infos{hostinfo} ||=
      MMM::Host->new( %infos, hostname => $infos{uri}->host );
    $infos{revision} ||= _rev();
    bless( {%infos}, $class );
}

=head2 url

Return the url of the mirror

=cut

sub url {
    my ($self) = @_;
    $self->{url};
}

=head2 host

Return the hostname of the mirror found in url

=cut

sub host {
    my ($self) = @_;
    return $self->{host};
}

=head2 level

Return the level of this mirror in mirrors hierarchy

=cut

sub level {
    my ($self) = @_;
    defined( $self->{level} ) ? $self->{level} : 3;
}

=head2 frequency

Period in minutes between sync performed by this mirror

=cut

sub frequency {
    my ($self) = @_;
    $self->{frequency} || 120;
}

=head2 source

Return the mirror source name from which this mirror is part of.

=cut

sub source {
    my ($self) = @_;
    $self->{source};
}

=head2 set_source($source)

Set the source name for this mirror.

=cut

sub set_source {
    my ( $self, $source ) = @_;
    $self->{source} = $source;
}

=head2 hostinfo

Return a MMM::Host object proper to the mirror if any

=cut

sub hostinfo {
    my ($self) = @_;
    return $self->{hostinfo};
}

=head2 get_geo

Load host geo info if any

=cut

sub get_geo {
    my ($self) = @_;
    if($self->{hostinfo}->get_geo()) {
        return 1;
    } else {
        return;
    }
}

=head2 random

Return a cached random value assigned to this mirror.

=cut

sub random {
    my ($self) = @_;
    $self->{random} ||= rand();
}

=head2 info

Return textual information about this mirror

=cut

sub info {
    my ($self) = @_;
    return
      sprintf( '%s (%d/%d)', $self->{url}, $self->level, $self->frequency );
}

=head2 revision

Return the revision of the entry. The revision is an id to identify if an
entry is newer than another for same mirror.

=cut

sub revision {
    my ($self) = @_;
    $self->{revision};
}

=head2 refresh_revision

Reset revision to current timestamp

=cut

sub refresh_revision {
    my ($self) = @_;
    $self->{revision} = _rev();
}

=head2 same_mirror($mirror)

Compare this mirror with another and return 1 if both entries refer to same
mirror

=cut

sub same_mirror {
    my ( $self, $mirror ) = @_;
    if ( $self->host eq $mirror->host && $self->source eq $mirror->source ) {
        return 1;
    }
    return;
}

=head2 sync_mirror($mirror)

Get unknown values from $mirror if defined.

=cut

sub sync_mirror {
    my ( $self, $mirror ) = @_;
    foreach (qw(level frequency)) {
        if (
            ( !defined( $self->{$_} ) )
            || ( defined( $mirror->{$_} )
                && $mirror->revision > $self->revision )
          )
        {
            $self->{$_} = $mirror->{$_};
        }
    }
    if ( $self->{hostinfo} && $mirror->{hostinfo} ) {
        $self->{hostinfo}->sync_host( $mirror->{hostinfo} );
    }
    else {
        $self->{hostinfo} ||= $mirror->{hostinfo};
    }

    if ( $mirror->revision > $self->revision ) {
        $self->{revision} = $mirror->{revision};
    }
}

=head2 xml_output

Return a xml string describing this mirror.

See also <MMM::MirrorList::xml_output>

=cut

sub xml_output {
    my ($self) = @_;
    my $xml = "\t\t<mirror>\n";

    foreach (qw(url level frequency revision)) {
        if ( defined( $self->{$_} ) ) {
            $xml .= sprintf( "\t\t\t<%s>%s</%s>\n", $_, $self->{$_}, $_ );
        }
    }
    foreach (qw(password ssh)) {
        if ( $self->{$_} ) {
            $xml .= sprintf( "\t\t\t<%s>%s</%s>\n", $_, $self->{$_}, $_ );
        }
    }

    $xml .= "\t\t</mirror>\n";

    $xml;
}

1;

=head1 AUTHOR

Olivier Thauvin <nanardon@nanardon.zarb.org>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2006 Olivier Thauvin

This program 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 2
of the License, or (at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

=cut