// Copyright (c) 2011 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.

#include "base/bind.h"
#include "base/command_line.h"
#include "base/mac/mac_util.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/background/background_mode_manager.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
#include "ui/base/l10n/l10n_util.h"

using content::BrowserThread;

namespace {
void SetUserRemovedLoginItemPrefOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  PrefService* service = g_browser_process->local_state();
  service->SetBoolean(prefs::kUserRemovedLoginItem, true);
}

void SetCreatedLoginItemPrefOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
  PrefService* service = g_browser_process->local_state();
  service->SetBoolean(prefs::kChromeCreatedLoginItem, true);
}

void DisableLaunchOnStartupOnFileThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
  // If the LoginItem is not hidden, it means it's user created, so don't
  // delete it.
  bool is_hidden = false;
  if (base::mac::CheckLoginItemStatus(&is_hidden) && is_hidden)
    base::mac::RemoveFromLoginItems();
}

void CheckForUserRemovedLoginItemOnFileThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
  if (!base::mac::CheckLoginItemStatus(NULL)) {
    // There's no LoginItem, so set the kUserRemovedLoginItem pref.
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::Bind(SetUserRemovedLoginItemPrefOnUIThread));
  }
}

void EnableLaunchOnStartupOnFileThread(bool need_migration) {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
  if (need_migration) {
    // This is the first time running Chrome since the kChromeCreatedLoginItem
    // pref was added. Initialize the status of this pref based on whether
    // there is already a hidden login item.
    bool is_hidden = false;
    if (base::mac::CheckLoginItemStatus(&is_hidden)) {
      if (is_hidden) {
      // We already have a hidden login item, so set the kChromeCreatedLoginItem
      // flag.
        BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                                base::Bind(SetCreatedLoginItemPrefOnUIThread));
      }
      // LoginItem already exists - just exit.
      return;
    }
  }

  // Check if Chrome is already a Login Item - if not, create one.
  if (!base::mac::CheckLoginItemStatus(NULL)) {
    // Call back to the UI thread to set our preference so we know that Chrome
    // created the login item (which means we are allowed to delete it later).
    // There's a race condition here if the user disables launch on startup
    // before our callback is run, but the user can manually disable
    // "Open At Login" via the dock if this happens.
    base::mac::AddToLoginItems(true);  // Hide on startup.
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::Bind(SetCreatedLoginItemPrefOnUIThread));
  }
}

}  // namespace

void BackgroundModeManager::EnableLaunchOnStartup(bool should_launch) {
  // LoginItems are associated with an executable, not with a specific
  // user-data-dir, so only mess with the LoginItem when running with the
  // default user-data-dir. So if a user is running multiple instances of
  // Chrome with different user-data-dirs, they won't conflict in their
  // use of LoginItems.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserDataDir))
    return;

  // There are a few cases we need to handle:
  //
  // 1) Chrome is transitioning to "launch on startup" state, and there's no
  // login item currently. We create a new item if the kUserRemovedLoginItem
  // and kChromeCreatedLoginItem flags are already false, and set the
  // kChromeCreatedLoginItem flag to true. If kChromeCreatedLoginItem is
  // already set (meaning that we created a login item that has since been
  // deleted) then we will set the kUserRemovedLoginItem so we do not create
  // login items in the future.
  //
  // 2) Chrome is transitioning to the "do not launch on startup" state. If
  // the kChromeCreatedLoginItem flag is false, we do nothing. Otherwise, we
  // will delete the login item if it's present, and not we will set
  // kUserRemovedLoginItem to true to prevent future login items from being
  // created.
  if (should_launch) {
    PrefService* service = g_browser_process->local_state();
    // If the user removed the login item, don't ever create another one.
    if (service->GetBoolean(prefs::kUserRemovedLoginItem))
      return;

    if (service->GetBoolean(prefs::kChromeCreatedLoginItem)) {
      DCHECK(service->GetBoolean(prefs::kMigratedLoginItemPref));
      // If we previously created a login item, we don't need to create
      // a new one - just check to see if the user removed it so we don't
      // ever create another one.
      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                              base::Bind(
                                  CheckForUserRemovedLoginItemOnFileThread));
    } else {
      bool need_migration = !service->GetBoolean(
          prefs::kMigratedLoginItemPref);
      service->SetBoolean(prefs::kMigratedLoginItemPref, true);
      BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                              base::Bind(EnableLaunchOnStartupOnFileThread,
                                         need_migration));
    }
  } else {
    PrefService* service = g_browser_process->local_state();
    // If Chrome didn't create any login items, just exit.
    if (!service->GetBoolean(prefs::kChromeCreatedLoginItem))
      return;

    // Clear the pref now that we're removing the login item.
    service->ClearPref(prefs::kChromeCreatedLoginItem);

    // If the user removed our login item, note this so we don't ever create
    // another one.
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(
                                CheckForUserRemovedLoginItemOnFileThread));

    // Call to the File thread to remove the login item since it requires
    // accessing the disk.
    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
                            base::Bind(DisableLaunchOnStartupOnFileThread));
  }
}

void BackgroundModeManager::DisplayAppInstalledNotification(
    const extensions::Extension* extension) {
  // TODO(atwilson): Display a platform-appropriate notification here.
  // http://crbug.com/74970
}

base::string16 BackgroundModeManager::GetPreferencesMenuLabel() {
  return l10n_util::GetStringUTF16(IDS_OPTIONS);
}