/*
 * Copyright (C) 2009 Apple Inc. 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 APPLE INC. ``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 APPLE INC. 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. 
 */

#if !ENABLE_SPARKLE

void initializeSparkle()
{
    // No-op.
}

#else // ENABLE_SPARKLE

#import <Cocoa/Cocoa.h>
#import <Sparkle/SUUpdater.h>
#import <objc/objc-runtime.h>
#import "WebKitNightlyEnabler.h"

// We need to tweak the wording of the prompt to make sense in the context of WebKit and Safari.
static NSString* updatePermissionPromptDescription(id self, SEL _cmd)
{
    return @"Should WebKit automatically check for updates? You can always check for updates manually from the Safari menu.";
}

static NSPanel *updateAlertPanel(id updateItem, id host)
{
    NSString *hostName = objc_msgSend(host, @selector(name));
    NSPanel *panel = NSGetInformationalAlertPanel([NSString stringWithFormat:@"Would you like to download and install %@ %@ now?", hostName, objc_msgSend(updateItem, @selector(displayVersionString))],
                                                  @"%@",
                                                  @"Install Update", @"Skip This Version", @"Remind Me Later",
                                                  [NSString stringWithFormat:@"You are currently running %@ %@.", hostName, objc_msgSend(host, @selector(displayVersion))]);
    NSArray *subviews = [[panel contentView] subviews];
    NSEnumerator *e = [subviews objectEnumerator];
    NSView *view;
    while ((view = [e nextObject])) {
        if (![view isKindOfClass:[NSButton class]])
            continue;

        NSButton *button = (NSButton *)view;
        [button setAction:@selector(webKitHandleButtonPress:)];
        if ([button tag] == NSAlertOtherReturn)
            [button setKeyEquivalent:@"\033"];
    }
    [panel center];
    return panel;
}

// Sparkle's udpate alert panel looks odd with the release notes hidden, so we
// swap it out with a standard NSAlert-style panel instead.
static id updateAlertInitForAlertPanel(id self, SEL _cmd, id updateItem, id host)
{
    NSPanel *panel = updateAlertPanel(updateItem, host);
    [panel setDelegate:self];

    self = [self initWithWindow:panel];
    if (!self)
        return nil;

    [updateItem retain];
    [host retain];

    object_setInstanceVariable(self, "updateItem", (void*)updateItem);
    object_setInstanceVariable(self, "host", (void*)host);

    [self setShouldCascadeWindows:NO];

    return self;
}

@implementation NSAlert (WebKitLauncherExtensions)

- (void)webKitHandleButtonPress:(id)sender
{
    // We rely on the fact that NSAlertOtherReturn == -1, NSAlertAlternateReturn == 0 and NSAlertDefaultReturn == 1
    // to map the button tag to the corresponding selector
    SEL selectors[] = { @selector(remindMeLater:), @selector(skipThisVersion:), @selector(installUpdate:) };
    SEL selector = selectors[[sender tag] + 1];

    id delegate = [[sender window] delegate];
    objc_msgSend(delegate, selector, sender);
}

@end

static NSString *userAgentStringForSparkle()
{
    NSBundle *safariBundle = [NSBundle mainBundle];
    NSString *safariVersion = [[safariBundle localizedInfoDictionary] valueForKey:@"CFBundleShortVersionString"];
    NSString *safariBuild = [[[safariBundle infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] substringFromIndex:1];
    NSString *webKitRevision = [[webKitLauncherBundle() infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey];
    NSString *applicationName = [NSString stringWithFormat:@"Version/%@ Safari/%@ WebKitRevision/%@", safariVersion, safariBuild, webKitRevision];
    Class WebView = objc_lookUpClass("WebView");
    return objc_msgSend(WebView, @selector(_standardUserAgentWithApplicationName:), applicationName);
}

void initializeSparkle()
{
    // Override some Sparkle behaviour
    Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdatePermissionPrompt"), @selector(promptDescription));
    method_setImplementation(methodToPatch, (IMP)updatePermissionPromptDescription);

    methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdateAlert"), @selector(initWithAppcastItem:host:));
    method_setImplementation(methodToPatch, (IMP)updateAlertInitForAlertPanel);

    SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()];
    [updater setUserAgentString:userAgentStringForSparkle()];

    // Find the first separator on the Safari menu…
    NSMenu *applicationSubmenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
    int i = 0;
    for (; i < [applicationSubmenu numberOfItems]; i++) {
        if ([[applicationSubmenu itemAtIndex:i] isSeparatorItem])
            break;
    }

    // … and insert a menu item that can be used to manually trigger update checks.
    NSMenuItem *updateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for WebKit Updates…" action:@selector(checkForUpdates:) keyEquivalent:@""];
    [updateMenuItem setTarget:updater];
    [applicationSubmenu insertItem:updateMenuItem atIndex:i];
    [updateMenuItem release];
}

#endif // ENABLE_SPARKLE
