
#define DEBUG
// #define DEBUGX

#import "RSSFeed.h"

// Snownews header files

// FIXME: It's very bad to take the time from the 'time_t time()'!
#define UNIXOID

#ifndef MACOSX
#import "snownews_config.h"
#import "xmlparse.h"
#endif

#ifdef UNIXOID
#include <time.h>
#endif


@implementation RSSFeed

-init
{
  return [self initWithFetcher: nil];
}

-initWithFetcher: (id) aFetcher
{
  // please don't initialize without fetcher
  if (aFetcher != nil)
    {
      fetcher = RETAIN(aFetcher);
    }
  
  articles = [[NSMutableArray alloc] init];
  dirty = YES;
  lastError = RSSFeedErrorNoError;
  feedName = nil;
  
  return self;
}


-(NSString*) description
{
  return [NSString stringWithFormat: @"\"%@\" (rc=%d)",
		   feedName, [self retainCount]];
}


-(id)initWithCoder: (NSCoder*)coder
{
  int i;
#ifdef DEBUG
  NSLog(@"started decoding RSSFeed");
#endif
  
  if (self = [self init])
    {
      RELEASE(articles);
      RELEASE(feedName);
      
      dirty = NO;
      articles = RETAIN([coder decodeObject]);
      [coder decodeValueOfObjCType:@encode(int) at:&lastError];
      feedName = RETAIN([coder decodeObject]);
      fetcher = RETAIN([coder decodeObject]);
    }
  
#ifdef DEBUG
  NSLog(@"finished decoding RSSFeed (rc=%i)", [self retainCount]);
#endif
  
  return self;
}

-(void)encodeWithCoder: (NSCoder*)coder
{
#ifdef DEBUG
  NSLog(@"started encoding RSSFeed");
#endif
  
  [coder encodeObject: articles];
  [coder encodeValueOfObjCType: @encode(int) at:&lastError];
  [coder encodeObject: feedName];
  [coder encodeObject: fetcher];
  
#ifdef DEBUG
  NSLog(@"finished encoding RSSFeed");
#endif
}


// get the document from the http server


-(void) setDirty
{
  dirty = YES;
}


-(enum RSSFeedError) fetch
{
  // FIXME: get this to work on MacOSX!
#ifndef MACOSX
  struct newsitem * item;
  struct feed * newsfeed;
  char * buf = NULL;
  
  
  if (fetcher == nil)
    {
      NSLog(@"Sorry dude, %@ doesn't know how to fetch its feeds...",
	    [self description]);
      return RSSFeedErrorNoFetcherError;
    }
#ifdef DEBUG
  else
    {
      NSLog(@"Fetching using %@", [fetcher description]);
    }
#endif
  
  dirty = NO; //ok :-P
  
  
  // FIXME: Fix that, the surprise requests it.
  // Delete and recreate the list of articles.
  RELEASE(articles);
  articles = [[NSMutableArray alloc] init];
  
  
  // FIXME: fetchers must adopt protocols soon!
  buf = [(id)([fetcher fetch]) cString];
  
  
  if (buf == NULL)
    return [self setError: RSSFeedErrorDocumentNotPresent];
  
  //printf("buf = \n%s\n", buf);
  
  newsfeed = new_feed(buf); // FIXME: replace new_feed() soon?
  
  if (newsfeed == NULL)
    {
      free(buf);
      return [self setError: RSSFeedErrorMalformedRSS];
    }
  
  if (DeXML(newsfeed))
    {
      free(buf);
      free(newsfeed); // hope that works here and leaves no memory leaks...
      return [self setError: RSSFeedErrorMalformedRSS];
    }
  
  // replace feed name
  RELEASE(feedName);
  feedName = [[NSString alloc] initWithCString: newsfeed->title];
  
  item = newsfeed->items;
  while (item)
    {
      RSSArticle* article;
      NSString* headline;
      NSString* url;
      NSString* description;
      unsigned int myTime;
      
      if (item->title)
	headline = [[NSString alloc] initWithCString: item->title];
      else
	headline = @"no headline available";
      
      if (item->link)
	url = [[NSString alloc] initWithCString: item->link];
      else
	url = @"no link available";
      
      if (item->description)
	description =
	  [[NSString alloc] initWithCString: item->description];
      else
	description = @"no description available";
      
      // FIXME: Better fetch the time from a NeXTStep class!
#ifdef UNIXOID
      myTime = time(NULL);
#else
      myTime = 1096509297; // time of this writing: REPLACE THIS! FIXME
#endif
      
      article = [[RSSArticle alloc]
		  initWithHeadline: headline
		  url: url
		  description: description
		  time: myTime];
      
      printf(" + adding %s\n", item->title);
      RELEASE(headline);
      RELEASE(url);
      RELEASE(description);
      
      [articles addObject: article];
      
      item = item->next_ptr;
    }
  
  free(buf);
  free(newsfeed);
  
#endif // MACOSX
  
  return [self setError: RSSFeedErrorNoError]; // FIXME
}

-(enum RSSFeedError) setError: (enum RSSFeedError) err
{
  lastError = err;
  return err;
}

// access to the articles

- (RSSArticle*) articleAtIndex: (int) index
{
  RSSArticle* a;
  
  if (index >= [articles count])
    return nil;
  
  a = [articles objectAtIndex: index];
  
  return a;
}

- (NSString*) headlineAtIndex: (int) index
{
  id a;
  
#ifdef DEBUGX
  printf ("headlineAtIndex: %u\n  dirty = %s\n  count = %u\n", index,
	  (dirty?"YES":"NO"), [articles count]);
#endif
  
  if (dirty)
    [self fetch];
  
  if (index >= [articles count])
    return @"ERROR: index out of bounds in RSSFeed.m";
  
  a = [articles objectAtIndex: index];
  
  return [a headline];
}

- (NSString*) urlAtIndex: (int) index
{
  if (dirty)
    [self fetch];
  
  if (index >= [articles count])
    return @"ERROR: index out of bounds in RSSFeed.m";
  
  return [[articles objectAtIndex: index] url];
}

- (NSString*) descriptionAtIndex: (int) index
{
  if (dirty)
    [self fetch];
  
  if (index >= [articles count])
    return @"ERROR: index out of bounds in RSSFeed.m";
  
  return [[articles objectAtIndex: index] description];
}

- (unsigned int) timeAtIndex: (int) index
{
  if (dirty)
    [self fetch];
  
  if (index >= [articles count])
    return 0;
  
  return [[articles objectAtIndex: index] time];
}

- (unsigned int) count
{
  return [articles count];
}

// preferences
- (NSString*) feedName
{
  if (feedName == nil || dirty == YES)
    [self fetch];
  
  return feedName;
}

@end

