/*
 *  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();
  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
