// 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 <set>

#include "chrome/browser/profiles/profile_manager.h"

#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/default_apps_trial.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_metrics.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/webui/sync_promo/sync_promo_ui.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/user_metrics.h"
#include "grit/generated_resources.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_job.h"
#include "ui/base/l10n/l10n_util.h"

#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#endif

using content::BrowserThread;
using content::UserMetricsAction;

namespace {

// Profiles that should be deleted on shutdown.
std::vector<FilePath>& ProfilesToDelete() {
  CR_DEFINE_STATIC_LOCAL(std::vector<FilePath>, profiles_to_delete, ());
  return profiles_to_delete;
}

// Checks if any user prefs for |profile| have default values.
bool HasAnyDefaultUserPrefs(Profile* profile) {
  const PrefService::Preference* avatar_index =
      profile->GetPrefs()->FindPreference(prefs::kProfileAvatarIndex);
  DCHECK(avatar_index);
  const PrefService::Preference* profile_name =
    profile->GetPrefs()->FindPreference(prefs::kProfileName);
  DCHECK(profile_name);
  return avatar_index->IsDefaultValue() ||
         profile_name->IsDefaultValue();
}

// Simple task to log the size of the current profile.
void ProfileSizeTask(const FilePath& path, int extension_count) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));

  int64 size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("*"));
  int size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.TotalSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("History"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.HistorySize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("History*"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.TotalHistorySize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Cookies"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.CookiesSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Bookmarks"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.BookmarksSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Favicons"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.FaviconsSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Top Sites"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.TopSitesSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Visited Links"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.VisitedLinksSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Web Data"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.WebDataSize", size_MB);

  size = file_util::ComputeFilesSize(path, FILE_PATH_LITERAL("Extension*"));
  size_MB = static_cast<int>(size  / (1024 * 1024));
  UMA_HISTOGRAM_COUNTS_10000("Profile.ExtensionSize", size_MB);

  // Count number of extensions in this profile, if we know.
  if (extension_count != -1) {
    UMA_HISTOGRAM_COUNTS_10000("Profile.AppCount", extension_count);

    static bool default_apps_trial_exists = base::FieldTrialList::TrialExists(
        kDefaultAppsTrialName);
    if (default_apps_trial_exists) {
      UMA_HISTOGRAM_COUNTS_10000(
          base::FieldTrial::MakeName("Profile.AppCount",
                                     kDefaultAppsTrialName),
          extension_count);
    }
  }
}

void QueueProfileDirectoryForDeletion(const FilePath& path) {
  ProfilesToDelete().push_back(path);
}

// Called upon completion of profile creation. This function takes care of
// launching a new browser window and signing the user in to their Google
// account.
void OnOpenWindowForNewProfile(Profile* profile,
                               Profile::CreateStatus status) {
  if (status == Profile::CREATE_STATUS_INITIALIZED) {
    ProfileManager::NewWindowWithProfile(profile,
                                         BrowserInit::IS_PROCESS_STARTUP,
                                         BrowserInit::IS_FIRST_RUN);
  }
}

} // namespace

// static
void ProfileManager::ShutdownSessionServices() {
  ProfileManager* pm = g_browser_process->profile_manager();
  if (!pm)  // Is NULL when running unit tests.
    return;
  std::vector<Profile*> profiles(pm->GetLoadedProfiles());
  for (size_t i = 0; i < profiles.size(); ++i)
    SessionServiceFactory::ShutdownForProfile(profiles[i]);
}

// static
void ProfileManager::NukeDeletedProfilesFromDisk() {
  for (std::vector<FilePath>::iterator it =
          ProfilesToDelete().begin();
       it != ProfilesToDelete().end();
       ++it) {
    file_util::Delete(*it, true);
  }
  ProfilesToDelete().clear();
}

// static
Profile* ProfileManager::GetDefaultProfile() {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetDefaultProfile(profile_manager->user_data_dir_);
}

// static
Profile* ProfileManager::GetLastUsedProfile() {
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  return profile_manager->GetLastUsedProfile(profile_manager->user_data_dir_);
}

