/*
RSSController.m

Author: Makoto Kinoshita

Copyright 2004-2006 The Shiira Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of 
  conditions and the following disclaimer in the documentation and/or other materials provided 
  with the distribution.

THIS SOFTWARE IS PROVIDED BY THE SHIIRA PROJECT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE SHIIRA PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

#import "SRBrowserController.h"
#import "SRPageController.h"

#import "RSSFeedParser.h"
#import "RSSController.h"
#import "RSSPersistentStack.h"

static NSArray* _templateKeys = nil;

@interface RSSController (private)

// Contents HTML
- (NSString*)_createHTMLWithItem:(id)item;
- (NSString*)_createHTMLWithFeed:(id)feed;

@end

@implementation RSSController

//--------------------------------------------------------------//
#pragma mark -- Initialize --
//--------------------------------------------------------------//

- (id)init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    // Load nib
    if (![NSBundle loadNibNamed:@"RSSView" owner:self]) {
        // Error
        NSLog(@"Can't load RSSView.nib");
        return nil;
    }
    
    // Create template keys
    if (!_templateKeys) {
        _templateKeys = [[NSArray arrayWithObjects:
                @"$ENTRY_TITLE$", @"$ENTRY_LINK$", @"$ENTRY_DATE$", @"$ENTRY_CONTENT$", nil] retain];
    }
    
#if 0
    // Copy RSS template
    static BOOL _copyDone = NO;
    if (!_copyDone) {
        NSFileManager*  fileMgr;
        NSString*       srcPath;
        NSString*       destPath;
        fileMgr = [NSFileManager defaultManager];
        srcPath = [[[NSBundle mainBundle] resourcePath] 
                stringByAppendingPathComponent:@"template"];
        destPath = [HMApplicationSupportFolder(@"Shiira") stringByAppendingPathComponent:@"template"];
        if ([fileMgr fileExistsAtPath:destPath]) {
            [fileMgr removeFileAtPath:destPath handler:NULL];
        }
        [fileMgr copyPath:srcPath toPath:destPath handler:NULL];
        
        _copyDone = YES;
    }
#endif
    
    return self;
}

- (void)awakeFromNib
{
    NSRect  frame;
    
    // Get bar frame
    NSRect  barFrame;
    barFrame = [_rssBar frame];
    
    // Create buttons
    frame.origin.x = barFrame.size.width - 56;
    frame.origin.y = 4;
    frame.size = NSMakeSize(25, 19);
    _tableButton = [[NSClassFromString(@"HMButton") alloc] initWithFrame:frame];
    [_tableButton setButtonType:NSMomentaryChangeButton];
    [_tableButton setBezelStyle:NSRegularSquareBezelStyle];
    [_tableButton setAutoresizingMask:NSViewMinXMargin];
    [_tableButton setBordered:NO];
    [_tableButton setImage:[NSImage imageNamed:@"shelfListBrowser"]];
    [_tableButton setSelectedImage:[NSImage imageNamed:@"shelfPressedBackground"]];
    [_tableButton setTarget:self];
    [_tableButton setAction:@selector(selectDisplayAction:)];
    [_rssBar addSubview:_tableButton];
    
    frame.origin.x = barFrame.size.width - 29;
    frame.origin.y = 4;
    frame.size = NSMakeSize(25, 19);
    _listButton = [[NSClassFromString(@"HMButton") alloc] initWithFrame:frame];
    [_listButton setButtonType:NSMomentaryChangeButton];
    [_listButton setBezelStyle:NSRegularSquareBezelStyle];
    [_listButton setAutoresizingMask:NSViewMinXMargin];
    [_listButton setBordered:NO];
    [_listButton setImage:[NSImage imageNamed:@"shelfTableView"]];
    [_listButton setSelectedImage:[NSImage imageNamed:@"shelfPressedBackground"]];
    [_listButton setTarget:self];
    [_listButton setAction:@selector(selectDisplayAction:)];
    [_rssBar addSubview:_listButton];
    
    // Configure list view
    [_listSplitView setSplitType:HMSplitWide];
    
    // Configure array controller
    NSSortDescriptor*   sortDescriptor;
    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
    [_itemArrayController setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];
    
    // Configure table view
    NSTableColumn*          column;
    NSCell*                 oldCell;
    HMImageTextFieldCell*   cell;
    column = [_listTableView tableColumnWithIdentifier:@"title"];
    oldCell = [column dataCell];
    cell = [[HMImageTextFieldCell alloc] init];
    [cell setFont:[oldCell font]];
    [column setDataCell:cell];
    [cell release];
    
    column = [_listTableView tableColumnWithIdentifier:@"dateAndTime"];
    oldCell = [column dataCell];
    cell = [[HMImageTextFieldCell alloc] init];
    [cell setFont:[oldCell font]];
    [column setDataCell:cell];
    [cell release];
    
    // Set display style
    [self setDisplayStyle:RSSTableStyle];
}

- (void)dealloc
{
    [_listButton release], _listButton = nil;
    [_tableButton release], _tableButton = nil;
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- View --
//--------------------------------------------------------------//

- (NSView*)view
{
    return _view;
}

//--------------------------------------------------------------//
#pragma mark -- Display style --
//--------------------------------------------------------------//

- (void)_updateDisplayStyle
{
    // Get view frame
    NSRect  frame;
    frame = [_lowerView bounds];
    
    // Decide display style
    int displayStyle = RSSListStyle;
    if ([_listButton isSelected]) {
        displayStyle = RSSListStyle;
    }
    else if ([_tableButton isSelected]) {
        displayStyle = RSSTableStyle;
    }
    
    // For list
    if (displayStyle == RSSListStyle) {
        if ([_tableView superview] == _lowerView) {
            [_tableView removeFromSuperview];
        }
        
        [_listView setFrame:frame];
        [_lowerView addSubview:_listView];
    }
    // For table
    if (displayStyle == RSSTableStyle) {
        if ([_listView superview] == _lowerView) {
            [_listView removeFromSuperview];
        }
        
        [_tableView setFrame:frame];
        [_lowerView addSubview:_tableView];
        
        // Create HTML
        NSString*   html;
        html = [self _createHTMLWithFeed:_feed];
        if (!html) {
            html = @"";
        }
        
        // Load HTML
        NSString*   path;
        path = [HMApplicationSupportFolder(@"Shiira") stringByAppendingPathComponent:@"template/tmp.html"];
        [[html dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES];
        [[_tableWebView mainFrame] loadRequest:
                [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
    }
}

- (void)setDisplayStyle:(int)displayStyle
{
    // Select button
    switch (displayStyle) {
    case RSSListStyle: {
        [_listButton setSelected:YES];
        [_tableButton setSelected:NO];
        break;
    }
    case RSSTableStyle: {
        [_listButton setSelected:NO];
        [_tableButton setSelected:YES];
        break;
    }
    }
    
    // Update display style
    [self _updateDisplayStyle];
}

//--------------------------------------------------------------//
#pragma mark -- WebDataSource loading --
//--------------------------------------------------------------//

- (void)finishedLoadingWithDataSource:(WebDataSource*)dataSource
{
    // Get RSS data
    NSData* data;
    data = [dataSource data];
    
    // Create XML document
    NSXMLDocument*  document;
    document = [[NSXMLDocument alloc] initWithData:data options:0 error:NULL];
    
    // Parse it
    RSSFeedParser*  parser;
    parser = [[RSSFeedParser alloc] initWithXMLNode:[document rootElement]];
    _feed = [parser parseWithManagedObjectContext:[self managedObjectContext]];
    [parser release];
    
    // Set title
    [_rssBar setTitle:[self title]];
    
    // Set contents
    [_itemArrayController setContent:[_feed valueForKey:@"items"]];
    
    // Update appearance
    [self _updateDisplayStyle];
}

//--------------------------------------------------------------//
#pragma mark -- Feed --
//--------------------------------------------------------------//

- (NSString*)title
{
    NSString*   title;
    title = [_feed valueForKey:@"title"];
    if ([title length] == 0) {
        title = NSLocalizedString(@"(Untitled)", nil);
    }
    
    return title;
}

- (NSString*)link
{
    return [_feed valueForKey:@"link"];
}

//--------------------------------------------------------------//
#pragma mark -- Persistent stack --
//--------------------------------------------------------------//

- (NSManagedObjectContext*)managedObjectContext
{
    return [[RSSPersistentStack sharedInstance] managedObjectContext];
}

//--------------------------------------------------------------//
#pragma mark -- Contents HTML --
//--------------------------------------------------------------//

- (NSString*)_valueForTemplateKey:(NSString*)key item:(id)item
{
    // title
    if ([key isEqualToString:@"$ENTRY_TITLE$"]) {
        return [item valueForKey:@"title"];
    }
    // link
    if ([key isEqualToString:@"$ENTRY_LINK$"]) {
        return [item valueForKey:@"link"];
    }
    // date
    if ([key isEqualToString:@"$ENTRY_DATE$"]) {
        return [[item valueForKey:@"date"] 
                descriptionWithCalendarFormat:@"%y/%m/%d %H:%M" 
                timeZone:nil 
                locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]];
    }
    // date
    if ([key isEqualToString:@"$ENTRY_DATE$"]) {
        return [[item valueForKey:@"date"] description];
    }
    // content
    if ([key isEqualToString:@"$ENTRY_CONTENT$"]) {
        return [item valueForKey:@"content"];
    }
    
    return nil;
}

- (NSString*)_createHTMLWithItem:(id)item
{
    // Check arguments
    if (!item) {
        return nil;
    }
    
    // Load template
    NSString*   resPath;
    NSString*   path;
    NSString*   entryTemplate;
    resPath = [[NSBundle mainBundle] resourcePath];
    path = [resPath stringByAppendingPathComponent:@"template/EntryTemplate.html"];
    entryTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!entryTemplate) {
        // Error
        NSLog(@"Can't load EntryTemplate.html");
        return nil;
    }
    
    // Create buffer
    NSMutableString*    html;
    html = [NSMutableString stringWithString:entryTemplate];
    
    // Replace keys
    NSEnumerator*   enumerator;
    NSString*       templateKey;
    enumerator = [_templateKeys objectEnumerator];
    while (templateKey = [enumerator nextObject]) {
        // Find in buffer
        if ([html rangeOfString:templateKey].location == NSNotFound) {
            continue;
        }
        
        // Get value for template key
        NSString*   value;
        value = [self _valueForTemplateKey:templateKey item:item];
        if (!value) {
            value = @"";
        }
        
        // Replace it
        [html replaceOccurrencesOfString:templateKey 
                withString:value options:0 range:NSMakeRange(0, [html length])];
    }
    
    return html;
}

- (NSString*)_createHTMLWithFeed:(id)feed
{
    // Check arguments
    if (!feed) {
        return nil;
    }
    
    // Load templates
    NSString*   resPath;
    NSString*   path;
    NSString*   feedTemplate;
    NSString*   feedEntryTemplate;
    NSString*   feedEntryAltTemplate;
    resPath = [[NSBundle mainBundle] resourcePath];
    path = [resPath stringByAppendingPathComponent:@"template/FeedTemplate.html"];
    feedTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!feedTemplate) {
        // Error
        NSLog(@"Can't load EntryTemplate.html");
        return nil;
    }
    
    path = [resPath stringByAppendingPathComponent:@"template/FeedEntryTemplate.html"];
    feedEntryTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!feedEntryTemplate) {
        feedEntryTemplate = @"";
    }
    
    path = [resPath stringByAppendingPathComponent:@"template/FeedEntryAltTemplate.html"];
    feedEntryAltTemplate = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!feedEntryAltTemplate) {
        feedEntryAltTemplate = @"";
    }
    
    // Create buffer
    NSMutableString*    html;
    html = [NSMutableString stringWithString:feedTemplate];
    
    //
    // Replace feed keys
    //
    NSEnumerator*   enumerator;
    NSString*       templateKey;
    enumerator = [_templateKeys objectEnumerator];
    while (templateKey = [enumerator nextObject]) {
        // Find in buffer
        if ([html rangeOfString:templateKey].location == NSNotFound) {
            continue;
        }
        
        // Get value for template key
        NSString*   value;
        value = [self _valueForTemplateKey:templateKey item:feed];
        if (!value) {
            value = @"";
        }
        
        // Replace it
        [html replaceOccurrencesOfString:templateKey 
                withString:value options:0 range:NSMakeRange(0, [html length])];
    }
    
    //
    // Create entries
    //
    
    // Get sorted items
    NSArray*            items;
    NSSortDescriptor*   sortDescriptor;
    sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO];
    items = [[feed valueForKey:@"items"] allObjects];
    items = [items sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
    [sortDescriptor release];
    
    // Enumerate items
    NSMutableString*    entries;
    NSEnumerator*       itemEnumerator;
    id                  item;
    int                 count = 0;
    entries = [NSMutableString string];
    itemEnumerator = [items objectEnumerator];
    while (item = [itemEnumerator nextObject]) {
        // Copy template
        NSMutableString*    entry;
        if (count % 2 == 0) {
            entry = [NSMutableString stringWithString:feedEntryTemplate];
        }
        else {
            entry = [NSMutableString stringWithString:feedEntryAltTemplate];
        }
        count++;
        
        // Replace keys
        enumerator = [_templateKeys objectEnumerator];
        while (templateKey = [enumerator nextObject]) {
            // Find in buffer
            if ([entry rangeOfString:templateKey].location == NSNotFound) {
                continue;
            }
            
            // Get value for template key
            NSString*   value;
            value = [self _valueForTemplateKey:templateKey item:item];
            if (!value) {
                value = @"";
            }
            
            // Replace it
            [entry replaceOccurrencesOfString:templateKey 
                    withString:value options:0 range:NSMakeRange(0, [entry length])];
        }
        
        // Append entry
        [entries appendString:entry];
    }
    
    // Replace entry
    [html replaceOccurrencesOfString:@"$ENTRIES$" 
            withString:entries options:0 range:NSMakeRange(0, [html length])];
    
    return html;
}

//--------------------------------------------------------------//
#pragma mark -- Action --
//--------------------------------------------------------------//

- (void)selectDisplayAction:(id)sender
{
    // Set display style
    if (sender == _listButton) {
        [self setDisplayStyle:RSSListStyle];
    }
    if (sender == _tableButton) {
        [self setDisplayStyle:RSSTableStyle];
    }
}

//--------------------------------------------------------------//
#pragma mark -- WebView delegate --
//--------------------------------------------------------------//

- (void)webView:(WebView*)webView 
        decidePolicyForNavigationAction:(NSDictionary*)info 
        request:(NSURLRequest*)request 
        frame:(WebFrame*)frame 
        decisionListener:(id<WebPolicyDecisionListener>)listener
{
    // Get navigation type
    WebNavigationType   navigationType;
    navigationType = [[info objectForKey:WebActionNavigationTypeKey] intValue];
    
    // For link click
    if (navigationType == WebNavigationTypeLinkClicked) {
        // Open in new tab by borwser controller
        SRBrowserController*    browserController;
        browserController = (SRBrowserController*)[[_view window] windowController];
        [browserController openInNewTabURL:[request URL]];
        
        [listener ignore];
        return;
    }
    
    // Use it
    [listener use];
}

//--------------------------------------------------------------//
#pragma mark -- NSTableView delegate --
//--------------------------------------------------------------//

- (void)tableViewSelectionDidChange:(NSNotification*)notification
{
    // Get selected item
    NSArray*    items;
    id          item;
    items = [_itemArrayController selectedObjects];
    if ([items count] == 0) {
        return;
    }
    item = [items objectAtIndex:0];
    
    // Create HTML
    NSString*   html;
    html = [self _createHTMLWithItem:item];
    if (!html) {
        html = @"";
    }
    
    // Load HTML
    NSString*   path;
    path = [HMApplicationSupportFolder(@"Shiira") stringByAppendingPathComponent:@"template/tmp.html"];
    [[html dataUsingEncoding:NSUTF8StringEncoding] writeToFile:path atomically:YES];
    [[_listWebView mainFrame] loadRequest:
            [NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
}

@end
