#import "RSS2Parser.h"
#import "RXMLElement.h"


static NSString * NoNilString(NSString * input) {
	if (input) return input;
	return @"";
}

@implementation NSString (TrimmingConvenience)

- (NSString *)trimmedString {
	
	return [self stringByTrimmingCharactersInSet:
			[NSCharacterSet whitespaceAndNewlineCharacterSet]];
	
}

@end

@implementation NSArray (Map)

- (NSArray *)mapObjectsUsingBlock:(id (^)(id obj, NSUInteger idx))block {
    NSMutableArray *result = [NSMutableArray arrayWithCapacity:[self count]];
    [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        [result addObject:block(obj, idx)];
    }];
    return result;
}

@end


@implementation RSS2Parser {
	RSS2Channel * _channel;
	NSDictionary * _feedDictionary;
}

- (BOOL)parse {

	RXMLElement * rssNode = [RXMLElement elementFromXMLData:self.inputData];
	if (![rssNode isValid]) return NO;
	
	RXMLElement * channelNode = [rssNode child:@"channel"];
	
	_channel = RSS2Channel.new;
	_channel.title = [channelNode child:@"title"].text.trimmedString;
	_channel.link = [NSURL URLWithString:[channelNode child:@"link"].text.trimmedString];
	_channel.channelDescription = [channelNode child:@"description"].text.trimmedString;
	_channel.language = [channelNode child:@"language"].text.trimmedString;
	_channel.copyright = [channelNode child:@"copyright"].text.trimmedString;
	_channel.pubDate = [self parsePubDate:[channelNode child:@"pubDate"].text.trimmedString];
	_channel.image = [self parseImageInNode:channelNode];
	
	NSMutableArray * links = @[].mutableCopy;
	[[channelNode children:@"link"] enumerateObjectsUsingBlock:^(RXMLElement * linkNode, NSUInteger idx, BOOL *stop) {
		[links addObject:@{
							  @"rel":	NoNilString([linkNode attribute:@"rel"]),
							  @"href":	NoNilString([linkNode attribute:@"href"]),
							  }];
	}];
	
	_channel.links = links;

	NSMutableArray * items = [NSMutableArray array];
	
	[channelNode iterate:@"item" usingBlock:^(RXMLElement * itemNode) {
		[items addObject:[self parseItemFromNode:itemNode]];
	}];

	_channel.items = items;

	return YES;
}

- (RSS2ChannelImage *)parseImageInNode:(RXMLElement *)node {
	
	if (![node child:@"image"].isValid) return nil;
	
	RSS2ChannelImage * image = RSS2ChannelImage.new;
	
	image.url = [NSURL URLWithString:[node child:@"url"].text.trimmedString];
	image.title = [node child:@"title"].text.trimmedString;
	image.link = [NSURL URLWithString:[node child:@"link"].text.trimmedString];
	
	return image;
}

- (NSDate *)parsePubDate:(NSString *)pubDate {
	
	NSDateFormatter * df = [[NSDateFormatter alloc] init];
	[df setLocale: [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"] ];
	[df setDateFormat:@"EEE, dd MMMM yyyy HH:mm:ss Z"];
	NSDate * date = [df dateFromString:pubDate];
	if(!date) {
		// check for other date patterns
	}
	return date;
}

- (RSS2Item *)parseItemFromNode:(RXMLElement *)itemNode {

	RSS2Item * item = RSS2Item.new;
	
	item.title = [itemNode child:@"title"].text.trimmedString;
	item.itemDescription = [itemNode child:@"description"].text.trimmedString;
	item.link = [NSURL URLWithString:[itemNode child:@"link"].text.trimmedString];
	item.author = [itemNode child:@"author"].text.trimmedString;
	item.guid = [itemNode child:@"guid"].text.trimmedString;
	item.pubDate = [self parsePubDate:[itemNode child:@"pubDate"].text.trimmedString];
	NSArray * contentElements = [itemNode children:@"encoded"];
	if (contentElements.count) {
		RXMLElement * contentElement = [contentElements objectAtIndex:0];
		if (contentElement) item.content = contentElement.text.trimmedString;
	}
	NSArray * thumbnailElements = [itemNode children:@"thumbnail"];
	if (thumbnailElements.count) {
		RXMLElement * thumbnailElement = [thumbnailElements objectAtIndex:0];
		item.media_thumbnail = [thumbnailElement attribute:@"url"];
	}
	RXMLElement * enclosureElement = [itemNode child:@"enclosure"];
	if (enclosureElement) {
		NSMutableDictionary * enclosure = @{}.mutableCopy;
		NSString * sizeString = [enclosureElement attribute:@"size"];
		if (sizeString.length) {
		NSNumber * size = [NSNumber numberWithLongLong:[sizeString longLongValue]];
			enclosure[@"size"] = size;
		}
		NSString * type = [enclosureElement attribute:@"type"];
		if (type) enclosure[@"type"] = type;
		NSString * url = [enclosureElement attribute:@"url"];
		if (url) enclosure[@"url"] = url;
		item.enclosure = enclosure;
	}

	return item;
}

- (NSDictionary *)channelDictionaryRepresentation {

	if (!_feedDictionary) _feedDictionary = _channel.dictionaryRepresentation;
	return _feedDictionary;

}

@end



@implementation RSS2Channel

- (NSDictionary *)dictionaryRepresentation {
	
	NSArray * items = [self.items mapObjectsUsingBlock:^id(RSS2Item * item, NSUInteger idx) {
		return item.dictionaryRepresentation;
	}];
	
	
	NSMutableDictionary * rep = @{}.mutableCopy;
	
	if (self.title) rep[@"title"] = self.title;
	if (self.link.relativeString) rep[@"link"] = self.link.relativeString;
	if (self.channelDescription) rep[@"description"] = self.channelDescription;
	if (self.language) rep[@"language"] = self.language;
	if (self.copyright) rep[@"copyright"] = self.copyright;
	if (self.pubDate) rep[@"pubDate"] = [NSNumber numberWithDouble:self.pubDate.timeIntervalSince1970];
	//if (self.image) rep[@"image"] = self.image.dictionaryRepresentation;
	rep[@"item"] = items;
	rep[@"links"] = _links;
	
	return rep;
}

@end


@implementation RSS2Item

- (NSDictionary *)dictionaryRepresentation {
	
	NSMutableDictionary * representation = @{}.mutableCopy;

	if (self.title) representation[@"title"] = self.title;
	if (self.itemDescription) representation[@"description"] = self.itemDescription;
	if (self.content) representation[@"content"] = self.content;
	if (self.link) representation[@"link"] = self.link.relativeString;
	if (self.author) representation[@"author"] = self.author;
	//if (self.guid) representation[@"guid"] = self.guid;
	if (self.pubDate) representation[@"pubDate"] = [NSNumber numberWithDouble:self.pubDate.timeIntervalSince1970];
	if (self.media_thumbnail) representation[@"media:thumbnail"] = self.media_thumbnail;
	if (self.enclosure) representation[@"enclosure"] = self.enclosure;
	
	return representation;

}

@end

@implementation RSS2ChannelImage

- (NSDictionary *)dictionaryRepresentation {

	return @{
			 @"url":NoNilString(self.url.relativeString),
			 @"title":NoNilString(self.title),
			 @"link":NoNilString(self.link.relativeString)
			 };

}

@end