ProfileManager::ProfileManager(const FilePath& user_data_dir)
    : user_data_dir_(user_data_dir),
      logged_in_(false),
      will_import_(false) {
  BrowserList::AddObserver(this);
#if defined(OS_CHROMEOS)
  registrar_.Add(
      this,
      chrome::NOTIFICATION_LOGIN_USER_CHANGED,
      content::NotificationService::AllSources());
#endif
}

ProfileManager::~ProfileManager() {
  BrowserList::RemoveObserver(this);
#if defined(OS_WIN)
  if (profile_shortcut_manager_.get())
    profile_info_cache_->RemoveObserver(profile_shortcut_manager_.get());
#endif
}

FilePath ProfileManager::GetDefaultProfileDir(
    const FilePath& user_data_dir) {
  FilePath default_profile_dir(user_data_dir);
  default_profile_dir =
      default_profile_dir.AppendASCII(chrome::kInitialProfile);
  return default_profile_dir;
}

FilePath ProfileManager::GetProfilePrefsPath(
    const FilePath &profile_dir) {
  FilePath default_prefs_path(profile_dir);
  default_prefs_path = default_prefs_path.Append(chrome::kPreferencesFilename);
  return default_prefs_path;
}

FilePath ProfileManager::GetInitialProfileDir() {
  FilePath relative_profile_dir;
#if defined(OS_CHROMEOS)
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (logged_in_) {
    FilePath profile_dir;
    // If the user has logged in, pick up the new profile.
    if (command_line.HasSwitch(switches::kLoginProfile)) {
      profile_dir = command_line.GetSwitchValuePath(switches::kLoginProfile);
    } else {
      // We should never be logged in with no profile dir.
      NOTREACHED();
      return FilePath("");
    }
    relative_profile_dir = relative_profile_dir.Append(profile_dir);
    return relative_profile_dir;
  }
#endif
  // TODO(mirandac): should not automatically be default profile.
  relative_profile_dir =
      relative_profile_dir.AppendASCII(chrome::kInitialProfile);
  return relative_profile_dir;
}

Profile* ProfileManager::GetLastUsedProfile(const FilePath& user_data_dir) {
  FilePath last_used_profile_dir(user_data_dir);
  std::string last_profile_used;
  PrefService* local_state = g_browser_process->local_state();
  DCHECK(local_state);

  if (local_state->HasPrefPath(prefs::kProfileLastUsed))
    last_profile_used = local_state->GetString(prefs::kProfileLastUsed);
  last_used_profile_dir = last_profile_used.empty() ?
      last_used_profile_dir.AppendASCII(chrome::kInitialProfile) :
      last_used_profile_dir.AppendASCII(last_profile_used);
  return GetProfile(last_used_profile_dir);
}

Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
  FilePath default_profile_dir(user_data_dir);
  default_profile_dir = default_profile_dir.Append(GetInitialProfileDir());
#if defined(OS_CHROMEOS)
  if (!logged_in_) {
    Profile* profile = GetProfile(default_profile_dir);
    // For cros, return the OTR profile so we never accidentally keep
    // user data in an unencrypted profile. But doing this makes
    // many of the browser and ui tests fail. We do return the OTR profile
    // if the login-profile switch is passed so that we can test this.
    // TODO(davemoore) Fix the tests so they allow OTR profiles.
    if (ShouldGoOffTheRecord())
      return profile->GetOffTheRecordProfile();
    return profile;
  }
#endif
  return GetProfile(default_profile_dir);
}

bool ProfileManager::IsValidProfile(Profile* profile) {
  for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
       iter != profiles_info_.end(); ++iter) {
    if (iter->second->created) {
      Profile* candidate = iter->second->profile.get();
      if (candidate == profile ||
          (candidate->HasOffTheRecordProfile() &&
           candidate->GetOffTheRecordProfile() == profile)) {
        return true;
      }
    }
  }
  return false;
}

