############################################################################
##      Copyright (C) 2005 Subredu Manuel  <diablo@iasi.roedu.net>.        #
##                                                                         #
## This program is free software; you can redistribute it and/or modify    #
## it under the terms of the GNU General Public License v2 as published by #
## the Free Software Foundation.                                           #
##                                                                         #
## 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., 59 Temple Place - Suite 330, Boston,                  #
## MA 02111-1307,USA.                                                      #
############################################################################

package RoPkg::Simba::Plugin::GenRSS;

use strict;
use warnings;

use RoPkg::Exceptions;
use RoPkg::Utils qw(GetHumanDate SecToTime);
use RoPkg::Rsync::LogParser;

use XML::RSS;
use Scalar::Util   qw(blessed);
use Number::Format qw(:subs :vars);

use vars qw($VERSION);

$VERSION='0.2.1';

my $defaults_values = {
  max_items       => '10',
  updatePeriod    => 'hourly',
  updateFrequency => '1',
  language        => 'en_US',
  creator         => 'Simba ' . $RoPkg::Simba::VERSION,
  title           => 'Mirror updates',
  description     => 'Mirror updates',
  rights          => 'Our organization',
  publisher       => 'Our organization',
  timezone        => 'Europe/Bucharest',
  gmt_offset      => '+03:00',
};

sub new {
  my ($class, %opt) = @_;
  my $self;

  $self = bless { %opt }, $class;

  #create a log parser object. will use that later
  $self->{lp} = new RoPkg::Rsync::LogParser(type => 'client');

  return $self;
}


# Load the values from the configuration file
sub _load_config {
  my ($self, $cfg) = @_;

  if ( !defined($cfg->{file}) ) {
    Param::Missing->throw('no file parameter found in rss section of the config file');
  }

  #read the values from the configuration file (if they exists)
  foreach(qw(title description creator
             publisher rights language
             max_items site_url item_url
             item_msg file updatePeriod
             updateFrequency timezone
             gmt_offset)) {
    if ( $cfg->{$_} ) {
      $self->{$_} = $cfg->{$_};
    }
  }

  #init the parameters not specified by the user
  foreach(keys(%{ $defaults_values })) {
    if ( !$self->{$_} ) {
      $self->{$_} = $defaults_values->{$_};
    }
  }

  return 1;
}

# Add a new channel to the rss
sub _add_channel
{
  my ($self, $rss) = @_;

  $rss->channel( 
          title       => $self->{'title'},
          link        => $self->{'site_url'},
          description => $self->{'description'},

          dc => {
              date      => (DateTime->now(time_zone => $self->{timezone}) . $self->{gmt_offset}),
              subject   => $self->{'subject'},
              creator   => $self->{'creator'},
              publisher => $self->{'publisher'},
              rights    => $self->{'rights'},
              language  => $self->{'language'}
          },

          syn => {
              updatePeriod    => $self->{updatePeriod},
              updateFrequency => $self->{updateFrequency},
              updateBase      => (DateTime->new(year => '1970') . '+03:00')
          }
      );

  return $rss;
}

# Substitutes the tags from the message with the values from the mirror
sub _build_message 
{
  my ($self, $message, $mirror) = @_;
  my $res;
  my %items;

  #Initialize the mirror values
  $KILO_SUFFIX = ' K';
  $MEGA_SUFFIX = ' M';
  $GIGA_SUFFIX = ' G';

  $items{'__last_update__'}          = GetHumanDate($mirror->LastUpdated);
  $items{'__name__'}                 = $mirror->Name;
  $items{'__id__'}                   = $mirror->id;
  $items{'__last_update_speed__'}    = Number::Format::format_bytes($mirror->LastUpdateSpeed, 3);
  $items{'__last_update_duration__'} = SecToTime($mirror->LastUpdateDuration);
  $items{'__files_no__'}             = scalar $self->{lp}->Files;
  $items{'__real_files_no__'}        = scalar $self->{lp}->RealFiles;

  #replace all tags with values
  foreach(keys(%items)) {
    $message =~ s{$_}{$items{$_}}xmg;
  }

  return $message;
}

