// Copyright 2015 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/webui/settings/settings_startup_pages_handler.h"

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "chrome/browser/prefs/session_startup_pref.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/settings_utils.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/web_ui.h"
#include "url/gurl.h"

namespace settings {

StartupPagesHandler::StartupPagesHandler(content::WebUI* webui)
    : startup_custom_pages_table_model_(Profile::FromWebUI(webui)) {
}

StartupPagesHandler::~StartupPagesHandler() {
}

void StartupPagesHandler::RegisterMessages() {
  if (Profile::FromWebUI(web_ui())->IsOffTheRecord())
    return;

  web_ui()->RegisterMessageCallback(
      "addStartupPage",
      base::BindRepeating(&StartupPagesHandler::HandleAddStartupPage,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "editStartupPage",
      base::BindRepeating(&StartupPagesHandler::HandleEditStartupPage,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "onStartupPrefsPageLoad",
      base::BindRepeating(&StartupPagesHandler::HandleOnStartupPrefsPageLoad,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "removeStartupPage",
      base::BindRepeating(&StartupPagesHandler::HandleRemoveStartupPage,
                          base::Unretained(this)));
  web_ui()->RegisterMessageCallback(
      "setStartupPagesToCurrentPages",
      base::BindRepeating(
          &StartupPagesHandler::HandleSetStartupPagesToCurrentPages,
          base::Unretained(this)));
}

void StartupPagesHandler::OnJavascriptAllowed() {
  startup_custom_pages_table_model_.SetObserver(this);

  PrefService* prefService = Profile::FromWebUI(web_ui())->GetPrefs();
  SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefService);
  startup_custom_pages_table_model_.SetURLs(pref.urls);

  if (pref.urls.empty())
    pref.type = SessionStartupPref::DEFAULT;

  pref_change_registrar_.Init(prefService);
  pref_change_registrar_.Add(
      prefs::kURLsToRestoreOnStartup,
      base::Bind(&StartupPagesHandler::UpdateStartupPages,
                 base::Unretained(this)));
}

void StartupPagesHandler::OnJavascriptDisallowed() {
  startup_custom_pages_table_model_.SetObserver(nullptr);
  pref_change_registrar_.RemoveAll();
}

void StartupPagesHandler::OnModelChanged() {
  base::ListValue startup_pages;
  int page_count = startup_custom_pages_table_model_.RowCount();
  std::vector<GURL> urls = startup_custom_pages_table_model_.GetURLs();
  for (int i = 0; i < page_count; ++i) {
    std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
    entry->SetString("title", startup_custom_pages_table_model_.GetText(i, 0));
    entry->SetString("url", urls[i].spec());
    entry->SetString("tooltip",
                     startup_custom_pages_table_model_.GetTooltip(i));
    entry->SetInteger("modelIndex", i);
    startup_pages.Append(std::move(entry));
  }

  FireWebUIListener("update-startup-pages", startup_pages);
}

void StartupPagesHandler::OnItemsChanged(int start, int length) {
  OnModelChanged();
}

void StartupPagesHandler::OnItemsAdded(int start, int length) {
  OnModelChanged();
}

void StartupPagesHandler::OnItemsRemoved(int start, int length) {
  OnModelChanged();
}

void StartupPagesHandler::HandleAddStartupPage(const base::ListValue* args) {
  CHECK_EQ(2U, args->GetSize());

  const base::Value* callback_id;
  CHECK(args->Get(0, &callback_id));

  std::string url_string;
  CHECK(args->GetString(1, &url_string));

  GURL url;
  if (!settings_utils::FixupAndValidateStartupPage(url_string, &url)) {
    ResolveJavascriptCallback(*callback_id, base::Value(false));
    return;
  }

  int row_count = startup_custom_pages_table_model_.RowCount();
  int index;
  if (!args->GetInteger(1, &index) || index > row_count)
    index = row_count;

  startup_custom_pages_table_model_.Add(index, url);
  SaveStartupPagesPref();
  ResolveJavascriptCallback(*callback_id, base::Value(true));
}

void StartupPagesHandler::HandleEditStartupPage(const base::ListValue* args) {
  CHECK_EQ(args->GetSize(), 3U);
  const base::Value* callback_id;
  CHECK(args->Get(0, &callback_id));
  int index;
  CHECK(args->GetInteger(1, &index));

  if (index < 0 || index > startup_custom_pages_table_model_.RowCount()) {
    RejectJavascriptCallback(*callback_id, base::Value());
    NOTREACHED();
    return;
  }

  std::string url_string;
  CHECK(args->GetString(2, &url_string));

  GURL fixed_url;
  if (settings_utils::FixupAndValidateStartupPage(url_string, &fixed_url)) {
    std::vector<GURL> urls = startup_custom_pages_table_model_.GetURLs();
    urls[index] = fixed_url;
    startup_custom_pages_table_model_.SetURLs(urls);
    SaveStartupPagesPref();
    ResolveJavascriptCallback(*callback_id, base::Value(true));
  } else {
    ResolveJavascriptCallback(*callback_id, base::Value(false));
  }
}

void StartupPagesHandler::HandleOnStartupPrefsPageLoad(
    const base::ListValue* args) {
  AllowJavascript();
}

void StartupPagesHandler::HandleRemoveStartupPage(const base::ListValue* args) {
  int selected_index;
  if (!args->GetInteger(0, &selected_index)) {
    NOTREACHED();
    return;
  }

  if (selected_index < 0 ||
      selected_index >= startup_custom_pages_table_model_.RowCount()) {
    NOTREACHED();
    return;
  }

  startup_custom_pages_table_model_.Remove(selected_index);
  SaveStartupPagesPref();
}

void StartupPagesHandler::HandleSetStartupPagesToCurrentPages(
    const base::ListValue* args) {
  startup_custom_pages_table_model_.SetToCurrentlyOpenPages(
      web_ui()->GetWebContents());
  SaveStartupPagesPref();
}

void StartupPagesHandler::SaveStartupPagesPref() {
  PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();

  SessionStartupPref pref = SessionStartupPref::GetStartupPref(prefs);
  pref.urls = startup_custom_pages_table_model_.GetURLs();

  if (pref.urls.empty())
    pref.type = SessionStartupPref::DEFAULT;

  SessionStartupPref::SetStartupPref(prefs, pref);
}

void StartupPagesHandler::UpdateStartupPages() {
  const SessionStartupPref startup_pref = SessionStartupPref::GetStartupPref(
      Profile::FromWebUI(web_ui())->GetPrefs());
  startup_custom_pages_table_model_.SetURLs(startup_pref.urls);
  // The change will go to the JS code in the
  // StartupPagesHandler::OnModelChanged() method.
}

}  // namespace settings
