/*
 *  Copyright 2009 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.
 */

#ifndef WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_
#define WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_

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

#include "webrtc/p2p/base/fakedtlstransport.h"
#include "webrtc/p2p/base/fakeicetransport.h"
#include "webrtc/p2p/base/transportcontroller.h"
#include "webrtc/rtc_base/bind.h"
#include "webrtc/rtc_base/sslfingerprint.h"
#include "webrtc/rtc_base/thread.h"

namespace cricket {

// Fake TransportController class, which can be passed into a WebRtcSession
// object for test purposes. Can be connected to other FakeTransportControllers
// via Connect().
//
// This fake is unusual in that for the most part, it's implemented with the
// real TransportController code, but with fake TransportChannels underneath.
class FakeTransportController : public TransportController {
 public:
  FakeTransportController()
      : TransportController(rtc::Thread::Current(),
                            rtc::Thread::Current(),
                            nullptr,
                            /*redetermine_role_on_ice_restart=*/true,
                            rtc::CryptoOptions()) {}

  explicit FakeTransportController(bool redetermine_role_on_ice_restart)
      : TransportController(rtc::Thread::Current(),
                            rtc::Thread::Current(),
                            nullptr,
                            redetermine_role_on_ice_restart,
                            rtc::CryptoOptions()) {}

  explicit FakeTransportController(IceRole role)
      : TransportController(rtc::Thread::Current(),
                            rtc::Thread::Current(),
                            nullptr,
                            /*redetermine_role_on_ice_restart=*/true,
                            rtc::CryptoOptions()) {
    SetIceRole(role);
  }

  explicit FakeTransportController(rtc::Thread* network_thread)
      : TransportController(rtc::Thread::Current(),
                            network_thread,
                            nullptr,
                            /*redetermine_role_on_ice_restart=*/true,
                            rtc::CryptoOptions()) {}

  FakeTransportController(rtc::Thread* network_thread, IceRole role)
      : TransportController(rtc::Thread::Current(),
                            network_thread,
                            nullptr,
                            /*redetermine_role_on_ice_restart=*/true,
                            rtc::CryptoOptions()) {
    SetIceRole(role);
  }

  FakeDtlsTransport* GetFakeDtlsTransport_n(const std::string& transport_name,
                                            int component) {
    return static_cast<FakeDtlsTransport*>(
        get_channel_for_testing(transport_name, component));
  }

  // Simulate the exchange of transport descriptions, and the gathering and
  // exchange of ICE candidates.
  void Connect(FakeTransportController* dest) {
    for (const std::string& transport_name : transport_names_for_testing()) {
      std::unique_ptr<rtc::SSLFingerprint> local_fingerprint;
      std::unique_ptr<rtc::SSLFingerprint> remote_fingerprint;
      if (certificate_for_testing()) {
        local_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(
            certificate_for_testing()));
      }
      if (dest->certificate_for_testing()) {
        remote_fingerprint.reset(rtc::SSLFingerprint::CreateFromCertificate(
            dest->certificate_for_testing()));
      }
      TransportDescription local_desc(
          std::vector<std::string>(),
          rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH),
          rtc::CreateRandomString(cricket::ICE_PWD_LENGTH),
          cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE,
          local_fingerprint.get());
      TransportDescription remote_desc(
          std::vector<std::string>(),
          rtc::CreateRandomString(cricket::ICE_UFRAG_LENGTH),
          rtc::CreateRandomString(cricket::ICE_PWD_LENGTH),
          cricket::ICEMODE_FULL, cricket::CONNECTIONROLE_NONE,
          remote_fingerprint.get());
      std::string err;
      SetLocalTransportDescription(transport_name, local_desc,
                                   cricket::CA_OFFER, &err);
      dest->SetRemoteTransportDescription(transport_name, local_desc,
                                          cricket::CA_OFFER, &err);
      dest->SetLocalTransportDescription(transport_name, remote_desc,
                                         cricket::CA_ANSWER, &err);
      SetRemoteTransportDescription(transport_name, remote_desc,
                                    cricket::CA_ANSWER, &err);
    }
    MaybeStartGathering();
    dest->MaybeStartGathering();
    network_thread()->Invoke<void>(
        RTC_FROM_HERE,
        rtc::Bind(&FakeTransportController::SetChannelDestinations_n, this,
                  dest));
  }

  void DestroyRtcpTransport(const std::string& transport_name) {
    DestroyDtlsTransport_n(transport_name,
                           cricket::ICE_CANDIDATE_COMPONENT_RTCP);
  }

 protected:
  IceTransportInternal* CreateIceTransportChannel_n(
      const std::string& transport_name,
      int component) override {
    return new FakeIceTransport(transport_name, component);
  }

  DtlsTransportInternal* CreateDtlsTransportChannel_n(
      const std::string& transport_name,
      int component,
      IceTransportInternal* ice) override {
    return new FakeDtlsTransport(static_cast<FakeIceTransport*>(ice));
  }

 private:
  void SetChannelDestinations_n(FakeTransportController* dest) {
    for (DtlsTransportInternal* tc : channels_for_testing()) {
      FakeDtlsTransport* local = static_cast<FakeDtlsTransport*>(tc);
      FakeDtlsTransport* remote = dest->GetFakeDtlsTransport_n(
          local->transport_name(), local->component());
      if (remote) {
        bool asymmetric = false;
        local->SetDestination(remote, asymmetric);
      }
    }
  }
};

}  // namespace cricket

#endif  // WEBRTC_P2P_BASE_FAKETRANSPORTCONTROLLER_H_
