// 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.
#include "chrome/browser/chromeos/contacts/contact_manager.h"
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/contacts/contact.pb.h"
#include "chrome/browser/chromeos/contacts/contact_manager_observer.h"
#include "chrome/browser/chromeos/contacts/contact_store.h"
#include "chrome/browser/chromeos/contacts/google_contact_store.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
using content::BrowserThread;
namespace contacts {
namespace {
// Singleton instance.
ContactManager* g_instance = NULL;
} // namespace
// static
ContactManager* ContactManager::GetInstance() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(g_instance);
return g_instance;
}
ContactManager::ContactManager()
: profile_observers_deleter_(&profile_observers_),
contact_store_factory_(new GoogleContactStoreFactory),
contact_stores_deleter_(&contact_stores_),
weak_ptr_factory_(this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!g_instance);
g_instance = this;
}
ContactManager::~ContactManager() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(g_instance, this);
weak_ptr_factory_.InvalidateWeakPtrs();
g_instance = NULL;
for (ContactStoreMap::const_iterator it = contact_stores_.begin();
it != contact_stores_.end(); ++it) {
it->second->RemoveObserver(this);
}
}
void ContactManager::SetContactStoreForTesting(
scoped_ptr<ContactStoreFactory> factory) {
DCHECK(contact_stores_.empty());
contact_store_factory_.swap(factory);
}
void ContactManager::Init() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
registrar_.Add(
this,
chrome::NOTIFICATION_PROFILE_CREATED,
content::NotificationService::AllSources());
registrar_.Add(
this,
chrome::NOTIFICATION_PROFILE_DESTROYED,
content::NotificationService::AllSources());
// Notify about any already-existing profiles.
std::vector<Profile*> profiles(
g_browser_process->profile_manager()->GetLoadedProfiles());
for (size_t i = 0; i < profiles.size(); ++i)
HandleProfileCreated(profiles[i]);
}
base::WeakPtr<ContactManagerInterface> ContactManager::GetWeakPtr() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
return weak_ptr_factory_.GetWeakPtr();
}
void ContactManager::AddObserver(ContactManagerObserver* observer,
Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(observer);
DCHECK(profile);
Observers* observers = GetObserversForProfile(profile, true);
observers->AddObserver(observer);
}
void ContactManager::RemoveObserver(ContactManagerObserver* observer,
Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(observer);
DCHECK(profile);
Observers* observers = GetObserversForProfile(profile, false);
if (observers)
observers->RemoveObserver(observer);
}
scoped_ptr<ContactPointers> ContactManager::GetAllContacts(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile);
scoped_ptr<ContactPointers> contacts(new ContactPointers);
ContactStoreMap::const_iterator it = contact_stores_.find(profile);
if (it != contact_stores_.end())
it->second->AppendContacts(contacts.get());
return contacts.Pass();
}
const Contact* ContactManager::GetContactById(Profile* profile,
const std::string& contact_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile);
ContactStoreMap::const_iterator it = contact_stores_.find(profile);
return it != contact_stores_.end() ?
it->second->GetContactById(contact_id) :
NULL;
}
void ContactManager::OnContactsUpdated(ContactStore* store) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
for (ContactStoreMap::const_iterator it = contact_stores_.begin();
it != contact_stores_.end(); ++it) {
if (it->second == store) {
Profile* profile = it->first;
Observers* observers = GetObserversForProfile(profile, false);
if (observers) {
FOR_EACH_OBSERVER(ContactManagerObserver,
*observers,
OnContactsUpdated(profile));
}
return;
}
}
NOTREACHED() << "Got update from unknown contact store " << store;
}
void ContactManager::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
switch (type) {
case chrome::NOTIFICATION_PROFILE_CREATED:
HandleProfileCreated(content::Source<Profile>(source).ptr());
break;
case chrome::NOTIFICATION_PROFILE_DESTROYED: {
Profile* profile = content::Details<Profile>(details).ptr();
if (profile)
HandleProfileDestroyed(profile);
break;
}
default:
NOTREACHED() << "Unexpected notification " << type;
}
}
ContactManager::Observers* ContactManager::GetObserversForProfile(
Profile* profile,
bool create) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ProfileObserversMap::const_iterator it = profile_observers_.find(profile);
if (it != profile_observers_.end())
return it->second;
if (!create)
return NULL;
Observers* observers = new Observers;
profile_observers_[profile] = observers;
return observers;
}
void ContactManager::HandleProfileCreated(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile);
ContactStoreMap::iterator it = contact_stores_.find(profile);
if (it != contact_stores_.end())
return;
if (!contact_store_factory_->CanCreateContactStoreForProfile(profile))
return;
VLOG(1) << "Adding profile " << profile->GetProfileName();
ContactStore* store = contact_store_factory_->CreateContactStore(profile);
DCHECK(store);
store->AddObserver(this);
store->Init();
DCHECK_EQ(contact_stores_.count(profile), static_cast<size_t>(0));
contact_stores_[profile] = store;
}
void ContactManager::HandleProfileDestroyed(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile);
ContactStoreMap::iterator store_it = contact_stores_.find(profile);
if (store_it != contact_stores_.end()) {
store_it->second->RemoveObserver(this);
delete store_it->second;
contact_stores_.erase(store_it);
}
ProfileObserversMap::iterator observer_it = profile_observers_.find(profile);
if (observer_it != profile_observers_.end()) {
delete observer_it->second;
profile_observers_.erase(observer_it);
}
}
} // namespace contacts