#Add a new item (a mirror) to the rss
sub _add_mirror
{
  my ($self, $rss, $mirror) = @_;

  $rss->add_item(
         title       => $mirror->Name . ' updated',
         link        => $self->_build_message($self->{'item_url'}, $mirror),
         description => $self->_build_message($self->{'item_msg'}, $mirror),
         dc => {
             date => (
                       DateTime->from_epoch (
                         epoch => $mirror->LastUpdated,
                         time_zone => $self->{timezone}
                       ) . $self->{gmt_offset}
                     ),
             rights => $self->{rights},
             language => $self->{language},
         }
     );

  return $rss;
}

#Filters the list of mirrors, and add the first ones to the rss
sub _add_mirrors {
  my ($self, $rss, $cfg, $m_list) = @_;
  my $i;

  my @mirrors = @{ $m_list };

  #sort mirrors by LastUpdate field
  @mirrors = sort { $b->LastUpdated <=> $a->LastUpdated } @mirrors;

  #initialize counter
  $i=1;

  #give the probes list to the rsync log parser
  $self->{lp}->Probes(@{ $cfg->{mProbes}});

  foreach(@mirrors) {
    my $mirror = $_;

    #ignore the Inactive, Inprogress or mirrors who don't have any output
    next if ( ! $mirror->Active or $mirror->InProgress or !$mirror->StdOut);

    #parse the rsync log
    $self->{lp}->Log($mirror->StdOut);
    $self->{lp}->Parse();

    #ignore the mirror if nothing was transfered
    next if ( (scalar $self->{lp}->Files) == 0 );

    #add the mirror to the rss
    $self->_add_mirror($rss, $mirror);
    $i++;

    #stop if we have enough mirrors
    last if ( $i > $self->{'max_items'} );
  }

  return $rss;
}

sub _enabled {
  my ($self, $cfg) = @_;

  #if enabled found
  if ( $cfg->{enabled} ) {

    #return 1 if the value is yes (case insensitive)
    return 1 if ( $cfg->{enabled} =~ m{^yes$}xmi );

    #else, return 0
    return 0;
  }

  #if no enabled was found, assume yes
  return 1;
}

#The public method called by Simba.
sub genFeed {
  my ($self, $cfg, $mirrors) = @_;
  my ($rss, $i);

  if ( !blessed($self) ) {
    OutsideClass->throw('Called outside class instance');
  }

  #do nothing if no configuration items are found
  return 0 if ( !$cfg->{plugins}->{rss} );

  #do nothing if plugin is disabled
  return 0 if ( !$self->_enabled($cfg->{plugins}->{rss}) );

  #nothing to do if no mirrors are given
  return 0 if ((scalar @{ $mirrors }) <= 0 );

  #load configuration
  $self->_load_config($cfg->{plugins}->{rss});

  #initialize the rss object
  $rss = new XML::RSS(version => '1.0');
  $rss->add_module(prefix => 'html', uri => 'http://www.w3.org/1999/xhtml');
  $self->_add_channel($rss);

  #add the mirrors
  $self->_add_mirrors($rss, $cfg, $mirrors);

  #save the rss to a file
  $rss->save($self->{file});

  return 1;
}

1;

__END__

=head1 NAME

RoPkg::Simba::Plugin::GenRSS

=head1 DESCRIPTION

GenRSS is a rss feed generator plugin for Simba. GenRSS allows you
to create custom rss feeds from the mirror updates information.

=head1 PREREQUISITES

GenRSS needs the following perl modules:

=over 4

=item *) XML::RSS

=item *) Scalar::Util

=item *) Number::Format

=item *) DateTime

=back

=head1 METHODS

=head2 genFeed($cfg, @mirrors)

Generate rss feeds. The $cfg is a hash reference to the
simba configuration file.

=head1 CONFIGURATION

All configuration documentation is available on the website
(http://simba.packages.ro).

=head1 SEE ALSO

L<RoPkg::Simba> L<RoPkg::Exceptions>

=head1 AUTHOR

Subredu Manuel <diablo@iasi.roedu.net>

=head1 LICENSE

Copyright (C) 2005 Subredu Manuel.  All Rights Reserved.
This module is free software; you can redistribute it 
and/or modify it under the same terms as Perl itself.
The LICENSE file contains the full text of the license.

=cut
