#! /usr/local/bin/perl -w
#
# $Id: generate-rss.pl,v 1.2 2003/09/14 20:52:05 bc Exp $
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
# 
# The contents of this file are subject to the Mozilla Public License Version 
# 1.1 (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.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
# 
# The Original Code is Netscape code.
#
# The Initial Developer of the Original Code is
# Netscape Corporation.
# Portions created by the Initial Developer are Copyright (C) 2001
# the Initial Developer. All Rights Reserved.
#
# Contributor(s): Bob Clary <bclary@netscape.com>
# Contributor(s): Bob Clary <http://bclary.com>
# 
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
# 
# ***** END LICENSE BLOCK *****
# Create both full and new feeds for RSS and Catalog files as described by
# rssdirectory.xml. New feeds consist of the most recent 5 entries.
#
# Feeds are named rss-full.xml, rss-new.xml and catalog-full.xml, catalog-new.xml
#
# Modified to use CatalogDocument perl object to manage individual
# Catalog entries.
#
# Also changed the Catalog nde:document to nde:article
#
# to invoke
#
# perl -I ~/cvs-devedge/build-web/bin ~/cvs-devedge/build-web/bin/generate-rss '/devedge-srce/' srce
#
# from the ~/cvs-devedge/devedge directory.
#
# generate xml catalogs and rss feeds
#
# 

use strict;

use File::Find ();
use File::Basename;
use XML::LibXML;
use CatalogDocument;
use Time::Local;

my @months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
my @days   = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
my %languages = ();


# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &updateDOMCatalog calls, including -eval statements:
use vars qw/*name *dir *prune/;

*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

my $argsok = 0;
my $argcount = @ARGV;

if ($argcount < 3)
{
  print <<USAGE;
  USAGE: rssgen.pl webroot startdir webmap
USAGE
exit (1);
}

my $webroot = shift;
$::startdir = shift;
my $webmap  = shift;


my $NDEXMLNS = 'http://devedge.netscape.com/2002/de';
my $XMLNS = 'http://www.w3.org/XML/1998/namespace';
my $parser = XML::LibXML->new();
my $catFile = $::startdir . '/catalog.xml';
my $catTime;
my $catDocument;
my $catDocumentElement;

if (-e $catFile)
{
  $catDocument = $parser->parse_file($catFile);
  $catDocumentElement = $catDocument->documentElement;
  $catTime = (stat $catFile)[9];
}
else
{
  $catDocument = XML::LibXML::Document->new( '1.0', 'UTF-8');
  $catDocumentElement = $catDocument->createElementNS($NDEXMLNS, 'nde:catalog');
  $catDocument->setDocumentElement($catDocumentElement);
  $catTime = -1;
}

# Traverse desired filesystems
# and load the catalog with changed articles

File::Find::find({wanted => \&updateDOMCatalog}, $::startdir);

my $rssDirectoryFile = $::startdir . '/rssdirectory.xml';

if (! -e $rssDirectoryFile)
{
  die "$rssDirectoryFile must exist before attempting to generate the RSS";
}

my $rssDirectoryDocument = $parser->parse_file($rssDirectoryFile);
my $rssDirectoryDocumentElement = $rssDirectoryDocument->documentElement;

my @perlCatalog = ();
convertDOMCatalogToPerl($catDocument, \@perlCatalog);
$catDocument = undef;

createFeeds(\@perlCatalog, 'full');
createFeeds(\@perlCatalog, 'new');

# save the new catalog to disk
#$catDocument->toFile($catFile,1);
$catDocument = convertPerlCatalogToDOM(\@perlCatalog);
@perlCatalog = undef;
$catDocument->toFile($catFile,1);


exit;

sub updateDOMCatalog 
{
  #print "updateDOMCatalog: Dir: $dir, File: $_, Pattern: $::fileregx\n";

  return if (!($_ =~ /\.xml$/i));
  return if (($dir =~ /\/CVS$/));

  my $artFile = $_;
  my $artTime = (stat $artFile)[9];

  if ($artTime < $catTime)
  {
    return;
  }

  my $artDocument;

  eval { $artDocument = $parser->parse_file($artFile); };

  if ($@)
  {
    die "Unable to parse $dir/$artFile\:\n$@";
  }

  my $artDocumentElement = $artDocument->documentElement;

  if ($artDocumentElement->nodeName ne 'nde:article')
  {
    return;
  }

  my $artURL = $artDocumentElement->getAttribute('url');
  my $artLang = $artDocumentElement->getAttributeNS($XMLNS, 'lang');

  #XXX HACK FIX THIS
  my $tempURL  = '{' . $artURL . '}';
  my $tempFile = '{' . $dir    . '/' . '}';
  $tempURL =~ s/$webroot//;
  $tempFile =~ s/$::startdir//;
  #print "WARNING: $dir/$artFile contains incorrect URL $tempURL, $tempFile\n" if (! ($tempURL =~ $tempFile) );
  die "WARNING: $dir/$artFile contains incorrect URL" if (! ($tempURL =~ $tempFile) );

  $artLang = 'en' if !$artLang;

  my $catart;
  my @catartlist = $catDocument->findnodes('//nde:article[@url="' . $artURL . '"]');
  foreach $catart (@catartlist)
  {
    if ($catart->getAttribute('lang') eq $artLang)
    {
      $catDocumentElement->removeChild($catart);
    }
  }

  $catart = $catDocument->createElementNS($NDEXMLNS, 'nde:article');
  $catDocumentElement->appendChild($catart);

  # XXX maybe not needed for catalogs? my $mappedURL = $artURL =~ s/$webroot\//$webmap\//;
  $catart->setAttribute( 'url', $artURL );
  $catart->setAttribute( 'lang', $artLang );

  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:channel');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:pubdate');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:moddate');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:title');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:summary');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:authname');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:category');
  importTags(\$artDocumentElement, \$catDocument, \$catart, 'nde:obsolete');
}


sub importTags
{
  my $refArtDocumentElement = $_[0];
  my $refCatDocument = $_[1];
  my $refCatArticle = $_[2];
  my $tagName = $_[3];

  my @artNodeList = $$refArtDocumentElement->getElementsByTagName($tagName)->get_nodelist;

  for (my $artIndex = 0; $artIndex < @artNodeList; ++$artIndex)
  {
    my $artNode = $artNodeList[$artIndex];

    normalizeNode(\$artNode);

    my $catNode = $$refCatDocument->importNode( $artNode );

    # hack change in id->channelid
    if ($catNode->nodeName eq "nde:channel")
    {
      my $channelid = $catNode->getAttribute('id');
      $catNode->setAttribute('channelid', $channelid);
      $catNode->removeAttribute('id');
    }
    $$refCatArticle->appendChild($catNode);
  }
}

sub normalizeNode
{
  my $refNode = $_[0];

  while ($$refNode->firstChild)
  {
    my $child = $$refNode->firstChild;
    my $type = $child->nodeType;
    if ($type == 8)
    {
      $$refNode->removeChild($child);

    }
    elsif ($type == 3)
    {
      my $data = $child->data;

      if ($data =~ /^[\s\n]+$/)
      {
        $$refNode->removeChild($child);
      }
      else
      {
        $data =~ s/^[\s\n]+//;
        $child->setData($data);
        last;
      }
    }
    else
    {
      last;
    }
  }

  while ($$refNode->lastChild)
  {
    my $child = $$refNode->lastChild;
    my $type = $child->nodeType;
    if ($type == 8)
    {
      $$refNode->removeChild($child);

    }
    elsif ($type == 3)
    {
      my $data = $child->data;

      if ($data =~ /^[\s\n]+$/)
      {
        $$refNode->removeChild($child);
      }
      else
      {
        $data =~ s/[\s\n]+$//;
        $child->setData($data);
        last;
      }
    }
    else
    {
      last;
    }
  }
}

sub createFeeds
{
  my $refPerlCatalog = $_[0];
  my $feedtype = $_[1];
  my $maxcount;

  die "invalid feedtype $feedtype in createFeeds" if $feedtype ne 'full' and $feedtype ne 'new';

  if ($feedtype eq 'new')
  {
    $maxcount = 15;
  }

  my @languages   = keys %languages;
  my @channelList = $rssDirectoryDocumentElement->getElementsByTagName('nde:rsschannel')->get_nodelist;

  foreach my $channel (@channelList)
  {
    my $channelLoc = $channel->getAttribute('loc');
    my $channelId = $channel->getAttribute('channelid');
    my $filteryear = $channel->getAttribute('year');

    if (!$filteryear)
    {
      $filteryear = '*';
    }

    foreach my $language (@languages)
    {
      my @perlArticleList = filterPerlCatalog($refPerlCatalog, $channelId, $filteryear, $language, $maxcount);
      if (@perlArticleList == 0)
      {
        next;
      }

      my @nodes;
      my $channelDirectory = $channelLoc;

      $channelDirectory =~ s/^$webroot//;
      $channelDirectory = $::startdir . '/' . $channelDirectory;

      my $rssDocument = XML::LibXML::Document->new( '1.0', 'UTF-8' );
      my $rssDocumentElement = $rssDocument->createElement('rss');
      $rssDocument->setDocumentElement($rssDocumentElement);
      $rssDocumentElement->setAttribute('version', '2.0');

      my $rssChannel = $rssDocument->createElement('channel');
      $rssDocumentElement->appendChild($rssChannel);

      @nodes = $channel->getElementsByTagName('nde:rsschanneltitle')->get_nodelist;
      die if @nodes != 1;

      my $rssChannelTitle = $rssDocument->createElement('title');
      $rssChannel->appendChild($rssChannelTitle);
      $rssChannelTitle->appendChild($rssDocument->createTextNode($nodes[0]->firstChild->data));

      # force absolute paths
      my $linkDir = $channelLoc;
      $linkDir =~ s/$webroot\//$webmap\//;

      my $rssChannelLink = $rssDocument->createElement('link');
      $rssChannel->appendChild($rssChannelLink);
      $rssChannelLink->appendChild($rssDocument->createTextNode($linkDir));

      my $rssChannelLanguage = $rssDocument->createElement('language');
      $rssChannel->appendChild($rssChannelLanguage);
      $rssChannelLanguage->appendChild($rssDocument->createTextNode($language));

      @nodes = $channel->getElementsByTagName('nde:rsschanneldesc')->get_nodelist;
      die if @nodes != 1;

      my $rssChannelDescription = $rssDocument->createElement('description');
      $rssChannel->appendChild($rssChannelDescription);
      $rssChannelDescription->appendChild($rssDocument->createTextNode($nodes[0]->firstChild->data));

      my $rssChannelBuildDate = $rssDocument->createElement('lastBuildDate');
      $rssChannel->appendChild($rssChannelBuildDate);
      $rssChannelBuildDate->appendChild( $rssDocument->createTextNode(getGMT()) );

      my $rssChannelCopyright = $rssDocument->createElement('copyright');
      $rssChannel->appendChild($rssChannelCopyright);
      $rssChannelCopyright->appendChild( $rssDocument->createTextNode('2000-' . ((localtime(time))[5] + 1900) . ' Netscape Communications') );

      my $catNode;
      my $text;
      my $lastCatNodeUrl = '';
      my $catNodeUrl = '';
      my $feedYear = '';
      my $feedMonth = '';
      my $feedDay = '';

      foreach my $perlArticle (@perlArticleList)
      {
        $catNodeUrl = $perlArticle->{'url'};

        if ($lastCatNodeUrl eq $catNodeUrl)
        {
          next;
        }
        $lastCatNodeUrl = $catNodeUrl;

        my $rssItem = $rssDocument->createElement('item');
        $rssChannel->appendChild( $rssItem );

        my $rssTitle = $rssDocument->createElement('title');
        $rssTitle->appendChild( $rssDocument->createTextNode($perlArticle->{title}) );
        $rssItem->appendChild($rssTitle);

        # force absolute paths
        $linkDir = $perlArticle->{url};
        $linkDir =~ s/$webroot\//$webmap\//;

        my $rssLink = $rssDocument->createElement('link');
        $rssLink->appendChild( $rssDocument->createTextNode($linkDir) );
        $rssItem->appendChild($rssLink);

        my $rssGuid = $rssDocument->createElement('guid');
        $rssGuid->appendChild( $rssDocument->createTextNode($linkDir) );
        $rssItem->appendChild($rssGuid);

        my $author  = '';
        my $authname  = '';
        foreach $authname (@{$perlArticle->{authnames}})
        {
          $author .= $authname . ', ';
        }

        if ($author)
        {
          $author =~ s/, $//;
          my $rssAuthor = $rssDocument->createElement('author');
          $rssAuthor->appendChild( $rssDocument->createTextNode($author) );
          $rssItem->appendChild($rssAuthor);
        }

        my $category    = $perlArticle->{category};
        my $rssCategory = $rssDocument->createElement('category');
        $rssCategory->appendChild( $rssDocument->createTextNode($category) );
        $rssItem->appendChild($rssCategory);

        my $year;
        my $month;
        my $day;
        if ($perlArticle->{moddate}->{year})
        {
          $year  = $perlArticle->{moddate}->{year};
          $month = $perlArticle->{moddate}->{month};
          $day = $perlArticle->{moddate}->{day};
        }
        elsif ($perlArticle->{pubdate}->{year})
        {
          $year  = $perlArticle->{pubdate}->{year};
          $month = $perlArticle->{pubdate}->{month};
          $day = $perlArticle->{pubdate}->{day};
        }
        if ($year && $month && $day)
        {
          $text = $day . ' ' . $months[$month-1] . ' ' . $year . ' 00:00:00 GMT';
          my $rssPubDate = $rssDocument->createElement('pubDate');
          $rssPubDate->appendChild( $rssDocument->createTextNode($text) );
          $rssItem->appendChild($rssPubDate);

          if ("$year.$month.$day" gt "$feedYear.$feedMonth.$feedDay")
          {
            $feedYear = $year;
            $feedMonth = $month;
            $feedDay = $day;
          }
        }
        
        if ($perlArticle->{summary})
        {
          my $rssDescription = $rssDocument->createElement('description');
          $rssDescription->appendChild( $rssDocument->createTextNode($perlArticle->{summary}) );
          $rssItem->appendChild($rssDescription);
        }

      }

      $language =~ s/-/_/g;
      my $rssFile = "$channelDirectory/rss-$feedtype" . "_" . "$language.xml";

      $rssDocument->toFile($rssFile, 1);

      my $domFeedFile = "$channelDirectory/catalog-$feedtype" . "_" . "$language.xml";
      my $domFeedCatalog = convertPerlCatalogToDOM(\@perlArticleList);

      $domFeedCatalog->toFile($domFeedFile, 1);

      if ($feedYear && $feedMonth && $feedDay)
      {
        my $feedDate = timelocal(0, 0, 0, $feedDay, $feedMonth-1, $feedYear-1900);
        utime $feedDate, $feedDate, $rssFile;
        #utime $feedDate, $feedDate, $domFeedFile;
        # print "$rssFile $domFeedFile: FeedDate $feedDate\n"
      }
    }
  }

}

sub getGMT
{
  my $timeval = shift;

  if (!$timeval)
  {
    $timeval = time;
  }
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($timeval);

  $year += 1900;

  $mday = '0' . $mday if length($mday) < 2;
  $hour = '0' . $hour if length($hour) < 2;
  $min  = '0' . $min if length($min) < 2;
  $sec  = '0' . $sec if length($sec) < 2;

  $mday =~ s/ /0/g;
  $hour =~ s/ /0/g;
  $min =~ s/ /0/g;
  $sec =~ s/ /0/g;

  my $gmt = "$days[$wday], $mday $months[$mon] $year $hour:$min:$sec GMT";

  $gmt;
}

sub convertDOMCatalogToPerl
{
  my $domCatDocument = $_[0];
  my $refPerlCatalog = $_[1];

  my @domCatalogArticleList = $domCatDocument->documentElement->findnodes('nde:article');
  my @nodes;
  my $node;
  my $perlCatalogArticle;
  my $lang;
  my $year;
  my $month;
  my $day;

  foreach my $domCatalogArticle (@domCatalogArticleList)
  {
    my $perlCatalogArticle = CatalogDocument->new();
    push @{$refPerlCatalog}, $perlCatalogArticle;

    $lang = $domCatalogArticle->getAttribute('lang');

    if (!$lang)
    {
      $lang = 'en';
    }

    $languages{$lang} = 1;

    $perlCatalogArticle->{url} = $domCatalogArticle->getAttribute('url');
    $perlCatalogArticle->{lang} = $lang;

    @nodes = $domCatalogArticle->findnodes('nde:title');
    if (@nodes > 0)
    {
      $perlCatalogArticle->{title} = $nodes[0]->firstChild->data;
    }

    @nodes = $domCatalogArticle->findnodes('nde:obsolete');
    if (@nodes > 0)
    {
      my $val;

      %{$perlCatalogArticle->{obsolete}} = ();
      $val = $nodes[0]->getAttribute('url');
      if ($val)
      {
        $perlCatalogArticle->{obsolete}->{url} = $val;
      }

      $val = $nodes[0]->getAttribute('title');
      if ($val)
      {
        $perlCatalogArticle->{obsolete}->{title} = $val;
      }
      if ($nodes[0]->firstChild)
      {
        $val = $nodes[0]->firstChild->data;
        $perlCatalogArticle->{obsolete}->{message} = $val;
      }
    }

    @nodes = $domCatalogArticle->findnodes('nde:category');
    if (@nodes > 0)
    {
      if ($nodes[0]->firstChild && $nodes[0]->firstChild->data)
      {
        $perlCatalogArticle->{category} = $nodes[0]->firstChild->data;
      }
    }

    @nodes = $domCatalogArticle->findnodes('nde:summary');
    if (@nodes > 0)
    {
      my $summary = $nodes[0]->toString();
      $summary =~ s/<[\/]?nde:summary[^>]*>//g;
      $perlCatalogArticle->{summary} = $summary;
    }

    @nodes = $domCatalogArticle->findnodes('nde:pubdate');
    if (@nodes > 0)
    {
      $year = $nodes[0]->getAttribute('year') || '1900';
      $month = $nodes[0]->getAttribute('month') || '01';
      $day = $nodes[0]->getAttribute('day') || '01';

      $perlCatalogArticle->{pubdate}->{year} = $year;
      $perlCatalogArticle->{pubdate}->{month} = $month;
      $perlCatalogArticle->{pubdate}->{day} = $day;
    }

    @nodes = $domCatalogArticle->findnodes('nde:moddate');
    if (@nodes > 0)
    {
      $year = $nodes[0]->getAttribute('year') || '1900';
      $month = $nodes[0]->getAttribute('month') || '01';
      $day = $nodes[0]->getAttribute('day') || '01';

      $perlCatalogArticle->{moddate}->{year} = $year;
      $perlCatalogArticle->{moddate}->{month} = $month;
      $perlCatalogArticle->{moddate}->{day} = $day;
    }

    @nodes = $domCatalogArticle->findnodes('nde:channel');
    foreach $node (@nodes)
    {
      $perlCatalogArticle->addChannel($node->getAttribute('channelid'));
    }

    @nodes = $domCatalogArticle->findnodes('nde:authname');
    foreach $node (@nodes)
    {
      $perlCatalogArticle->addAuthor($node->firstChild->data);
    }

  }

  # sort by descending pubdate
  @{$refPerlCatalog} = sort 
  {
    my $lyear;
    my $lmonth;
    my $lday;
    my $ryear;
    my $rmonth;
    my $rday;

    if ($a->{pubdate}->{year})
    {
      ($lyear, $lmonth, $lday) = 
         ($a->{pubdate}->{year}, $a->{pubdate}->{month}, $a->{pubdate}->{day});
    }
    else
    {
      ($lyear, $lmonth, $lday) = 
         ($a->{moddate}->{year}, $a->{moddate}->{month}, $a->{moddate}->{day});
    }

    if ($b->{pubdate}->{year})
    {
      ($ryear, $rmonth, $rday) = 
         ($b->{pubdate}->{year}, $b->{pubdate}->{month}, $b->{pubdate}->{day});
    }
    else
    {
      ($ryear, $rmonth, $rday) = 
         ($b->{moddate}->{year}, $b->{moddate}->{month}, $b->{moddate}->{day});
    }

    $lyear = '1900' if !$lyear;
    $ryear = '1900' if !$ryear;

    $lmonth = '01' if !$lmonth;
    $rmonth = '01' if !$rmonth;

    $lday = '01' if !$lday;
    $rday = '01' if !$rday;

    $ryear cmp $lyear
      or
    $rmonth cmp $lmonth
      or
    $rday cmp $lday
  } 
  @{$refPerlCatalog};
}

sub convertPerlCatalogToDOM
{
  my $refPerlCatalog = $_[0];

  my $textnode;
  my $domCatalogDocument = XML::LibXML::Document->new( '1.0', 'UTF-8');
  my $domCatalogDocumentElement = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:catalog');
  $domCatalogDocument->setDocumentElement($domCatalogDocumentElement);

  foreach my $perlCatalogArticle (@{$refPerlCatalog})
  {
    my $domCatalogArticle = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:article');
    $domCatalogArticle->setAttribute('url', $perlCatalogArticle->{url});
    $domCatalogArticle->setAttribute('lang', $perlCatalogArticle->{lang});
    $domCatalogDocumentElement->appendChild($domCatalogArticle);

    my $domCatalogTitle = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:title');
    $domCatalogArticle->appendChild($domCatalogTitle);
    $textnode = $domCatalogDocument->createTextNode($perlCatalogArticle->{title});
    $domCatalogTitle->appendChild($textnode);

    if ($perlCatalogArticle->{obsolete})
    {
      my $domCatalogObsolete = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:obsolete');
      $domCatalogArticle->appendChild($domCatalogObsolete);
      if ($perlCatalogArticle->{obsolete}->{url})
      {
        $domCatalogObsolete->setAttribute('url', $perlCatalogArticle->{obsolete}->{url});
      }
      if ($perlCatalogArticle->{obsolete}->{title})
      {
        $domCatalogObsolete->setAttribute('title', $perlCatalogArticle->{obsolete}->{title});
      }
      if ($perlCatalogArticle->{obsolete}->{message})
      {
        $textnode = $domCatalogDocument->createTextNode($perlCatalogArticle->{obsolete}->{message});
        $domCatalogObsolete->appendChild($textnode);
      }

    }

    $textnode = '<nde:summary xmlns:nde="' . $NDEXMLNS . '">' . $perlCatalogArticle->{summary} . '</nde:summary>';

    my $domTempSummaryDocument = $parser->parse_string($textnode);
    my $domCatalogSummary = $domCatalogDocument->importNode($domTempSummaryDocument->documentElement);
    $domCatalogArticle->appendChild($domCatalogSummary);

    my $domCatalogCategory = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:category');
    $domCatalogArticle->appendChild($domCatalogCategory);
    $textnode = $domCatalogDocument->createTextNode($perlCatalogArticle->{category});
    $domCatalogCategory->appendChild($textnode);

    my $domCatalogPubDate = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:pubdate');
    $domCatalogArticle->appendChild($domCatalogPubDate);
    $domCatalogPubDate->setAttribute('year', $perlCatalogArticle->{pubdate}->{year});
    $domCatalogPubDate->setAttribute('month', $perlCatalogArticle->{pubdate}->{month});
    $domCatalogPubDate->setAttribute('day', $perlCatalogArticle->{pubdate}->{day});

    if ($perlCatalogArticle->{moddate}->{year})
    {
      my $domCatalogModDate = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:moddate');
      $domCatalogArticle->appendChild($domCatalogModDate);
      $domCatalogModDate->setAttribute('year', $perlCatalogArticle->{moddate}->{year});
      $domCatalogModDate->setAttribute('month', $perlCatalogArticle->{moddate}->{month});
      $domCatalogModDate->setAttribute('day', $perlCatalogArticle->{moddate}->{day});
    }

    foreach my $perlChannel (sort @{$perlCatalogArticle->{channels}})
    {
      my $domCatalogChannel = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:channel');
      $domCatalogChannel->setAttribute('channelid', $perlChannel);
      $domCatalogArticle->appendChild($domCatalogChannel);
    }

    foreach my $perlAuthName (@{$perlCatalogArticle->{authnames}})
    {
      my $domCatalogAuthName = $domCatalogDocument->createElementNS($NDEXMLNS, 'nde:authname');
      $domCatalogArticle->appendChild($domCatalogAuthName);
      $textnode = $domCatalogDocument->createTextNode($perlAuthName);
      $domCatalogAuthName->appendChild($textnode);
    }
  }

  return $domCatalogDocument;
}


sub filterPerlCatalog
{
  # return a list containing $count articles
  # which match he channelid. Since the PerlCatalog
  # is sorted by descending date, this will retrieve
  # the results in reverse date order as well.
  my $refPerlCatalog = $_[0];
  my $channelid = $_[1];
  my $filteryear = $_[2];
  my $language = $_[3];
  my $maxcount = $_[4];
  my @results = ();

  foreach my $perlCatalogArticle (@{$refPerlCatalog})
  {

    if ($maxcount && @results >= $maxcount)
    {
      last;
    }

    if ($filteryear ne '*' && 
        $perlCatalogArticle->{pubdate}->{year} &&
        $perlCatalogArticle->{pubdate}->{year} ne $filteryear)
    {
      next;
    }

    if ($perlCatalogArticle->{obsolete})
    {
      next;
    }

    if (!($perlCatalogArticle->getChannelIds() =~ /$channelid/))
    {
      next;
    }

    if (!($perlCatalogArticle->{lang} =~ /$language/))
    {
      next;
    }

    push @results, $perlCatalogArticle;

  }

  return @results;
}