std::vector<Profile*> ProfileManager::GetLoadedProfiles() const {
  std::vector<Profile*> profiles;
  for (ProfilesInfoMap::const_iterator iter = profiles_info_.begin();
       iter != profiles_info_.end(); ++iter) {
    if (iter->second->created)
      profiles.push_back(iter->second->profile.get());
  }
  return profiles;
}

Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
  // If the profile is already loaded (e.g., chrome.exe launched twice), just
  // return it.
  Profile* profile = GetProfileByPath(profile_dir);
  if (NULL != profile)
    return profile;

  profile = CreateProfileHelper(profile_dir);
  DCHECK(profile);
  if (profile) {
    bool result = AddProfile(profile);
    DCHECK(result);
  }
  return profile;
}

void ProfileManager::CreateProfileAsync(const FilePath& profile_path,
                                        const CreateCallback& callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  ProfilesInfoMap::iterator iter = profiles_info_.find(profile_path);
  if (iter != profiles_info_.end()) {
    ProfileInfo* info = iter->second.get();
    if (info->created) {
      // Profile has already been created. Run callback immediately.
      callback.Run(info->profile.get(), Profile::CREATE_STATUS_INITIALIZED);
    } else {
      // Profile is being created. Add callback to list.
      info->callbacks.push_back(callback);
    }
  } else {
    // Initiate asynchronous creation process.
    ProfileInfo* info =
        RegisterProfile(CreateProfileAsyncHelper(profile_path, this), false);
    info->callbacks.push_back(callback);
  }
}

// static
void ProfileManager::CreateDefaultProfileAsync(const CreateCallback& callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  ProfileManager* profile_manager = g_browser_process->profile_manager();

  FilePath default_profile_dir = profile_manager->user_data_dir_;
  // TODO(mirandac): current directory will not always be default in the future
  default_profile_dir = default_profile_dir.Append(
      profile_manager->GetInitialProfileDir());

  profile_manager->CreateProfileAsync(default_profile_dir, callback);
}

bool ProfileManager::AddProfile(Profile* profile) {
  DCHECK(profile);

  // Make sure that we're not loading a profile with the same ID as a profile
  // that's already loaded.
  if (GetProfileByPath(profile->GetPath())) {
    NOTREACHED() << "Attempted to add profile with the same path (" <<
                    profile->GetPath().value() <<
                    ") as an already-loaded profile.";
    return false;
  }

  RegisterProfile(profile, true);
  DoFinalInit(profile, ShouldGoOffTheRecord());
  ProfileMetrics::LogNumberOfProfiles(this, ProfileMetrics::ADD_PROFILE_EVENT);
  return true;
}

ProfileManager::ProfileInfo* ProfileManager::RegisterProfile(Profile* profile,
                                                             bool created) {
  ProfileInfo* info = new ProfileInfo(profile, created);
  profiles_info_.insert(std::make_pair(profile->GetPath(), info));
  return info;
}

Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
  ProfilesInfoMap::const_iterator iter = profiles_info_.find(path);
  return (iter == profiles_info_.end()) ? NULL : iter->second->profile.get();
}

// static
void ProfileManager::NewWindowWithProfile(
    Profile* profile,
    BrowserInit::IsProcessStartup process_startup,
    BrowserInit::IsFirstRun is_first_run) {
  DCHECK(profile);
  Browser* browser = BrowserList::FindTabbedBrowser(profile, false);
  if (browser) {
    browser->window()->Activate();
  } else {
    content::RecordAction(UserMetricsAction("NewWindow"));
    CommandLine command_line(CommandLine::NO_PROGRAM);
    int return_code;
    BrowserInit browser_init;
    browser_init.LaunchBrowser(command_line, profile, FilePath(),
                               process_startup, is_first_run, &return_code);
  }
}

void ProfileManager::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
#if defined(OS_CHROMEOS)
  if (type == chrome::NOTIFICATION_LOGIN_USER_CHANGED) {
    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    if (!command_line.HasSwitch(switches::kTestType)) {
      // If we don't have a mounted profile directory we're in trouble.
      // TODO(davemoore) Once we have better api this check should ensure that
      // our profile directory is the one that's mounted, and that it's mounted
      // as the current user.
      CHECK(chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->IsMounted());
    }
    logged_in_ = true;
  }
#endif
}

void ProfileManager::SetWillImport() {
  will_import_ = true;
}

