// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/ui/cocoa/external_protocol_dialog.h"

#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/gfx/text_elider.h"

///////////////////////////////////////////////////////////////////////////////
// ExternalProtocolHandler

// static
void ExternalProtocolHandler::RunExternalProtocolDialog(
    const GURL& url, int render_process_host_id, int routing_id,
    ui::PageTransition page_transition, bool has_user_gesture) {
  [[ExternalProtocolDialogController alloc] initWithGURL:&url
                                     renderProcessHostId:render_process_host_id
                                               routingId:routing_id];
}

///////////////////////////////////////////////////////////////////////////////
// ExternalProtocolDialogController

@interface ExternalProtocolDialogController(Private)
- (void)alertEnded:(NSAlert *)alert
        returnCode:(int)returnCode
       contextInfo:(void*)contextInfo;
@end

@implementation ExternalProtocolDialogController
- (id)initWithGURL:(const GURL*)url
    renderProcessHostId:(int)renderProcessHostId
    routingId:(int)routingId {
  DCHECK(base::MessageLoopForUI::IsCurrent());

  if (!(self = [super init]))
    return nil;

  url_ = *url;
  render_process_host_id_ = renderProcessHostId;
  routing_id_ = routingId;
  creation_time_ = base::Time::Now();

  base::string16 appName =
      shell_integration::GetApplicationNameForProtocol(url_);
  if (appName.length() == 0) {
    // No registered apps for this protocol; give up and go home.
    [self autorelease];
    return nil;
  }

  alert_ = [[NSAlert alloc] init];

  [alert_ setMessageText:
      l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_TITLE)];

  NSButton* allowButton = [alert_ addButtonWithTitle:
      l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_OK_BUTTON_TEXT)];
  [allowButton setKeyEquivalent:@""];  // disallow as default
  [alert_ addButtonWithTitle:
      l10n_util::GetNSStringWithFixup(
        IDS_EXTERNAL_PROTOCOL_CANCEL_BUTTON_TEXT)];

  const size_t kMaxUrlWithoutSchemeSize = 256;
  base::string16 elided_url_without_scheme;
  gfx::ElideString(base::ASCIIToUTF16(url_.possibly_invalid_spec()),
                  kMaxUrlWithoutSchemeSize, &elided_url_without_scheme);

  NSString* urlString = l10n_util::GetNSStringFWithFixup(
      IDS_EXTERNAL_PROTOCOL_INFORMATION,
      base::ASCIIToUTF16(url_.scheme() + ":"),
      elided_url_without_scheme);
  NSString* appString = l10n_util::GetNSStringFWithFixup(
      IDS_EXTERNAL_PROTOCOL_APPLICATION_TO_LAUNCH,
      appName);
  NSString* warningString =
      l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_WARNING);
  NSString* informativeText =
      [NSString stringWithFormat:@"%@\n\n%@\n\n%@",
                                 urlString,
                                 appString,
                                 warningString];

  [alert_ setInformativeText:informativeText];

  [alert_ setShowsSuppressionButton:YES];
  [[alert_ suppressionButton] setTitle:
      l10n_util::GetNSStringWithFixup(IDS_EXTERNAL_PROTOCOL_CHECKBOX_TEXT)];

  [alert_ beginSheetModalForWindow:nil  // nil here makes it app-modal
                     modalDelegate:self
                    didEndSelector:@selector(alertEnded:returnCode:contextInfo:)
                       contextInfo:nil];

  return self;
}

- (void)dealloc {
  [alert_ release];

  [super dealloc];
}

- (void)alertEnded:(NSAlert *)alert
        returnCode:(int)returnCode
       contextInfo:(void*)contextInfo {
  ExternalProtocolHandler::BlockState blockState =
      ExternalProtocolHandler::UNKNOWN;
  switch (returnCode) {
    case NSAlertFirstButtonReturn:
      blockState = ExternalProtocolHandler::DONT_BLOCK;
      break;
    case NSAlertSecondButtonReturn:
      blockState = ExternalProtocolHandler::BLOCK;
      break;
    default:
      NOTREACHED();
  }

  // Set the "don't warn me again" info.
  if ([[alert_ suppressionButton] state] == NSOnState)
    ExternalProtocolHandler::SetBlockState(url_.scheme(), blockState);

  if (blockState == ExternalProtocolHandler::DONT_BLOCK) {
    UMA_HISTOGRAM_LONG_TIMES("clickjacking.launch_url",
                             base::Time::Now() - creation_time_);

    ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(
        url_, render_process_host_id_, routing_id_);
  }

  [self autorelease];
}

@end