// 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 "components/enhanced_bookmarks/bookmark_server_cluster_service.h"

#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/values.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
#include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
#include "components/enhanced_bookmarks/pref_names.h"
#include "components/enhanced_bookmarks/proto/cluster.pb.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/sync_driver/sync_service.h"
#include "net/base/url_util.h"
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context_getter.h"

using bookmarks::BookmarkNode;

namespace {
const char kClusterUrl[] = "https://www.google.com/stars/cluster";
const int kPrefServiceVersion = 1;
const char kPrefServiceVersionKey[] = "version";
const char kPrefServiceDataKey[] = "data";
const char kAuthIdKey[] = "auth_id";
}  // namespace

namespace enhanced_bookmarks {

BookmarkServerClusterService::BookmarkServerClusterService(
    const std::string& application_language_code,
    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
    ProfileOAuth2TokenService* token_service,
    SigninManagerBase* signin_manager,
    enhanced_bookmarks::EnhancedBookmarkModel* enhanced_bookmark_model,
    sync_driver::SyncService* sync_service,
    PrefService* pref_service)
    : BookmarkServerService(request_context_getter,
                            token_service,
                            signin_manager,
                            enhanced_bookmark_model),
      application_language_code_(application_language_code),
      sync_service_(sync_service),
      pref_service_(pref_service),
      sync_refresh_skipped_(false),
      refreshes_needed_(0) {
  LoadModel();

  if (model_->loaded())
    TriggerTokenRequest(false);

  GetSigninManager()->AddObserver(this);
  if (sync_service_)
    sync_service_->AddObserver(this);
}

BookmarkServerClusterService::~BookmarkServerClusterService() {
}

void BookmarkServerClusterService::Shutdown() {
  if (sync_service_)
    sync_service_->RemoveObserver(this);
  GetSigninManager()->RemoveObserver(this);
}

const std::vector<const BookmarkNode*>
BookmarkServerClusterService::BookmarksForClusterNamed(
    const std::string& cluster_name) const {
  std::vector<const BookmarkNode*> results;

  ClusterMap::const_iterator cluster_it = cluster_data_.find(cluster_name);
  if (cluster_it == cluster_data_.end())
    return results;

  for (auto& star_id : cluster_it->second) {
    const BookmarkNode* bookmark = BookmarkForRemoteId(star_id);
    if (bookmark)
      results.push_back(bookmark);
  }
  return results;
}

const std::vector<std::string>
BookmarkServerClusterService::ClustersForBookmark(
    const BookmarkNode* bookmark) const {
  const std::string& star_id = RemoteIDForBookmark(bookmark);

  // TODO(noyau): if this turns out to be a perf bottleneck this may be improved
  // by storing a reverse map from id to cluster.
  std::vector<std::string> clusters;
  for (auto& pair : cluster_data_) {
    const std::vector<std::string>& stars_ids = pair.second;
    if (std::find(stars_ids.begin(), stars_ids.end(), star_id) !=
        stars_ids.end())
      clusters.push_back(pair.first);
  }
  return clusters;
}

const std::vector<std::string> BookmarkServerClusterService::GetClusters()
    const {
  std::vector<std::string> cluster_names;

  for (auto& pair : cluster_data_) {
    for (auto& star_id : pair.second) {
      const BookmarkNode* bookmark = BookmarkForRemoteId(star_id);
      if (bookmark) {
        // Only add clusters that have children.
        cluster_names.push_back(pair.first);
        break;
      }
    }
  }

  return cluster_names;
}

void BookmarkServerClusterService::AddObserver(
    enhanced_bookmarks::BookmarkServerServiceObserver* observer) {
  BookmarkServerService::AddObserver(observer);
  if (sync_refresh_skipped_) {
    TriggerTokenRequest(false);
    sync_refresh_skipped_ = true;
  }
}

// static
void BookmarkServerClusterService::RegisterPrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterDictionaryPref(prefs::kBookmarkClusters);
}

