// Copyright 2014 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 "apps/app_window_geometry_cache.h"

#include "base/bind.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/extension.h"

namespace {

// The timeout in milliseconds before we'll persist window geometry to the
// StateStore.
const int kSyncTimeoutMilliseconds = 1000;

}  // namespace

namespace apps {

AppWindowGeometryCache::AppWindowGeometryCache(
    content::BrowserContext* context,
    extensions::ExtensionPrefs* prefs)
    : prefs_(prefs),
      sync_delay_(base::TimeDelta::FromMilliseconds(kSyncTimeoutMilliseconds)),
      extension_registry_observer_(this) {
  extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(context));
}

AppWindowGeometryCache::~AppWindowGeometryCache() {}

// static
AppWindowGeometryCache* AppWindowGeometryCache::Get(
    content::BrowserContext* context) {
  return Factory::GetForContext(context, true /* create */);
}

void AppWindowGeometryCache::SaveGeometry(const std::string& extension_id,
                                          const std::string& window_id,
                                          const gfx::Rect& bounds,
                                          const gfx::Rect& screen_bounds,
                                          ui::WindowShowState window_state) {
  ExtensionData& extension_data = cache_[extension_id];

  // If we don't have any unsynced changes and this is a duplicate of what's
  // already in the cache, just ignore it.
  if (extension_data[window_id].bounds == bounds &&
      extension_data[window_id].window_state == window_state &&
      extension_data[window_id].screen_bounds == screen_bounds &&
      !ContainsKey(unsynced_extensions_, extension_id))
    return;

  base::Time now = base::Time::Now();

  extension_data[window_id].bounds = bounds;
  extension_data[window_id].screen_bounds = screen_bounds;
  extension_data[window_id].window_state = window_state;
  extension_data[window_id].last_change = now;

  if (extension_data.size() > kMaxCachedWindows) {
    ExtensionData::iterator oldest = extension_data.end();
    // Too many windows in the cache, find the oldest one to remove.
    for (ExtensionData::iterator it = extension_data.begin();
         it != extension_data.end();
         ++it) {
      // Don't expunge the window that was just added.
      if (it->first == window_id)
        continue;

      // If time is in the future, reset it to now to minimize weirdness.
      if (it->second.last_change > now)
        it->second.last_change = now;

      if (oldest == extension_data.end() ||
          it->second.last_change < oldest->second.last_change)
        oldest = it;
    }
    extension_data.erase(oldest);
  }

  unsynced_extensions_.insert(extension_id);

  // We don't use Reset() because the timer may not yet be running.
  // (In that case Stop() is a no-op.)
  sync_timer_.Stop();
  sync_timer_.Start(
      FROM_HERE, sync_delay_, this, &AppWindowGeometryCache::SyncToStorage);
}

void AppWindowGeometryCache::SyncToStorage() {
  std::set<std::string> tosync;
  tosync.swap(unsynced_extensions_);
  for (std::set<std::string>::const_iterator it = tosync.begin(),
                                             eit = tosync.end();
       it != eit;
       ++it) {
    const std::string& extension_id = *it;
    const ExtensionData& extension_data = cache_[extension_id];

    scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
    for (ExtensionData::const_iterator it = extension_data.begin(),
                                       eit = extension_data.end();
         it != eit;
         ++it) {
      base::DictionaryValue* value = new base::DictionaryValue;
      const gfx::Rect& bounds = it->second.bounds;
      const gfx::Rect& screen_bounds = it->second.screen_bounds;
      DCHECK(!bounds.IsEmpty());
      DCHECK(!screen_bounds.IsEmpty());
      DCHECK(it->second.window_state != ui::SHOW_STATE_DEFAULT);
      value->SetInteger("x", bounds.x());
      value->SetInteger("y", bounds.y());
      value->SetInteger("w", bounds.width());
      value->SetInteger("h", bounds.height());
      value->SetInteger("screen_bounds_x", screen_bounds.x());
      value->SetInteger("screen_bounds_y", screen_bounds.y());
      value->SetInteger("screen_bounds_w", screen_bounds.width());
      value->SetInteger("screen_bounds_h", screen_bounds.height());
      value->SetInteger("state", it->second.window_state);
      value->SetString(
          "ts", base::Int64ToString(it->second.last_change.ToInternalValue()));
      dict->SetWithoutPathExpansion(it->first, value);

      FOR_EACH_OBSERVER(
          Observer,
          observers_,
          OnGeometryCacheChanged(extension_id, it->first, bounds));
    }

    prefs_->SetGeometryCache(extension_id, dict.Pass());
  }
}

