/*
RSSPanelController.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 "SRAppController.h"
#import "SRBrowserController.h"

#import "SRPrefDefaultKeys.h"

#import "RSSFeedList.h"
#import "RSSPersistentStack.h"
#import "RSSManager.h"

#import "RSSPanelController.h"

#import "RSSContextMenu.h"

#import "RSSSyndication.h"

// Frame auto save name
NSString*   RSSPanelFrameAutoSaveName = @"RSSPanelFrameAutoSaveName";

@implementation RSSPanelController

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

+ (id)sharedInstance
{
    static RSSPanelController*  _sharedInstance = nil;
    if (!_sharedInstance) {
        _sharedInstance = [[RSSPanelController alloc] init];
    }
    
    return _sharedInstance;
}

- (id)init
{
    self = [super initWithWindowNibName:@"RSSPanel"];
    if (!self) {
        return nil;
    }
    
    // Register observer
    NSNotificationCenter*   center;
    center = [NSNotificationCenter defaultCenter];
    [center addObserver:self selector:@selector(rssArticlesRead:) 
            name:RSSArticlesRead object:nil];
    [center addObserver:self selector:@selector(rssPersistentStackRefreshed:) 
            name:RSSPersistentStackRefreshed object:[RSSPersistentStack sharedInstance]];
    
    NSDistributedNotificationCenter*    distributedCenter;
    distributedCenter = [NSDistributedNotificationCenter defaultCenter];
    [distributedCenter addObserver:self selector:@selector(feedWillStartRefresh:) 
            name:RSSDFeedWillStartRefresh object:nil];
    [distributedCenter addObserver:self selector:@selector(feedDidProgressRefresh:) 
            name:RSSDFeedProgressRefresh object:nil];
    [distributedCenter addObserver:self selector:@selector(feedDidEndRefresh:) 
            name:RSSDFeedDidEndRefresh object:nil];
    
    return self;
}

- (void)awakeFromNib
{
    // Configure window
    NSWindow*   window;
    window = [self window];
    [window setFrameAutosaveName:RSSPanelFrameAutoSaveName];
    
    // Configure RSS table
    [_tableView setTarget:self];
    [_tableView setDoubleAction:@selector(openRSSAction:)];
    
    // Set image text cell
    NSTableColumn*          column;
    NSCell*                 oldCell;
    HMImageTextFieldCell*   cell;
    column = [_tableView tableColumnWithIdentifier:@"rss"];
    oldCell = [column dataCell];
    cell = [[HMImageTextFieldCell alloc] init];
    [cell setFont:[oldCell font]];
    [column setDataCell:cell];
    [cell release];
    
    // Configure menu button
    [_menuButton setDelegate:self];
    
    // Set values
    [_content setValue:[NSNumber numberWithBool:NO] forKey:@"progressAnimate"];
}

- (void)dealloc
{
    // Remove observer
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    NSDistributedNotificationCenter*    distributedCenter;
    distributedCenter = [NSDistributedNotificationCenter defaultCenter];
    [distributedCenter removeObserver:self name:RSSDFeedWillStartRefresh object:nil];
    [distributedCenter removeObserver:self name:RSSDFeedProgressRefresh object:nil];
    [distributedCenter removeObserver:self name:RSSDFeedDidEndRefresh object:nil];
    
    [super dealloc];
}

//--------------------------------------------------------------//
#pragma mark -- RSS --
//--------------------------------------------------------------//

- (NSArray*)selectedRSSItems
{
    // Get selected objects
    NSArray*    objects;
    objects = [_rssArrayController selectedObjects];
    if (!objects || [objects count] == 0) {
        return nil;
    }
    
    return objects;
}

- (NSMenu*)_contextMenuForView:(id)view 
        event:(NSEvent*)event 
        from:(id)from
{
    NSUserDefaults* defaults;
    defaults = [NSUserDefaults standardUserDefaults];
    
    // Create array for tags
    NSMutableArray* tags;
    tags = [NSMutableArray array];
    
    // For right click on the outline view
    if (from == _tableView) {
        // Select RSS item under the cursor
        NSPoint point;
        int     rowUnderPoint;
        point = [view convertPoint:[event locationInWindow] 
                fromView:nil];
        rowUnderPoint = [view rowAtPoint:point];
        if (![[view selectedRowIndexes] containsIndex:rowUnderPoint]) {
            [view selectRowIndexes:[NSIndexSet indexSetWithIndex:rowUnderPoint] 
                    byExtendingSelection:NO];
        }
    }
    
    // Get selected rows
    NSIndexSet* indexSet;
    indexSet = [view selectedRowIndexes];
    
    id          rssItem = nil;
    NSArray*    rssItems = nil;
    
    // No RSS is selected
    if ([indexSet count] == 0) {
        // Create tag array
        [tags addObject:[NSNumber numberWithInt:SRMakeAllArticlesPreviewedTag]];
        [tags addObject:[NSNumber numberWithInt:SRRefreshAllFeedsTag]];
        [tags addObject:[NSNumber numberWithInt:SRDeleteAllArticlesTag]];
    }
    else {
        // Just one RSS item is selected
        if ([indexSet count] == 1) {
            // Get RSS item
            rssItem = [[self selectedRSSItems] objectAtIndex:0];
        }
        else {
            // Get RSS items
            rssItems = [self selectedRSSItems];
        }
        
        // Case of one RSS item
        if (rssItem) {
            // Create tag array
            [tags addObject:[NSNumber numberWithInt:SROpenRSSTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewBackgroundTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewWindowTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewBackgroundWindowTag]];
            
#if 0
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkInNewTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkInNewBackgroundTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkInNewWindowTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkInNewBackgroundWindowTag]];
#endif
            
            [tags addObject:[NSNumber numberWithInt:SRMakeArticlesPreviewedTag]];
            [tags addObject:[NSNumber numberWithInt:SRMakeAllArticlesPreviewedTag]];
            [tags addObject:[NSNumber numberWithInt:SRRefreshFeedTag]];
            [tags addObject:[NSNumber numberWithInt:SRRefreshAllFeedsTag]];
            
            [tags addObject:[NSNumber numberWithInt:SRDeleteFeedTag]];
            [tags addObject:[NSNumber numberWithInt:SRDeleteArticlseTag]];
            [tags addObject:[NSNumber numberWithInt:SRDeleteAllArticlesTag]];
        }
        // Case of multiple RSS items
        if (rssItems) {
            // Create tag array
            [tags addObject:[NSNumber numberWithInt:SROpenRSSTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewBackgroundTabTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewWindowTag]];
            [tags addObject:[NSNumber numberWithInt:SROpenRSSInNewBackgroundWindowTag]];
            
#if 0
            [tags addObject:[NSNumber numberWithInt:SROpenRSSLinkInTabsTag]];
#endif
            
            [tags addObject:[NSNumber numberWithInt:SRMakeArticlesPreviewedTag]];
            [tags addObject:[NSNumber numberWithInt:SRMakeAllArticlesPreviewedTag]];
            
            [tags addObject:[NSNumber numberWithInt:SRDeleteFeedTag]];
            [tags addObject:[NSNumber numberWithInt:SRDeleteArticlseTag]];
            [tags addObject:[NSNumber numberWithInt:SRDeleteAllArticlesTag]];
        }
    }
    
    if ([tags count] > 0) {
        // Copy menu
        NSMenu* menu;
        menu = HMCopyMenuWithTags([RSSContextMenu contextMenu], tags, self);
        
        // Set represented object
        if (rssItem) {
            [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                    withObject:rssItem];
        }
        if (rssItems) {
            [[menu itemArray] makeObjectsPerformSelector:@selector(setRepresentedObject:) 
                    withObject:rssItems];
        }
        
        // Set alt menu
        NSMenuItem* altMenuItem;
        if ([defaults boolForKey:SRTabSelectNewTabs]) {
            altMenuItem = [menu itemWithTag:SROpenRSSInNewBackgroundWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenRSSInNewBackgroundTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
#if 0
            altMenuItem = [menu itemWithTag:SROpenRSSLinkInNewBackgroundWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenRSSLinkInNewBackgroundTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
#endif
        }
        else {
            altMenuItem = [menu itemWithTag:SROpenRSSInNewWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenRSSInNewTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
#if 0
            altMenuItem = [menu itemWithTag:SROpenRSSLinkInNewWindowTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
            
            altMenuItem = [menu itemWithTag:SROpenRSSLinkInNewTabTag];
            [altMenuItem setKeyEquivalentModifierMask:NSShiftKeyMask];
            [altMenuItem setAlternate:YES];
#endif
        }
        
        return menu;
    }
    
    return nil;
}

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

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

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

- (NSString*)_urlStringOfSelectedItem
{
    // Get selected RSS
    NSArray*    rssItems;
    rssItems = [self selectedRSSItems];
    if (!rssItems || [rssItems count] == 0) {
        return nil;
    }
    
    // Get item
    NSDictionary*   rssItem;
    rssItem = [rssItems objectAtIndex:0];
    
    NSString*   urlString = nil;
    
    // For feed
    if ([rssItem valueForKey:@"feedURL"]) {
        // Get feed URL
        urlString = [rssItem valueForKey:@"feedURL"];
    }
    
    // Change scheme
    if ([urlString hasPrefix:@"http://"]) {
        urlString = [NSString stringWithFormat:@"rss://%@", [urlString substringFromIndex:7]];
    }
    
    return urlString;
}

- (void)openRSSAction:(id)sender
{
    // Get URL of selected RSS
    NSString*   urlString;
    urlString = [self _urlStringOfSelectedItem];
    if (!urlString) {
        return;
    }
    
    // Open URL
    WebView*    webView;
    webView = [[[SRAppController sharedInstance] openURLString:urlString] webView];
    
    // Make web view window key window
    NSWindow*   window;
    window = [webView window];
    if (window) {
        [window makeKeyWindow];
    }
}

- (void)openRSSInNewTabAction:(id)sender
{
    // Get URL of selected RSS
    NSString*   urlString;
    urlString = [self _urlStringOfSelectedItem];
    if (!urlString) {
        return;
    }
    
    // Open URL in new tab
    [[SRBrowserController mainBrowserController] 
            openInNewTabURLString:urlString];
}

- (void)openRSSInNewBackgroundTabAction:(id)sender
{
    // Get URL of selected RSS
    NSString*   urlString;
    urlString = [self _urlStringOfSelectedItem];
    if (!urlString) {
        return;
    }
    
    // Open URL in new background tab
    [[SRBrowserController mainBrowserController] 
            openInNewTabURLString:urlString select:NO];
}

- (void)openRSSInNewWindowAction:(id)sender
{
    // Get URL of selected RSS
    NSString*   urlString;
    urlString = [self _urlStringOfSelectedItem];
    if (!urlString) {
        return;
    }
    
    // Open URL in new background tab
    [[SRBrowserController mainBrowserController] 
            openInNewWindowURLString:urlString];
}

- (void)openRSSInNewBackgroundWindowAction:(id)sender
{
    // Get URL of selected RSS
    NSString*   urlString;
    urlString = [self _urlStringOfSelectedItem];
    if (!urlString) {
        return;
    }
    
    // Open URL in new background tab
    [[SRBrowserController mainBrowserController] 
            openInNewBackgroundWindowURLString:urlString];
}

- (void)openRSSLinkAction:(id)sender
{
}

- (void)openRSSLinkInNewTabAction:(id)sender
{
}

- (void)openRSSLinkInNewBackgroundTabAction:(id)sender
{
}

- (void)openRSSLinkInNewWindowAction:(id)sender
{
}

- (void)openRSSLinkInNewBackgroundWindowAction:(id)sender
{
}

- (void)openRSSLinkInTabs:(id)sender
{
}

- (void)makeArticlesPreviewedAction:(id)sender
{
    // Get selected RSS
    NSArray*    rssItems;
    rssItems = [self selectedRSSItems];
    if (!rssItems || [rssItems count] == 0) {
        return;
    }
    
    // Get item
    NSDictionary*   rssItem;
    rssItem = [rssItems objectAtIndex:0];
    
    // Make articles previewed
    [[RSSManager sharedInstance] makeItemsPreviewedWithFeed:rssItem];
}

- (void)makeAllArticlesPreviewedAction:(id)sender
{
    // Make all articles previewed
    [[RSSManager sharedInstance] makeAllArticlesPreviewed];
}

- (void)refreshFeedAction:(id)sender
{
    // Get selected RSS
    NSArray*    rssItems;
    rssItems = [self selectedRSSItems];
    if (!rssItems || [rssItems count] == 0) {
        return;
    }
    
    // Refresh feed
    NSMutableArray* feedURLs;
    NSEnumerator*   enumerator;
    id              feed;
    feedURLs = [NSMutableArray array];
    enumerator = [rssItems objectEnumerator];
    while (feed = [enumerator nextObject]) {
        NSString*   feedURL;
        feedURL = [feed valueForKey:@"feedURL"];
        if (feedURL) {
            [feedURLs addObject:feedURL];
        }
    }
    
    [[RSSManager sharedInstance] refreshFeeds:feedURLs];
}

- (void)refreshAllFeedsAction:(id)sender
{
    // Refresh all feeds
    [[RSSManager sharedInstance] refreshAllFeeds];
}

- (void)deleteFeedAction:(id)sender
{
}

- (void)deleteArticlesAction:(id)sender
{
}

- (void)deleteAllArticlesAction:(id)sender
{
}

- (void)showShelfAction:(id)sender
{
    [[SRAppController sharedInstance] openShelf:@"jp.hmdt.shiira.rssshelf"];
}

//--------------------------------------------------------------//
#pragma mark -- NSTableView data source --
//--------------------------------------------------------------//

- (int)numberOfRowsInTableView:(NSTableView*)tableView
{
    return 0;
}

- (id)tableView:(NSTableView*)tableView 
        objectValueForTableColumn:(NSTableColumn*)tableColumn row:(int)rowIndex
{
    return nil;
}

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

- (int)_unreadArticlesNumberWithFeedURL:(NSString*)urlString
{
    // Get managed object context
    NSManagedObjectContext* context;
    context = [self managedObjectContext];
    
    // Get feed
    NSFetchRequest* request;
    request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:
            [NSEntityDescription entityForName:@"RSSFeed" inManagedObjectContext:context]];
    [request setPredicate:
            [NSPredicate predicateWithFormat:@"feedURL == %@", urlString]];
    
    NSArray*    items;
    items = [context executeFetchRequest:request error:NULL];
    if ([items count] != 1) {
        return 0;
    }
    
    // Get number of unread articles
    return [[[items objectAtIndex:0] valueForKey:@"numberOfUnreadArticles"] intValue];
}

- (void)tableView:(NSTableView*)tableView 
        willDisplayCell:(id)cell 
        forTableColumn:(NSTableColumn*)column 
        row:(int)index
{
    // RSS table
    if (tableView == _tableView) {
        // Get column identifier
        id  identifier;
        identifier = [column identifier];
        
        // For RSS column
        if ([identifier isEqualToString:@"rss"]) {
            // Get object
            NSArray*    objects;
            objects = [_rssArrayController arrangedObjects];
            if ([objects count] > index) {
                id  object;
                object = [objects objectAtIndex:index];
                
                // Get feed URL
                NSImage*    image = nil;
                NSString*   urlString;
                urlString = [object valueForKey:@"feedURL"];
                if (urlString) {
                    WebIconDatabase*    database;
                    database = [WebIconDatabase sharedIconDatabase];
                    
                    if ([database iconURLForURL:urlString]) {
                        image = [database iconForURL:urlString withSize:NSMakeSize(16, 16)];
                    }
                }
                if (!image) {
                    image = [NSImage imageNamed:@"rssIcon"];
                }
                
                // Set image
                [cell setImage:image];
                
                // Get unread articles number
                int number;
                number = [self _unreadArticlesNumberWithFeedURL:urlString];
                [cell setTextFieldType:HMNumberedTextFieldType];
                [cell setNumber:number];
            }
            
            return;
        }
    }
}

//--------------------------------------------------------------//
#pragma mark -- NSTableViewEx delegate --
//--------------------------------------------------------------//

- (NSMenu*)tableView:(NSTableView*)tableView menuForEvent:(NSEvent*)event
{
    return [self _contextMenuForView:tableView event:event from:tableView];
}

//--------------------------------------------------------------//
#pragma mark -- HMMenuButton delegate --
//--------------------------------------------------------------//

- (NSMenu*)menuButton:(HMMenuButton*)menuButton menuForEvent:(NSEvent*)event
{
    return [self _contextMenuForView:_tableView event:event from:menuButton];
}

//--------------------------------------------------------------//
#pragma mark -- RSSController notification --
//--------------------------------------------------------------//

- (void)rssArticlesRead:(NSNotification*)notification
{
    // Reload table
    [_tableView reloadData];
}

//--------------------------------------------------------------//
#pragma mark -- RSSPersistentStack notification --
//--------------------------------------------------------------//

- (void)rssPersistentStackRefreshed:(NSNotification*)notification
{
    // Prepare content
    [_rssArrayController prepareContent];
}

//--------------------------------------------------------------//
#pragma mark -- RSSSyndication notification --
//--------------------------------------------------------------//

- (void)feedWillStartRefresh:(NSNotification*)notification
{
    // Set values
    [_content setValue:[NSNumber numberWithBool:YES] forKey:@"progressAnimate"];
}

- (void)feedDidProgressRefresh:(NSNotification*)notification
{
    // Do nothing
}

- (void)feedDidEndRefresh:(NSNotification*)notification
{
    // Set values
    [_content setValue:[NSNumber numberWithBool:NO] forKey:@"progressAnimate"];
}

@end