scoped_ptr<net::URLFetcher> BookmarkServerClusterService::CreateFetcher() {
  // Add the necessary arguments to the URI.
  GURL url(kClusterUrl);
  url = net::AppendQueryParameter(url, "output", "proto");

  // Append language.
  if (!application_language_code_.empty())
    url = net::AppendQueryParameter(url, "hl", application_language_code_);

  url = net::AppendQueryParameter(url, "v", model_->GetVersionString());

  // Build the URLFetcher to perform the request.
  scoped_ptr<net::URLFetcher> url_fetcher =
      net::URLFetcher::Create(url, net::URLFetcher::POST, this);

  // Binary encode a basic request proto.
  image_collections::ClusterRequest request_proto;
  request_proto.set_cluster_all(true);

  std::string proto_output;
  bool result = request_proto.SerializePartialToString(&proto_output);
  DCHECK(result);

  url_fetcher->SetUploadData("application/octet-stream", proto_output);
  return url_fetcher;
}

bool BookmarkServerClusterService::ProcessResponse(const std::string& response,
                                                   bool* should_notify) {
  DCHECK(*should_notify);
  image_collections::ClusterResponse response_proto;
  bool result = response_proto.ParseFromString(response);
  if (!result)
    return false;  // Not formatted properly.

  ClusterMap new_cluster_data;
  for (const auto& cluster : response_proto.clusters()) {
    const std::string& title = cluster.title();
    if (title.empty())
      continue;
    std::vector<std::string> stars_ids;
    for (auto& doc : cluster.docs()) {
      if (!doc.empty())
        stars_ids.push_back(doc);
    }
    if (stars_ids.size())
      new_cluster_data[title] = stars_ids;
  }

  if (new_cluster_data.size() == cluster_data_.size() &&
      std::equal(new_cluster_data.begin(),
                 new_cluster_data.end(),
                 cluster_data_.begin())) {
    *should_notify = false;
  } else {
    SwapModel(&new_cluster_data);
  }
  return true;
}

void BookmarkServerClusterService::CleanAfterFailure() {
  if (cluster_data_.empty())
    return;

  ClusterMap empty;
  SwapModel(&empty);
}

void BookmarkServerClusterService::EnhancedBookmarkModelLoaded() {
  TriggerTokenRequest(false);
}

void BookmarkServerClusterService::EnhancedBookmarkAdded(
    const BookmarkNode* node) {
  InvalidateCache();
}

void BookmarkServerClusterService::EnhancedBookmarkRemoved(
    const BookmarkNode* node) {
  // It is possible to remove the entries from the map here, but as those are
  // filtered in ClustersForBookmark() this is not strictly necessary.
  InvalidateCache();
}

void BookmarkServerClusterService::EnhancedBookmarkNodeChanged(
    const BookmarkNode* node) {
  InvalidateCache();
}

void BookmarkServerClusterService::EnhancedBookmarkAllUserNodesRemoved() {
  if (!cluster_data_.empty()) {
    ClusterMap empty;
    SwapModel(&empty);
  }
}

void BookmarkServerClusterService::EnhancedBookmarkRemoteIdChanged(
    const BookmarkNode* node,
    const std::string& old_remote_id,
    const std::string& remote_id) {
  std::vector<std::string> clusters;
  for (auto& pair : cluster_data_) {
    std::vector<std::string>& stars_ids = pair.second;
    std::replace(stars_ids.begin(), stars_ids.end(), old_remote_id, remote_id);
  }
}

void BookmarkServerClusterService::GoogleSignedOut(
    const std::string& account_id,
    const std::string& username) {
  if (!cluster_data_.empty()) {
    ClusterMap empty;
    SwapModel(&empty);
  }
}

void BookmarkServerClusterService::SwapModel(ClusterMap* cluster_map) {
  cluster_data_.swap(*cluster_map);
  const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();
  scoped_ptr<base::DictionaryValue> dictionary(
      Serialize(cluster_data_, auth_id));
  pref_service_->Set(prefs::kBookmarkClusters, *dictionary);
}

void BookmarkServerClusterService::LoadModel() {
  const base::DictionaryValue* dictionary =
      pref_service_->GetDictionary(prefs::kBookmarkClusters);
  const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();

  ClusterMap loaded_data;
  bool result = BookmarkServerClusterService::Deserialize(
      *dictionary, auth_id, &loaded_data);
  if (result)
    cluster_data_.swap(loaded_data);
}

