// 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 "content/public/browser/push_messaging_service.h"

#include "base/callback.h"
#include "content/browser/push_messaging/push_messaging_message_filter.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"

namespace content {

namespace {

void CallStringCallbackFromIO(
    const PushMessagingService::StringCallback& callback,
    const std::vector<std::string>& data,
    ServiceWorkerStatusCode service_worker_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  bool success = service_worker_status == SERVICE_WORKER_OK;
  bool not_found = service_worker_status == SERVICE_WORKER_ERROR_NOT_FOUND;
  std::string result;
  if (success) {
    DCHECK_EQ(1u, data.size());
    result = data[0];
  }
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          base::Bind(callback, result, success, not_found));
}

void CallClosureFromIO(const base::Closure& callback,
                       ServiceWorkerStatusCode status) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
}

void GetUserDataOnIO(
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_wrapper,
    int64_t service_worker_registration_id,
    const std::string& key,
    const PushMessagingService::StringCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  service_worker_context_wrapper->GetRegistrationUserData(
      service_worker_registration_id, {key},
      base::Bind(&CallStringCallbackFromIO, callback));
}

void ClearPushSubscriptionIdOnIO(
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    int64_t service_worker_registration_id,
    const base::Closure& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  service_worker_context->ClearRegistrationUserData(
      service_worker_registration_id, {kPushRegistrationIdServiceWorkerKey},
      base::Bind(&CallClosureFromIO, callback));
}

void StorePushSubscriptionOnIOForTesting(
    scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
    int64_t service_worker_registration_id,
    const GURL& origin,
    const std::string& subscription_id,
    const std::string& sender_id,
    const base::Closure& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  service_worker_context->StoreRegistrationUserData(
      service_worker_registration_id, origin,
      {{kPushRegistrationIdServiceWorkerKey, subscription_id},
       {kPushSenderIdServiceWorkerKey, sender_id}},
      base::Bind(&CallClosureFromIO, callback));
}

scoped_refptr<ServiceWorkerContextWrapper> GetServiceWorkerContext(
    BrowserContext* browser_context, const GURL& origin) {
  StoragePartition* partition =
      BrowserContext::GetStoragePartitionForSite(browser_context, origin);
  return make_scoped_refptr(
      static_cast<ServiceWorkerContextWrapper*>(
          partition->GetServiceWorkerContext()));
}

}  // anonymous namespace

// static
void PushMessagingService::GetSenderId(BrowserContext* browser_context,
                                       const GURL& origin,
                                       int64_t service_worker_registration_id,
                                       const StringCallback& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      base::Bind(&GetUserDataOnIO,
                 GetServiceWorkerContext(browser_context, origin),
                 service_worker_registration_id,
                 kPushSenderIdServiceWorkerKey,
                 callback));
}

// static
void PushMessagingService::ClearPushSubscriptionId(
    BrowserContext* browser_context,
    const GURL& origin,
    int64_t service_worker_registration_id,
    const base::Closure& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&ClearPushSubscriptionIdOnIO,
                 GetServiceWorkerContext(browser_context, origin),
                 service_worker_registration_id, callback));
}

// static
void PushMessagingService::StorePushSubscriptionForTesting(
    BrowserContext* browser_context,
    const GURL& origin,
    int64_t service_worker_registration_id,
    const std::string& subscription_id,
    const std::string& sender_id,
    const base::Closure& callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&StorePushSubscriptionOnIOForTesting,
                 GetServiceWorkerContext(browser_context, origin),
                 service_worker_registration_id, origin, subscription_id,
                 sender_id, callback));
}

}  // namespace content