bool AppWindowGeometryCache::GetGeometry(const std::string& extension_id,
                                         const std::string& window_id,
                                         gfx::Rect* bounds,
                                         gfx::Rect* screen_bounds,
                                         ui::WindowShowState* window_state) {
  std::map<std::string, ExtensionData>::const_iterator extension_data_it =
      cache_.find(extension_id);

  // Not in the map means loading data for the extension didn't finish yet or
  // the cache was not constructed until after the extension was loaded.
  // Attempt to load from sync to address the latter case.
  if (extension_data_it == cache_.end()) {
    LoadGeometryFromStorage(extension_id);
    extension_data_it = cache_.find(extension_id);
    DCHECK(extension_data_it != cache_.end());
  }

  ExtensionData::const_iterator window_data_it =
      extension_data_it->second.find(window_id);

  if (window_data_it == extension_data_it->second.end())
    return false;

  const WindowData& window_data = window_data_it->second;

  // Check for and do not return corrupt data.
  if ((bounds && window_data.bounds.IsEmpty()) ||
      (screen_bounds && window_data.screen_bounds.IsEmpty()) ||
      (window_state && window_data.window_state == ui::SHOW_STATE_DEFAULT))
    return false;

  if (bounds)
    *bounds = window_data.bounds;
  if (screen_bounds)
    *screen_bounds = window_data.screen_bounds;
  if (window_state)
    *window_state = window_data.window_state;
  return true;
}

void AppWindowGeometryCache::Shutdown() { SyncToStorage(); }

AppWindowGeometryCache::WindowData::WindowData()
    : window_state(ui::SHOW_STATE_DEFAULT) {}

AppWindowGeometryCache::WindowData::~WindowData() {}

void AppWindowGeometryCache::OnExtensionLoaded(
    content::BrowserContext* browser_context,
    const extensions::Extension* extension) {
  LoadGeometryFromStorage(extension->id());
}

void AppWindowGeometryCache::OnExtensionUnloaded(
    content::BrowserContext* browser_context,
    const extensions::Extension* extension,
    extensions::UnloadedExtensionInfo::Reason reason) {
  SyncToStorage();
  cache_.erase(extension->id());
}

void AppWindowGeometryCache::SetSyncDelayForTests(int timeout_ms) {
  sync_delay_ = base::TimeDelta::FromMilliseconds(timeout_ms);
}

void AppWindowGeometryCache::LoadGeometryFromStorage(
    const std::string& extension_id) {
  ExtensionData& extension_data = cache_[extension_id];

  const base::DictionaryValue* stored_windows =
      prefs_->GetGeometryCache(extension_id);
  if (!stored_windows)
    return;

  for (base::DictionaryValue::Iterator it(*stored_windows); !it.IsAtEnd();
       it.Advance()) {
    // If the cache already contains geometry for this window, don't
    // overwrite that information since it is probably the result of an
    // application starting up very quickly.
    const std::string& window_id = it.key();
    ExtensionData::iterator cached_window = extension_data.find(window_id);
    if (cached_window == extension_data.end()) {
      const base::DictionaryValue* stored_window;
      if (it.value().GetAsDictionary(&stored_window)) {
        WindowData& window_data = extension_data[it.key()];

        int i;
        if (stored_window->GetInteger("x", &i))
          window_data.bounds.set_x(i);
        if (stored_window->GetInteger("y", &i))
          window_data.bounds.set_y(i);
        if (stored_window->GetInteger("w", &i))
          window_data.bounds.set_width(i);
        if (stored_window->GetInteger("h", &i))
          window_data.bounds.set_height(i);
        if (stored_window->GetInteger("screen_bounds_x", &i))
          window_data.screen_bounds.set_x(i);
        if (stored_window->GetInteger("screen_bounds_y", &i))
          window_data.screen_bounds.set_y(i);
        if (stored_window->GetInteger("screen_bounds_w", &i))
          window_data.screen_bounds.set_width(i);
        if (stored_window->GetInteger("screen_bounds_h", &i))
          window_data.screen_bounds.set_height(i);
        if (stored_window->GetInteger("state", &i)) {
          window_data.window_state = static_cast<ui::WindowShowState>(i);
        }
        std::string ts_as_string;
        if (stored_window->GetString("ts", &ts_as_string)) {
          int64 ts;
          if (base::StringToInt64(ts_as_string, &ts)) {
            window_data.last_change = base::Time::FromInternalValue(ts);
          }
        }
      }
    }
  }
}

///////////////////////////////////////////////////////////////////////////////
// Factory boilerplate

// static
AppWindowGeometryCache* AppWindowGeometryCache::Factory::GetForContext(
    content::BrowserContext* context,
    bool create) {
  return static_cast<AppWindowGeometryCache*>(
      GetInstance()->GetServiceForBrowserContext(context, create));
}

AppWindowGeometryCache::Factory*
AppWindowGeometryCache::Factory::GetInstance() {
  return Singleton<AppWindowGeometryCache::Factory>::get();
}

AppWindowGeometryCache::Factory::Factory()
    : BrowserContextKeyedServiceFactory(
          "AppWindowGeometryCache",
          BrowserContextDependencyManager::GetInstance()) {
  DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
}

AppWindowGeometryCache::Factory::~Factory() {}

KeyedService* AppWindowGeometryCache::Factory::BuildServiceInstanceFor(
    content::BrowserContext* context) const {
  return new AppWindowGeometryCache(context,
                                    extensions::ExtensionPrefs::Get(context));
}

bool AppWindowGeometryCache::Factory::ServiceIsNULLWhileTesting() const {
  return false;
}

content::BrowserContext*
AppWindowGeometryCache::Factory::GetBrowserContextToUse(
    content::BrowserContext* context) const {
  return extensions::ExtensionsBrowserClient::Get()->GetOriginalContext(
      context);
}

void AppWindowGeometryCache::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void AppWindowGeometryCache::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

}  // namespace apps
