// 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/extensions/state_store.h"

#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "extensions/common/extension.h"

namespace {

// Delay, in seconds, before we should open the State Store database. We
// defer it to avoid slowing down startup. See http://crbug.com/161848
const int kInitDelaySeconds = 1;

std::string GetFullKey(const std::string& extension_id,
                       const std::string& key) {
  return extension_id + "." + key;
}

}  // namespace

namespace extensions {

// Helper class to delay tasks until we're ready to start executing them.
class StateStore::DelayedTaskQueue {
 public:
  DelayedTaskQueue() : ready_(false) {}
  ~DelayedTaskQueue() {}

  // Queues up a task for invoking once we're ready. Invokes immediately if
  // we're already ready.
  void InvokeWhenReady(base::Closure task);

  // Marks us ready, and invokes all pending tasks.
  void SetReady();

 private:
  bool ready_;
  std::vector<base::Closure> pending_tasks_;
};

void StateStore::DelayedTaskQueue::InvokeWhenReady(base::Closure task) {
  if (ready_) {
    task.Run();
  } else {
    pending_tasks_.push_back(task);
  }
}

void StateStore::DelayedTaskQueue::SetReady() {
  ready_ = true;

  for (size_t i = 0; i < pending_tasks_.size(); ++i)
    pending_tasks_[i].Run();
  pending_tasks_.clear();
}

StateStore::StateStore(Profile* profile,
                       const base::FilePath& db_path,
                       bool deferred_load)
    : db_path_(db_path), task_queue_(new DelayedTaskQueue()) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
                 content::Source<Profile>(profile));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
                 content::Source<Profile>(profile));

  if (deferred_load) {
    // Don't Init until the first page is loaded or the session restored.
    registrar_.Add(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
                   content::NotificationService::
                       AllBrowserContextsAndSources());
    registrar_.Add(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
                   content::NotificationService::
                       AllBrowserContextsAndSources());
  } else {
    Init();
  }
}

StateStore::StateStore(Profile* profile, scoped_ptr<ValueStore> value_store)
    : store_(value_store.Pass()), task_queue_(new DelayedTaskQueue()) {
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
                 content::Source<Profile>(profile));
  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
                 content::Source<Profile>(profile));

  // This constructor is for testing. No need to delay Init.
  Init();
}

StateStore::~StateStore() {
}

void StateStore::RegisterKey(const std::string& key) {
  registered_keys_.insert(key);
}

void StateStore::GetExtensionValue(const std::string& extension_id,
                                   const std::string& key,
                                   ReadCallback callback) {
  task_queue_->InvokeWhenReady(
      base::Bind(&ValueStoreFrontend::Get, base::Unretained(&store_),
                 GetFullKey(extension_id, key), callback));
}

void StateStore::SetExtensionValue(
    const std::string& extension_id,
    const std::string& key,
    scoped_ptr<base::Value> value) {
  task_queue_->InvokeWhenReady(
      base::Bind(&ValueStoreFrontend::Set, base::Unretained(&store_),
                 GetFullKey(extension_id, key), base::Passed(&value)));
}

void StateStore::RemoveExtensionValue(const std::string& extension_id,
                                      const std::string& key) {
  task_queue_->InvokeWhenReady(
      base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
                 GetFullKey(extension_id, key)));
}

void StateStore::Observe(int type,
                         const content::NotificationSource& source,
                         const content::NotificationDetails& details) {
  switch (type) {
    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
      RemoveKeysForExtension(
          content::Details<const InstalledExtensionInfo>(details)->extension->
              id());
      break;
    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
      RemoveKeysForExtension(
          content::Details<const Extension>(details)->id());
      break;
    case chrome::NOTIFICATION_SESSION_RESTORE_DONE:
    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME:
      registrar_.Remove(this, content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
                        content::NotificationService::AllSources());
      registrar_.Remove(this, chrome::NOTIFICATION_SESSION_RESTORE_DONE,
                        content::NotificationService::AllSources());
      base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
          base::Bind(&StateStore::Init, AsWeakPtr()),
          base::TimeDelta::FromSeconds(kInitDelaySeconds));
      break;
    default:
      NOTREACHED();
      return;
  }
}

void StateStore::Init() {
  if (!db_path_.empty())
    store_.Init(db_path_);
  task_queue_->SetReady();
}

void StateStore::RemoveKeysForExtension(const std::string& extension_id) {
  for (std::set<std::string>::iterator key = registered_keys_.begin();
       key != registered_keys_.end(); ++key) {
    task_queue_->InvokeWhenReady(
        base::Bind(&ValueStoreFrontend::Remove, base::Unretained(&store_),
                   GetFullKey(extension_id, *key)));
  }
}

}  // namespace extensions