void ProfileManager::OnImportFinished(Profile* profile) {
  will_import_ = false;
  DCHECK(profile);
  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_IMPORT_FINISHED,
      content::Source<Profile>(profile),
      content::NotificationService::NoDetails());
}

void ProfileManager::OnBrowserAdded(const Browser* browser) {}

void ProfileManager::OnBrowserRemoved(const Browser* browser) {}

void ProfileManager::OnBrowserSetLastActive(const Browser* browser) {
  Profile* last_active = browser->GetProfile();
  PrefService* local_state = g_browser_process->local_state();
  DCHECK(local_state);
  // Only keep track of profiles that we are managing; tests may create others.
  if (profiles_info_.find(last_active->GetPath()) != profiles_info_.end()) {
    local_state->SetString(prefs::kProfileLastUsed,
                           last_active->GetPath().BaseName().MaybeAsASCII());
  }
}

void ProfileManager::DoFinalInit(Profile* profile, bool go_off_the_record) {
  DoFinalInitForServices(profile, go_off_the_record);
  InitProfileUserPrefs(profile);
  AddProfileToCache(profile);
  DoFinalInitLogging(profile);
}

void ProfileManager::DoFinalInitForServices(Profile* profile,
                                         bool go_off_the_record) {
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  profile->InitExtensions(!go_off_the_record);
  if (!command_line.HasSwitch(switches::kDisableWebResources))
    profile->InitPromoResources();
}

void ProfileManager::DoFinalInitLogging(Profile* profile) {
  // Count number of extensions in this profile.
  int extension_count = -1;
  ExtensionService* extension_service = profile->GetExtensionService();
  if (extension_service)
    extension_count = extension_service->GetAppIds().size();

  // Log the profile size after a reasonable startup delay.
  BrowserThread::PostDelayedTask(
      BrowserThread::FILE, FROM_HERE,
      base::Bind(&ProfileSizeTask, profile->GetPath(), extension_count),
      112000);
}

Profile* ProfileManager::CreateProfileHelper(const FilePath& path) {
  return Profile::CreateProfile(path);
}

Profile* ProfileManager::CreateProfileAsyncHelper(const FilePath& path,
                                                  Delegate* delegate) {
  return Profile::CreateProfileAsync(path, delegate);
}

void ProfileManager::OnProfileCreated(Profile* profile, bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  ProfilesInfoMap::iterator iter = profiles_info_.find(profile->GetPath());
  DCHECK(iter != profiles_info_.end());
  ProfileInfo* info = iter->second.get();

  std::vector<CreateCallback> callbacks;
  info->callbacks.swap(callbacks);

  // Invoke CREATED callback for normal profiles.
  bool go_off_the_record = ShouldGoOffTheRecord();
  if (success && !go_off_the_record)
    RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED);

  // Perform initialization.
  if (success) {
    DoFinalInit(profile, go_off_the_record);
    if (go_off_the_record)
      profile = profile->GetOffTheRecordProfile();
    info->created = true;
  } else {
    profile = NULL;
    profiles_info_.erase(iter);
  }

  // Invoke CREATED callback for incognito profiles.
  if (profile && go_off_the_record)
    RunCallbacks(callbacks, profile, Profile::CREATE_STATUS_CREATED);

  // Invoke INITIALIZED or FAIL for all profiles.
  RunCallbacks(callbacks, profile,
               profile ? Profile::CREATE_STATUS_INITIALIZED :
                         Profile::CREATE_STATUS_FAIL);
}

FilePath ProfileManager::GenerateNextProfileDirectoryPath() {
  PrefService* local_state = g_browser_process->local_state();
  DCHECK(local_state);

  // Create the next profile in the next available directory slot.
  int next_directory = local_state->GetInteger(prefs::kProfilesNumCreated);
  std::string profile_name = chrome::kMultiProfileDirPrefix;
  profile_name.append(base::IntToString(next_directory));
  FilePath new_path = user_data_dir_;
#if defined(OS_WIN)
  new_path = new_path.Append(ASCIIToUTF16(profile_name));
#else
  new_path = new_path.Append(profile_name);
#endif
  local_state->SetInteger(prefs::kProfilesNumCreated, ++next_directory);
  return new_path;
}