void BookmarkServerClusterService::OnStateChanged() {
  // Do nothing.
}

void BookmarkServerClusterService::OnSyncCycleCompleted() {
  // The stars cluster API relies on the information in chrome-sync. Sending a
  // cluster request immediately after a bookmark is changed from the bookmark
  // observer notification will yield the wrong results. The request must be
  // delayed until the sync cycle has completed.
  // Note that we will be skipping calling this cluster API if there is no
  // observer attached, because calling that is meaningless without UI to show.
  // We also will avoid requesting for clusters if the bookmark data hasn't
  // changed.
  if (refreshes_needed_ > 0) {
    DCHECK(model_->loaded());
    if (observers_.might_have_observers()) {
      TriggerTokenRequest(false);
      sync_refresh_skipped_ = false;
    } else {
      sync_refresh_skipped_ = true;
    }
    --refreshes_needed_;
  }
}

void BookmarkServerClusterService::InvalidateCache() {
  // Bookmark changes can happen locally or via sync. It is difficult to
  // determine if a given SyncCycle contains all the local modifications.
  //
  // Consider the following sequence:
  //  1. SyncCycleBeginning (bookmark version:1)
  //  2. Bookmarks mutate locally (bookmark version:2)
  //  3. SyncCycleCompleted (bookmark version:1)
  //
  // In this case, the bookmarks modified locally won't be sent to the server
  // until the next SyncCycleCompleted.  Since we can't accurately determine
  // if a bookmark change has been sent on a SyncCycleCompleted, we're always
  // assuming that we need to wait for 2 sync cycles.
  refreshes_needed_ = 2;
}

//
// Serialization.
//
// static
scoped_ptr<base::DictionaryValue> BookmarkServerClusterService::Serialize(
    const ClusterMap& cluster_map,
    const std::string& auth_id) {
  // Create a list of all clusters. For each cluster, make another list. The
  // first element in the list is the key (cluster name). All subsequent
  // elements are stars ids.
  scoped_ptr<base::ListValue> all_clusters(new base::ListValue);
  for (auto& pair : cluster_map) {
    scoped_ptr<base::ListValue> cluster(new base::ListValue);
    cluster->AppendString(pair.first);
    cluster->AppendStrings(pair.second);
    all_clusters->Append(cluster.release());
  }

  // The dictionary that will be serialized has two fields: a version field and
  // a data field.
  scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue);
  data->SetInteger(kPrefServiceVersionKey, kPrefServiceVersion);
  data->Set(kPrefServiceDataKey, all_clusters.release());
  data->SetString(kAuthIdKey, auth_id);

  return data.Pass();
}

// static
bool BookmarkServerClusterService::Deserialize(
    const base::DictionaryValue& value,
    const std::string& auth_id,
    ClusterMap* out_map) {
  ClusterMap output;

  // Check version.
  int version;
  if (!value.GetInteger(kPrefServiceVersionKey, &version))
    return false;
  if (version != kPrefServiceVersion)
    return false;

  // Check auth id.
  std::string id;
  if (!value.GetString(kAuthIdKey, &id))
    return false;
  if (id != auth_id)
    return false;

  const base::ListValue* all_clusters = NULL;
  if (!value.GetList(kPrefServiceDataKey, &all_clusters))
    return false;

  for (size_t index = 0; index < all_clusters->GetSize(); ++index) {
    const base::ListValue* cluster = NULL;
    if (!all_clusters->GetList(index, &cluster))
      return false;
    if (cluster->GetSize() < 1)
      return false;
    std::string key;
    if (!cluster->GetString(0, &key))
      return false;
    std::vector<std::string> stars_ids;
    for (size_t index = 1; index < cluster->GetSize(); ++index) {
      std::string stars_id;
      if (!cluster->GetString(index, &stars_id))
        return false;
      stars_ids.push_back(stars_id);
    }
    output.insert(std::make_pair(key, stars_ids));
  }
  out_map->swap(output);
  return true;
}

}  // namespace enhanced_bookmarks
