/*
 *
 * Copyright 2015-2016 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <grpc/support/port_platform.h>

#include "src/core/lib/security/credentials/composite/composite_credentials.h"

#include <cstring>
#include <new>

#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/polling_entity.h"
#include "src/core/lib/surface/api_trace.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

/* -- Composite call credentials. -- */

static void composite_call_metadata_cb(void* arg, grpc_error* error);

namespace {
struct grpc_composite_call_credentials_metadata_context {
  grpc_composite_call_credentials_metadata_context(
      grpc_composite_call_credentials* composite_creds,
      grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
      grpc_credentials_mdelem_array* md_array,
      grpc_closure* on_request_metadata)
      : composite_creds(composite_creds),
        pollent(pollent),
        auth_md_context(auth_md_context),
        md_array(md_array),
        on_request_metadata(on_request_metadata) {
    GRPC_CLOSURE_INIT(&internal_on_request_metadata, composite_call_metadata_cb,
                      this, grpc_schedule_on_exec_ctx);
  }

  grpc_composite_call_credentials* composite_creds;
  size_t creds_index = 0;
  grpc_polling_entity* pollent;
  grpc_auth_metadata_context auth_md_context;
  grpc_credentials_mdelem_array* md_array;
  grpc_closure* on_request_metadata;
  grpc_closure internal_on_request_metadata;
};
}  // namespace

static void composite_call_metadata_cb(void* arg, grpc_error* error) {
  grpc_composite_call_credentials_metadata_context* ctx =
      static_cast<grpc_composite_call_credentials_metadata_context*>(arg);
  if (error == GRPC_ERROR_NONE) {
    const grpc_composite_call_credentials::CallCredentialsList& inner =
        ctx->composite_creds->inner();
    /* See if we need to get some more metadata. */
    if (ctx->creds_index < inner.size()) {
      if (inner[ctx->creds_index++]->get_request_metadata(
              ctx->pollent, ctx->auth_md_context, ctx->md_array,
              &ctx->internal_on_request_metadata, &error)) {
        // Synchronous response, so call ourselves recursively.
        composite_call_metadata_cb(arg, error);
        GRPC_ERROR_UNREF(error);
      }
      return;
    }
    // We're done!
  }
  GRPC_CLOSURE_SCHED(ctx->on_request_metadata, GRPC_ERROR_REF(error));
  gpr_free(ctx);
}

bool grpc_composite_call_credentials::get_request_metadata(
    grpc_polling_entity* pollent, grpc_auth_metadata_context auth_md_context,
    grpc_credentials_mdelem_array* md_array, grpc_closure* on_request_metadata,
    grpc_error** error) {
  grpc_composite_call_credentials_metadata_context* ctx;
  ctx = grpc_core::New<grpc_composite_call_credentials_metadata_context>(
      this, pollent, auth_md_context, md_array, on_request_metadata);
  bool synchronous = true;
  const CallCredentialsList& inner = ctx->composite_creds->inner();
  while (ctx->creds_index < inner.size()) {
    if (inner[ctx->creds_index++]->get_request_metadata(
            ctx->pollent, ctx->auth_md_context, ctx->md_array,
            &ctx->internal_on_request_metadata, error)) {
      if (*error != GRPC_ERROR_NONE) break;
    } else {
      synchronous = false;  // Async return.
      break;
    }
  }
  if (synchronous) grpc_core::Delete(ctx);
  return synchronous;
}

void grpc_composite_call_credentials::cancel_get_request_metadata(
    grpc_credentials_mdelem_array* md_array, grpc_error* error) {
  for (size_t i = 0; i < inner_.size(); ++i) {
    inner_[i]->cancel_get_request_metadata(md_array, GRPC_ERROR_REF(error));
  }
  GRPC_ERROR_UNREF(error);
}

static size_t get_creds_array_size(const grpc_call_credentials* creds,
                                   bool is_composite) {
  return is_composite
             ? static_cast<const grpc_composite_call_credentials*>(creds)
                   ->inner()
                   .size()
             : 1;
}

void grpc_composite_call_credentials::push_to_inner(
    grpc_core::RefCountedPtr<grpc_call_credentials> creds, bool is_composite) {
  if (!is_composite) {
    inner_.push_back(std::move(creds));
    return;
  }
  auto composite_creds =
      static_cast<grpc_composite_call_credentials*>(creds.get());
  for (size_t i = 0; i < composite_creds->inner().size(); ++i) {
    inner_.push_back(std::move(composite_creds->inner_[i]));
  }
}

grpc_composite_call_credentials::grpc_composite_call_credentials(
    grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
    grpc_core::RefCountedPtr<grpc_call_credentials> creds2)
    : grpc_call_credentials(GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) {
  const bool creds1_is_composite =
      strcmp(creds1->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
  const bool creds2_is_composite =
      strcmp(creds2->type(), GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0;
  const size_t size = get_creds_array_size(creds1.get(), creds1_is_composite) +
                      get_creds_array_size(creds2.get(), creds2_is_composite);
  inner_.reserve(size);
  push_to_inner(std::move(creds1), creds1_is_composite);
  push_to_inner(std::move(creds2), creds2_is_composite);
}

static grpc_core::RefCountedPtr<grpc_call_credentials>
composite_call_credentials_create(
    grpc_core::RefCountedPtr<grpc_call_credentials> creds1,
    grpc_core::RefCountedPtr<grpc_call_credentials> creds2) {
  return grpc_core::MakeRefCounted<grpc_composite_call_credentials>(
      std::move(creds1), std::move(creds2));
}

grpc_call_credentials* grpc_composite_call_credentials_create(
    grpc_call_credentials* creds1, grpc_call_credentials* creds2,
    void* reserved) {
  GRPC_API_TRACE(
      "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
      "reserved=%p)",
      3, (creds1, creds2, reserved));
  GPR_ASSERT(reserved == nullptr);
  GPR_ASSERT(creds1 != nullptr);
  GPR_ASSERT(creds2 != nullptr);

  return composite_call_credentials_create(creds1->Ref(), creds2->Ref())
      .release();
}

/* -- Composite channel credentials. -- */

grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_composite_channel_credentials::create_security_connector(
    grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
    const char* target, const grpc_channel_args* args,
    grpc_channel_args** new_args) {
  GPR_ASSERT(inner_creds_ != nullptr && call_creds_ != nullptr);
  /* If we are passed a call_creds, create a call composite to pass it
     downstream. */
  if (call_creds != nullptr) {
    return inner_creds_->create_security_connector(
        composite_call_credentials_create(call_creds_, std::move(call_creds)),
        target, args, new_args);
  } else {
    return inner_creds_->create_security_connector(call_creds_, target, args,
                                                   new_args);
  }
}

grpc_channel_credentials* grpc_composite_channel_credentials_create(
    grpc_channel_credentials* channel_creds, grpc_call_credentials* call_creds,
    void* reserved) {
  GPR_ASSERT(channel_creds != nullptr && call_creds != nullptr &&
             reserved == nullptr);
  GRPC_API_TRACE(
      "grpc_composite_channel_credentials_create(channel_creds=%p, "
      "call_creds=%p, reserved=%p)",
      3, (channel_creds, call_creds, reserved));
  return grpc_core::New<grpc_composite_channel_credentials>(
      channel_creds->Ref(), call_creds->Ref());
}