// static
void ProfileManager::CreateMultiProfileAsync() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  ProfileManager* profile_manager = g_browser_process->profile_manager();

  FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath();

  profile_manager->CreateProfileAsync(new_path,
                                      base::Bind(&OnOpenWindowForNewProfile));
}

// static
void ProfileManager::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterStringPref(prefs::kProfileLastUsed, "");
  prefs->RegisterIntegerPref(prefs::kProfilesNumCreated, 1);
}

size_t ProfileManager::GetNumberOfProfiles() {
  return GetProfileInfoCache().GetNumberOfProfiles();
}

bool ProfileManager::CompareProfilePathAndName(
    const ProfileManager::ProfilePathAndName& pair1,
    const ProfileManager::ProfilePathAndName& pair2) {
  int name_compare = pair1.second.compare(pair2.second);
  if (name_compare < 0) {
    return true;
  } else if (name_compare > 0) {
    return false;
  } else {
    return pair1.first < pair2.first;
  }
}

ProfileInfoCache& ProfileManager::GetProfileInfoCache() {
  if (!profile_info_cache_.get()) {
    profile_info_cache_.reset(new ProfileInfoCache(
        g_browser_process->local_state(), user_data_dir_));
#if defined(OS_WIN)
    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
    if (!command_line.HasSwitch(switches::kNoFirstRun)) {
      profile_shortcut_manager_.reset(new ProfileShortcutManagerWin());
      profile_info_cache_->AddObserver(profile_shortcut_manager_.get());
    }
#endif
  }
  return *profile_info_cache_.get();
}

void ProfileManager::AddProfileToCache(Profile* profile) {
  ProfileInfoCache& cache = GetProfileInfoCache();
  if (profile->GetPath().DirName() != cache.GetUserDataDir())
    return;

  if (cache.GetIndexOfProfileWithPath(profile->GetPath()) != std::string::npos)
    return;

  string16 username = UTF8ToUTF16(profile->GetPrefs()->GetString(
      prefs::kGoogleServicesUsername));

  // Profile name and avatar are set by InitProfileUserPrefs and stored in the
  // profile. Use those values to setup the cache entry.
  string16 profile_name = UTF8ToUTF16(profile->GetPrefs()->GetString(
      prefs::kProfileName));

  size_t icon_index = profile->GetPrefs()->GetInteger(
      prefs::kProfileAvatarIndex);

  cache.AddProfileToCache(profile->GetPath(),
                          profile_name,
                          username,
                          icon_index);
}

void ProfileManager::InitProfileUserPrefs(Profile* profile) {
  ProfileInfoCache& cache = GetProfileInfoCache();

  if (profile->GetPath().DirName() != cache.GetUserDataDir())
    return;

  // Initialize the user preferences (name and avatar) only if the profile
  // doesn't have default preferenc values for them.
  if (HasAnyDefaultUserPrefs(profile)) {
    size_t profile_cache_index =
        cache.GetIndexOfProfileWithPath(profile->GetPath());
    // If the cache has an entry for this profile, use the cache data
    if (profile_cache_index != std::string::npos) {
      profile->GetPrefs()->SetInteger(prefs::kProfileAvatarIndex,
          cache.GetAvatarIconIndexOfProfileAtIndex(profile_cache_index));
      profile->GetPrefs()->SetString(prefs::kProfileName,
          UTF16ToUTF8(cache.GetNameOfProfileAtIndex(profile_cache_index)));
    } else if (profile->GetPath() ==
               GetDefaultProfileDir(cache.GetUserDataDir())) {
      profile->GetPrefs()->SetInteger(prefs::kProfileAvatarIndex, 0);
      profile->GetPrefs()->SetString(prefs::kProfileName,
          l10n_util::GetStringUTF8(IDS_DEFAULT_PROFILE_NAME));
    } else {
      size_t icon_index = cache.ChooseAvatarIconIndexForNewProfile();
      profile->GetPrefs()->SetInteger(prefs::kProfileAvatarIndex, icon_index);
      profile->GetPrefs()->SetString(
          prefs::kProfileName,
          UTF16ToUTF8(cache.ChooseNameForNewProfile(icon_index)));
    }
  }
}

