// 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/ui/browser_window_state.h"

#include <stddef.h>

#include "base/command_line.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/defaults.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_service.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/window_sizer/window_sizer.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"

namespace chrome {
namespace {

// Parse two comma-separated integers from str. Return true on success.
bool ParseCommaSeparatedIntegers(const std::string& str,
                                 int* ret_num1,
                                 int* ret_num2) {
  size_t num1_size = str.find_first_of(',');
  if (num1_size == std::string::npos)
    return false;

  size_t num2_pos = num1_size + 1;
  size_t num2_size = str.size() - num2_pos;
  int num1 = 0;
  int num2 = 0;
  if (!base::StringToInt(str.substr(0, num1_size), &num1) ||
      !base::StringToInt(str.substr(num2_pos, num2_size), &num2))
    return false;

  *ret_num1 = num1;
  *ret_num2 = num2;
  return true;
}

class WindowPlacementPrefUpdate : public DictionaryPrefUpdate {
 public:
  WindowPlacementPrefUpdate(PrefService* service,
                            const std::string& window_name)
      : DictionaryPrefUpdate(service, prefs::kAppWindowPlacement),
        window_name_(window_name) {}

  ~WindowPlacementPrefUpdate() override {}

  base::DictionaryValue* Get() override {
    base::DictionaryValue* all_apps_dict = DictionaryPrefUpdate::Get();
    base::DictionaryValue* this_app_dict = NULL;
    if (!all_apps_dict->GetDictionary(window_name_, &this_app_dict)) {
      this_app_dict = new base::DictionaryValue;
      all_apps_dict->Set(window_name_, this_app_dict);
    }
    return this_app_dict;
  }

 private:
  const std::string window_name_;

  DISALLOW_COPY_AND_ASSIGN(WindowPlacementPrefUpdate);
};

}  // namespace

std::string GetWindowName(const Browser* browser) {
  if (browser->app_name().empty()) {
    return browser->is_type_popup() ?
        prefs::kBrowserWindowPlacementPopup : prefs::kBrowserWindowPlacement;
  }
  return browser->app_name();
}

scoped_ptr<DictionaryPrefUpdate> GetWindowPlacementDictionaryReadWrite(
    const std::string& window_name,
    PrefService* prefs) {
  DCHECK(!window_name.empty());
  // A normal DictionaryPrefUpdate will suffice for non-app windows.
  if (prefs->FindPreference(window_name.c_str())) {
    return make_scoped_ptr(
        new DictionaryPrefUpdate(prefs, window_name.c_str()));
  }
  return scoped_ptr<DictionaryPrefUpdate>(
      new WindowPlacementPrefUpdate(prefs, window_name));
}

const base::DictionaryValue* GetWindowPlacementDictionaryReadOnly(
    const std::string& window_name,
    PrefService* prefs) {
  DCHECK(!window_name.empty());
  if (prefs->FindPreference(window_name.c_str()))
    return prefs->GetDictionary(window_name.c_str());

  const base::DictionaryValue* app_windows =
      prefs->GetDictionary(prefs::kAppWindowPlacement);
  if (!app_windows)
    return NULL;
  const base::DictionaryValue* to_return = NULL;
  app_windows->GetDictionary(window_name, &to_return);
  return to_return;
}

bool ShouldSaveWindowPlacement(const Browser* browser) {
  // Only save the window placement of popups if the window is from a trusted
  // source (v1 app, devtools, or system window).
  return (browser->type() == Browser::TYPE_TABBED) ||
    ((browser->type() == Browser::TYPE_POPUP) && browser->is_trusted_source());
}

bool SavedBoundsAreContentBounds(const Browser* browser) {
  // Pop ups such as devtools or bookmark app windows should behave as per other
  // windows with persisted sizes - treating the saved bounds as window bounds.
  return browser->is_type_popup() && !browser->is_app() &&
         !browser->is_trusted_source();
}

void SaveWindowPlacement(const Browser* browser,
                         const gfx::Rect& bounds,
                         ui::WindowShowState show_state) {
  // Save to the session storage service, used when reloading a past session.
  // Note that we don't want to be the ones who cause lazy initialization of
  // the session service. This function gets called during initial window
  // showing, and we don't want to bring in the session service this early.
  SessionService* session_service =
      SessionServiceFactory::GetForProfileIfExisting(browser->profile());
  if (session_service)
    session_service->SetWindowBounds(browser->session_id(), bounds, show_state);
}

void GetSavedWindowBoundsAndShowState(const Browser* browser,
                                      gfx::Rect* bounds,
                                      ui::WindowShowState* show_state) {
  DCHECK(browser);
  DCHECK(bounds);
  DCHECK(show_state);
  *bounds = browser->override_bounds();
  WindowSizer::GetBrowserWindowBoundsAndShowState(browser->app_name(),
                                                  *bounds,
                                                  browser,
                                                  bounds,
                                                  show_state);

  const base::CommandLine& parsed_command_line =
      *base::CommandLine::ForCurrentProcess();

  if (parsed_command_line.HasSwitch(switches::kWindowSize)) {
    std::string str =
        parsed_command_line.GetSwitchValueASCII(switches::kWindowSize);
    int width, height;
    if (ParseCommaSeparatedIntegers(str, &width, &height))
      bounds->set_size(gfx::Size(width, height));
  }
  if (parsed_command_line.HasSwitch(switches::kWindowPosition)) {
    std::string str =
        parsed_command_line.GetSwitchValueASCII(switches::kWindowPosition);
    int x, y;
    if (ParseCommaSeparatedIntegers(str, &x, &y))
      bounds->set_origin(gfx::Point(x, y));
  }
}

}  // namespace chrome
