//
// Copyright 2017 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.
//

//
// Automatically generated by tools/codegen/core/gen_settings_ids.py
//

#include "src/core/ext/transport/chttp2/transport/http2_settings.h"

#include <grpc/support/port_platform.h>

#include "src/core/ext/transport/chttp2/transport/http2_status.h"
#include "src/core/util/useful.h"
#include "absl/strings/str_cat.h"

using grpc_core::http2::Http2ErrorCode;

namespace grpc_core {

void Http2Settings::Diff(
    bool is_first_send, const Http2Settings& old_setting,
    absl::FunctionRef<void(uint16_t key, uint32_t value)> cb) const {
  if (header_table_size_ != old_setting.header_table_size_) {
    cb(kHeaderTableSizeWireId, header_table_size_);
  }
  if (enable_push_ != old_setting.enable_push_) {
    cb(kEnablePushWireId, enable_push_);
  }
  if (max_concurrent_streams_ != old_setting.max_concurrent_streams_) {
    cb(kMaxConcurrentStreamsWireId, max_concurrent_streams_);
  }
  if (is_first_send ||
      initial_window_size_ != old_setting.initial_window_size_) {
    cb(kInitialWindowSizeWireId, initial_window_size_);
  }
  if (max_frame_size_ != old_setting.max_frame_size_) {
    cb(kMaxFrameSizeWireId, max_frame_size_);
  }
  if (max_header_list_size_ != old_setting.max_header_list_size_) {
    cb(kMaxHeaderListSizeWireId, max_header_list_size_);
  }
  if (allow_true_binary_metadata_ != old_setting.allow_true_binary_metadata_) {
    cb(kGrpcAllowTrueBinaryMetadataWireId, allow_true_binary_metadata_);
  }
  if (preferred_receive_crypto_message_size_ !=
      old_setting.preferred_receive_crypto_message_size_) {
    cb(kGrpcPreferredReceiveCryptoFrameSizeWireId,
       preferred_receive_crypto_message_size_);
  }
  if (allow_security_frame_ != old_setting.allow_security_frame_) {
    cb(kGrpcAllowSecurityFrameWireId, allow_security_frame_);
  }
}

std::string Http2Settings::WireIdToName(uint16_t wire_id) {
  switch (wire_id) {
    case kHeaderTableSizeWireId:
      return std::string(header_table_size_name());
    case kEnablePushWireId:
      return std::string(enable_push_name());
    case kMaxConcurrentStreamsWireId:
      return std::string(max_concurrent_streams_name());
    case kInitialWindowSizeWireId:
      return std::string(initial_window_size_name());
    case kMaxFrameSizeWireId:
      return std::string(max_frame_size_name());
    case kMaxHeaderListSizeWireId:
      return std::string(max_header_list_size_name());
    case kGrpcAllowTrueBinaryMetadataWireId:
      return std::string(allow_true_binary_metadata_name());
    case kGrpcPreferredReceiveCryptoFrameSizeWireId:
      return std::string(preferred_receive_crypto_message_size_name());
    case kGrpcAllowSecurityFrameWireId:
      return std::string(allow_security_frame_name());
    default:
      return absl::StrCat("UNKNOWN (", wire_id, ")");
  }
}

Http2ErrorCode Http2Settings::Apply(uint16_t key, uint32_t value) {
  switch (key) {
    case kHeaderTableSizeWireId:
      header_table_size_ = value;
      break;
    case kEnablePushWireId:
      if (value > 1) return Http2ErrorCode::kProtocolError;
      enable_push_ = value != 0;
      break;
    case kMaxConcurrentStreamsWireId:
      initial_max_concurrent_streams_ = value;
      max_concurrent_streams_ = value;
      break;
    case kInitialWindowSizeWireId:
      if (value > max_initial_window_size()) {
        return Http2ErrorCode::kFlowControlError;
      }
      initial_window_size_ = value;
      break;
    case kMaxFrameSizeWireId:
      if (value < min_max_frame_size() || value > max_max_frame_size()) {
        return Http2ErrorCode::kProtocolError;
      }
      max_frame_size_ = value;
      break;
    case kMaxHeaderListSizeWireId:
      max_header_list_size_ = std::min(value, 16777216u);
      break;
    case kGrpcAllowTrueBinaryMetadataWireId:
      if (value > 1) return Http2ErrorCode::kProtocolError;
      allow_true_binary_metadata_ = value != 0;
      break;
    case kGrpcPreferredReceiveCryptoFrameSizeWireId:
      preferred_receive_crypto_message_size_ =
          Clamp(value, min_preferred_receive_crypto_message_size(),
                max_preferred_receive_crypto_message_size());
      break;
    case kGrpcAllowSecurityFrameWireId:
      if (value > 1) return Http2ErrorCode::kProtocolError;
      allow_security_frame_ = value != 0;
      break;
  }
  return Http2ErrorCode::kNoError;
}

}  // namespace grpc_core