bool ProfileManager::ShouldGoOffTheRecord() {
  bool go_off_the_record = false;
#if defined(OS_CHROMEOS)
  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
  if (!logged_in_ &&
      (!command_line.HasSwitch(switches::kTestType) ||
       command_line.HasSwitch(switches::kLoginProfile))) {
    go_off_the_record = true;
  }
#endif
  return go_off_the_record;
}

void ProfileManager::ScheduleProfileForDeletion(const FilePath& profile_dir) {
  // If we're deleting the last profile, then create a new profile in its
  // place.
  ProfileInfoCache& cache = GetProfileInfoCache();
  if (cache.GetNumberOfProfiles() == 1) {
    FilePath new_path = GenerateNextProfileDirectoryPath();

    CreateProfileAsync(new_path, base::Bind(&OnOpenWindowForNewProfile));
  }

  // Update the last used profile pref before closing browser windows. This way
  // the correct last used profile is set for any notification observers.
  PrefService* local_state = g_browser_process->local_state();
  std::string last_profile = local_state->GetString(prefs::kProfileLastUsed);
  if (profile_dir.BaseName().MaybeAsASCII() == last_profile) {
    for (size_t i = 0; i < cache.GetNumberOfProfiles(); ++i) {
      FilePath cur_path = cache.GetPathOfProfileAtIndex(i);
      if (cur_path != profile_dir) {
        local_state->SetString(
            prefs::kProfileLastUsed, cur_path.BaseName().MaybeAsASCII());
        break;
      }
    }
  }

  // TODO(sail): Due to bug 88586 we don't delete the profile instance. Once we
  // start deleting the profile instance we need to close background apps too.
  Profile* profile = GetProfileByPath(profile_dir);
  if (profile) {
    BrowserList::CloseAllBrowsersWithProfile(profile);

    // Disable sync for doomed profile.
    if (profile->HasProfileSyncService())
      profile->GetProfileSyncService()->DisableForUser();
  }

  QueueProfileDirectoryForDeletion(profile_dir);
  cache.DeleteProfileFromCache(profile_dir);

  ProfileMetrics::LogNumberOfProfiles(this,
                                      ProfileMetrics::DELETE_PROFILE_EVENT);
}

// static
bool ProfileManager::IsMultipleProfilesEnabled() {
#if defined(OS_CHROMEOS)
  return CommandLine::ForCurrentProcess()->HasSwitch(switches::kMultiProfiles);
#else
  return true;
#endif
}

void ProfileManager::AutoloadProfiles() {
  ProfileInfoCache& cache = GetProfileInfoCache();
  size_t number_of_profiles = cache.GetNumberOfProfiles();
  for (size_t p = 0; p < number_of_profiles; ++p) {
    if (cache.GetBackgroundStatusOfProfileAtIndex(p)) {
      // If status is true, that profile is running background apps. By calling
      // GetProfile, we automatically cause the profile to be loaded which will
      // register it with the BackgroundModeManager.
      GetProfile(cache.GetPathOfProfileAtIndex(p));
    }
  }
  ProfileMetrics::LogNumberOfProfiles(this,
                                      ProfileMetrics::STARTUP_PROFILE_EVENT);
}

ProfileManagerWithoutInit::ProfileManagerWithoutInit(
    const FilePath& user_data_dir) : ProfileManager(user_data_dir) {
}

void ProfileManager::RegisterTestingProfile(Profile* profile,
                                            bool add_to_cache) {
  RegisterProfile(profile, true);
  if (add_to_cache){
    InitProfileUserPrefs(profile);
    AddProfileToCache(profile);
  }
}

#if defined(OS_WIN)
void ProfileManager::RemoveProfileShortcutManagerForTesting() {
  profile_info_cache_->RemoveObserver(profile_shortcut_manager_.get());
}
#endif

void ProfileManager::RunCallbacks(const std::vector<CreateCallback>& callbacks,
                                  Profile* profile,
                                  Profile::CreateStatus status) {
  for (size_t i = 0; i < callbacks.size(); ++i)
    callbacks[i].Run(profile, status);
}