/*
 *  Copyright 2018 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 "pc/rtcstatstraversal.h"

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "api/stats/rtcstats_objects.h"
#include "rtc_base/checks.h"

namespace webrtc {

namespace {

void TraverseAndTakeVisitedStats(RTCStatsReport* report,
                                 RTCStatsReport* visited_report,
                                 const std::string& current_id) {
  // Mark current stats object as visited by moving it |report| to
  // |visited_report|.
  std::unique_ptr<const RTCStats> current = report->Take(current_id);
  if (!current) {
    // This node has already been visited (or it is an invalid id).
    return;
  }
  std::vector<const std::string*> neighbor_ids =
      GetStatsReferencedIds(*current);
  visited_report->AddStats(std::move(current));

  // Recursively traverse all neighbors.
  for (const auto* neighbor_id : neighbor_ids) {
    TraverseAndTakeVisitedStats(report, visited_report, *neighbor_id);
  }
}

void AddIdIfDefined(const RTCStatsMember<std::string>& id,
                    std::vector<const std::string*>* neighbor_ids) {
  if (id.is_defined())
    neighbor_ids->push_back(&(*id));
}

void AddIdsIfDefined(const RTCStatsMember<std::vector<std::string>>& ids,
                     std::vector<const std::string*>* neighbor_ids) {
  if (ids.is_defined()) {
    for (const std::string& id : *ids)
      neighbor_ids->push_back(&id);
  }
}

}  // namespace

rtc::scoped_refptr<RTCStatsReport> TakeReferencedStats(
    rtc::scoped_refptr<RTCStatsReport> report,
    const std::vector<std::string>& ids) {
  rtc::scoped_refptr<RTCStatsReport> result =
      RTCStatsReport::Create(report->timestamp_us());
  for (const auto& id : ids) {
    TraverseAndTakeVisitedStats(report.get(), result.get(), id);
  }
  return result;
}

std::vector<const std::string*> GetStatsReferencedIds(const RTCStats& stats) {
  std::vector<const std::string*> neighbor_ids;
  const char* type = stats.type();
  if (type == RTCCertificateStats::kType) {
    const auto& certificate = static_cast<const RTCCertificateStats&>(stats);
    AddIdIfDefined(certificate.issuer_certificate_id, &neighbor_ids);
  } else if (type == RTCCodecStats::kType) {
    // RTCCodecStats does not have any neighbor references.
  } else if (type == RTCDataChannelStats::kType) {
    // RTCDataChannelStats does not have any neighbor references.
  } else if (type == RTCIceCandidatePairStats::kType) {
    const auto& candidate_pair =
        static_cast<const RTCIceCandidatePairStats&>(stats);
    AddIdIfDefined(candidate_pair.transport_id, &neighbor_ids);
    AddIdIfDefined(candidate_pair.local_candidate_id, &neighbor_ids);
    AddIdIfDefined(candidate_pair.remote_candidate_id, &neighbor_ids);
  } else if (type == RTCLocalIceCandidateStats::kType ||
             type == RTCRemoteIceCandidateStats::kType) {
    const auto& local_or_remote_candidate =
        static_cast<const RTCIceCandidateStats&>(stats);
    AddIdIfDefined(local_or_remote_candidate.transport_id, &neighbor_ids);
  } else if (type == RTCMediaStreamStats::kType) {
    const auto& stream = static_cast<const RTCMediaStreamStats&>(stats);
    AddIdsIfDefined(stream.track_ids, &neighbor_ids);
  } else if (type == RTCMediaStreamTrackStats::kType) {
    // RTCMediaStreamTrackStats does not have any neighbor references.
  } else if (type == RTCPeerConnectionStats::kType) {
    // RTCPeerConnectionStats does not have any neighbor references.
  } else if (type == RTCInboundRTPStreamStats::kType ||
             type == RTCOutboundRTPStreamStats::kType) {
    const auto& rtp = static_cast<const RTCRTPStreamStats&>(stats);
    AddIdIfDefined(rtp.associate_stats_id, &neighbor_ids);
    AddIdIfDefined(rtp.track_id, &neighbor_ids);
    AddIdIfDefined(rtp.transport_id, &neighbor_ids);
    AddIdIfDefined(rtp.codec_id, &neighbor_ids);
  } else if (type == RTCTransportStats::kType) {
    // RTCTransportStats does not have any neighbor references.
    const auto& transport = static_cast<const RTCTransportStats&>(stats);
    AddIdIfDefined(transport.rtcp_transport_stats_id, &neighbor_ids);
    AddIdIfDefined(transport.selected_candidate_pair_id, &neighbor_ids);
    AddIdIfDefined(transport.local_certificate_id, &neighbor_ids);
    AddIdIfDefined(transport.remote_certificate_id, &neighbor_ids);
  } else {
    RTC_NOTREACHED() << "Unrecognized type: " << type;
  }
  return neighbor_ids;
}

}  // namespace webrtc
