/*
 *  Copyright 2020 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "p2p/base/stun_dictionary.h"

#include <algorithm>
#include <deque>
#include <utility>

#include "rtc_base/logging.h"

namespace cricket {

const StunAddressAttribute* StunDictionaryView::GetAddress(int key) const {
  const StunAttribute* attr = GetOrNull(key, STUN_VALUE_ADDRESS);
  if (attr == nullptr) {
    return nullptr;
  }
  return reinterpret_cast<const StunAddressAttribute*>(attr);
}

const StunUInt32Attribute* StunDictionaryView::GetUInt32(int key) const {
  const StunAttribute* attr = GetOrNull(key, STUN_VALUE_UINT32);
  if (attr == nullptr) {
    return nullptr;
  }
  return reinterpret_cast<const StunUInt32Attribute*>(attr);
}

const StunUInt64Attribute* StunDictionaryView::GetUInt64(int key) const {
  const StunAttribute* attr = GetOrNull(key, STUN_VALUE_UINT64);
  if (attr == nullptr) {
    return nullptr;
  }
  return reinterpret_cast<const StunUInt64Attribute*>(attr);
}

const StunByteStringAttribute* StunDictionaryView::GetByteString(
    int key) const {
  const StunAttribute* attr = GetOrNull(key, STUN_VALUE_BYTE_STRING);
  if (attr == nullptr) {
    return nullptr;
  }
  return reinterpret_cast<const StunByteStringAttribute*>(attr);
}

const StunUInt16ListAttribute* StunDictionaryView::GetUInt16List(
    int key) const {
  const StunAttribute* attr = GetOrNull(key, STUN_VALUE_UINT16_LIST);
  if (attr == nullptr) {
    return nullptr;
  }
  return reinterpret_cast<const StunUInt16ListAttribute*>(attr);
}

const StunAttribute* StunDictionaryView::GetOrNull(
    int key,
    absl::optional<StunAttributeValueType> type) const {
  const auto it = attrs_.find(key);
  if (it == attrs_.end()) {
    return nullptr;
  }

  if (type && it->second->value_type() != *type) {
    RTC_LOG(LS_WARNING) << "Get key: " << key << " with type: " << *type
                        << " found different type: "
                        << it->second->value_type();
    return nullptr;
  }
  return (*it).second.get();
}

webrtc::RTCErrorOr<
    std::pair<uint64_t, std::deque<std::unique_ptr<StunAttribute>>>>
StunDictionaryView::ParseDelta(const StunByteStringAttribute& delta) {
  rtc::ByteBufferReader buf(delta.array_view());
  uint16_t magic;
  if (!buf.ReadUInt16(&magic)) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Failed to read magic number");
  }
  if (magic != kDeltaMagic) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Invalid magic number");
  }

  uint16_t delta_version;
  if (!buf.ReadUInt16(&delta_version)) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Failed to read version");
  }

  if (delta_version != kDeltaVersion) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Unsupported delta version");
  }

  // Now read all the attributes
  std::deque<std::unique_ptr<StunAttribute>> attrs;
  while (buf.Length()) {
    uint16_t key, length, value_type;
    if (!buf.ReadUInt16(&key)) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Failed to read attribute key");
    }
    if (!buf.ReadUInt16(&length)) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Failed to read attribute length");
    }
    if (!buf.ReadUInt16(&value_type)) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Failed to read value type");
    }

    StunAttributeValueType value_type_enum =
        static_cast<StunAttributeValueType>(value_type);
    std::unique_ptr<StunAttribute> attr(
        StunAttribute::Create(value_type_enum, key, length, nullptr));
    if (!attr) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Failed to create attribute");
    }
    if (attr->length() != length) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Inconsistent attribute length");
    }
    if (!attr->Read(&buf)) {
      return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                              "Failed to read attribute content");
    }
    attrs.push_back(std::move(attr));
  }

  // The first attribute should be the version...
  if (attrs.empty()) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Empty delta!");
  }

  if (attrs[0]->type() != kVersionKey ||
      attrs[0]->value_type() != STUN_VALUE_UINT64) {
    return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER,
                            "Missing version!");
  }

  uint64_t version_in_delta =
      reinterpret_cast<const StunUInt64Attribute*>(attrs[0].get())->value();
  attrs.pop_front();

  return std::make_pair(std::max(version_in_delta, version_in_delta),
                        std::move(attrs));
}

// Apply a delta return an StunUInt64Attribute to ack the update.
webrtc::RTCErrorOr<
    std::pair<std::unique_ptr<StunUInt64Attribute>, std::vector<uint16_t>>>
StunDictionaryView::ApplyDelta(const StunByteStringAttribute& delta) {
  auto parsed_delta = ParseDelta(delta);
  if (!parsed_delta.ok()) {
    return webrtc::RTCError(parsed_delta.error());
  }

  uint64_t version_in_delta = parsed_delta.value().first;

  // Check that update does not overflow max_bytes_stored_.
  int new_bytes_stored = bytes_stored_;
  for (auto& attr : parsed_delta.value().second) {
    auto old_version = version_per_key_.find(attr->type());
    if (old_version == version_per_key_.end() ||
        version_in_delta > old_version->second) {
      size_t new_length = attr->length();
      size_t old_length = GetLength(attr->type());
      if (old_version == version_per_key_.end()) {
        new_length += sizeof(int64_t);
      }

      new_bytes_stored = new_bytes_stored + new_length - old_length;
      if (new_bytes_stored <= 0) {
        RTC_LOG(LS_WARNING)
            << "attr: " << attr->type() << " old_length: " << old_length
            << " new_length: " << new_length
            << " bytes_stored_: " << bytes_stored_
            << " new_bytes_stored: " << new_bytes_stored;
        return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER);
      }
      if (new_bytes_stored > max_bytes_stored_) {
        RTC_LOG(LS_INFO) << "attr: " << attr->type()
                         << " old_length: " << old_length
                         << " new_length: " << new_length
                         << " bytes_stored_: " << bytes_stored_
                         << " new_bytes_stored: " << new_bytes_stored;
      }
    }
  }
  if (new_bytes_stored > max_bytes_stored_) {
    RTC_LOG(LS_INFO) << " bytes_stored_: " << bytes_stored_
                     << " new_bytes_stored: " << new_bytes_stored;
    return webrtc::RTCError(webrtc::RTCErrorType::RESOURCE_EXHAUSTED);
  }

  // Apply the update.
  std::vector<uint16_t> keys;
  for (auto& attr : parsed_delta.value().second) {
    if (version_in_delta > version_per_key_[attr->type()]) {
      version_per_key_[attr->type()] = version_in_delta;
      keys.push_back(attr->type());
      if (attr->value_type() == STUN_VALUE_BYTE_STRING && attr->length() == 0) {
        attrs_.erase(attr->type());
      } else {
        attrs_[attr->type()] = std::move(attr);
      }
    }
  }
  bytes_stored_ = new_bytes_stored;

  return std::make_pair(std::make_unique<StunUInt64Attribute>(
                            STUN_ATTR_GOOG_DELTA_ACK, version_in_delta),
                        std::move(keys));
}

size_t StunDictionaryView::GetLength(int key) const {
  auto attr = GetOrNull(key);
  if (attr != nullptr) {
    return attr->length();
  }
  return 0;
}

void StunDictionaryWriter::Disable() {
  disabled_ = true;
}

void StunDictionaryWriter::Delete(int key) {
  if (disabled_) {
    return;
  }

  if (dictionary_) {
    if (dictionary_->attrs_.find(key) == dictionary_->attrs_.end()) {
      return;
    }
  }

  // remove any pending updates.
  pending_.erase(
      std::remove_if(pending_.begin(), pending_.end(),
                     [key](const auto& p) { return p.second->type() == key; }),
      pending_.end());

  // Create tombstone.
  auto tombstone = std::make_unique<StunByteStringAttribute>(key);

  // add a pending entry.
  pending_.push_back(std::make_pair(++version_, tombstone.get()));

  // store the tombstone.
  tombstones_[key] = std::move(tombstone);

  if (dictionary_) {
    // remove value
    dictionary_->attrs_.erase(key);
  }
}

void StunDictionaryWriter::Set(std::unique_ptr<StunAttribute> attr) {
  if (disabled_) {
    return;
  }
  int key = attr->type();
  // remove any pending updates.
  pending_.erase(
      std::remove_if(pending_.begin(), pending_.end(),
                     [key](const auto& p) { return p.second->type() == key; }),
      pending_.end());

  // remove any existing key.
  tombstones_.erase(key);

  // create pending entry.
  pending_.push_back(std::make_pair(++version_, attr.get()));

  if (dictionary_) {
    // store attribute.
    dictionary_->attrs_[key] = std::move(attr);
  }
}

// Create an StunByteStringAttribute containing the pending (e.g not ack:ed)
// modifications.
std::unique_ptr<StunByteStringAttribute> StunDictionaryWriter::CreateDelta() {
  if (disabled_) {
    return nullptr;
  }
  if (pending_.empty()) {
    return nullptr;
  }

  rtc::ByteBufferWriter buf;
  buf.WriteUInt16(StunDictionaryView::kDeltaMagic);    // 0,1
  buf.WriteUInt16(StunDictionaryView::kDeltaVersion);  // 2,3

  // max version in Delta.
  buf.WriteUInt16(StunDictionaryView::kVersionKey);  // 4,5
  buf.WriteUInt16(8);                                // 6,7
  buf.WriteUInt16(STUN_VALUE_UINT64);                // 8,9
  buf.WriteUInt64(pending_.back().first);            // 10-17
  // attributes
  for (const auto& attr : pending_) {
    buf.WriteUInt16(attr.second->type());
    buf.WriteUInt16(static_cast<uint16_t>(attr.second->length()));
    buf.WriteUInt16(attr.second->value_type());
    if (!attr.second->Write(&buf)) {
      RTC_LOG(LS_ERROR) << "Failed to write key: " << attr.second->type();
      return nullptr;
    }
  }
  return std::make_unique<StunByteStringAttribute>(STUN_ATTR_GOOG_DELTA,
                                                   buf.Data(), buf.Length());
}

// Apply a delta ack, i.e prune list of pending changes.
void StunDictionaryWriter::ApplyDeltaAck(const StunUInt64Attribute& ack) {
  uint64_t acked_version = ack.value();
  auto entries_to_remove = std::remove_if(
      pending_.begin(), pending_.end(),
      [acked_version](const auto& p) { return p.first <= acked_version; });

  // remove tombstones.
  for (auto it = entries_to_remove; it != pending_.end(); ++it) {
    tombstones_.erase((*it).second->type());
  }
  pending_.erase(entries_to_remove, pending_.end());
}

// Check if a key has a pending change (i.e a change
// that has not been acked).
bool StunDictionaryWriter::Pending(int key) const {
  for (const auto& attr : pending_) {
    if (attr.second->type() == key) {
      return true;
    }
  }
  return false;
}

int StunDictionaryWriter::Pending() const {
  return pending_.size();
}

}  // namespace cricket
