// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "network.h"

#include <src/lib/fxl/memory/weak_ptr.h>

#include "fake_endpoint.h"
#include "interceptors/latency.h"
#include "interceptors/packet_loss.h"
#include "interceptors/reorder.h"
#include "network_context.h"

namespace netemul {
namespace impl {

class NetworkBus : public data::BusConsumer {
 public:
  NetworkBus() : weak_ptr_factory_(this) {}
  ~NetworkBus() override = default;

  decltype(auto) GetPointer() { return weak_ptr_factory_.GetWeakPtr(); }

  void Consume(const void* data, size_t len,
               const data::Consumer::Ptr& sender) override {
    if (interceptors_.empty()) {
      ForwardData(data, len, sender);
    } else {
      interceptors_.back()->Intercept(InterceptPacket(data, len, sender));
    }
  }

  std::vector<data::Consumer::Ptr>& sinks() { return sinks_; }
  std::vector<FakeEndpoint::Ptr>& fake_endpoints() { return fake_endpoints_; }

  void UpdateConfiguration(const Network::Config& config) {
    // first, flush all packets that are currently in interceptors:
    for (auto& i : interceptors_) {
      auto packets = i->Flush();
      for (auto& packet : packets) {
        ForwardData(packet.data().data(), packet.data().size(),
                    packet.origin());
      }
    }
    // clear all interceptors
    interceptors_.clear();

    // rebuild interceptors based on configuration

    // reordering interceptor:
    if (config.has_reorder()) {
      interceptors_.emplace_back(new interceptor::Reorder(
          config.reorder().store_buff, zx::msec(config.reorder().tick),
          MakeInterceptorCallback()));
    }
    // latency interceptor:
    if (config.has_latency()) {
      interceptors_.emplace_back(new interceptor::Latency(
          config.latency().average, config.latency().std_dev,
          MakeInterceptorCallback()));
    }
    // packet loss interceptor:
    if (config.has_packet_loss()) {
      if (config.packet_loss().is_random_rate()) {
        interceptors_.emplace_back(new interceptor::PacketLoss(
            config.packet_loss().random_rate(), MakeInterceptorCallback()));
      }
    }
  }

 private:
  Interceptor::ForwardPacketCallback MakeInterceptorCallback() {
    if (interceptors_.empty()) {
      // if no interceptors inside just forward packet
      return [this](InterceptPacket packet) {
        ForwardData(packet.data().data(), packet.data().size(),
                    packet.origin());
      };
    } else {
      // if interceptors already have members, point onto the back for chaining
      auto* next = interceptors_.back().get();
      return [next](InterceptPacket packet) {
        next->Intercept(std::move(packet));
      };
    }
  }

  void ForwardData(const void* data, size_t len,
                   const data::Consumer::Ptr& sender) {
    for (auto i = sinks_.begin(); i != sinks_.end();) {
      if (*i) {
        if (i->get() !=
            sender.get()) {  // flood all sinks different than sender
          (*i)->Consume(data, len);
        }
        ++i;
      } else {
        // sink has been free'd, erase it
        i = sinks_.erase(i);
      }
    }
  }

  fxl::WeakPtrFactory<data::BusConsumer> weak_ptr_factory_;
  std::vector<data::Consumer::Ptr> sinks_;
  std::vector<FakeEndpoint::Ptr> fake_endpoints_;
  std::vector<std::unique_ptr<Interceptor>> interceptors_;
};

}  // namespace impl

Network::Network(NetworkContext* context, std::string name,
                 Network::Config config)
    : bus_(new impl::NetworkBus()),
      parent_(context),
      name_(std::move(name)),
      config_(std::move(config)) {
  bindings_.set_empty_set_handler([this]() {
    if (closed_callback_) {
      closed_callback_(*this);
    }
  });
  bus_->UpdateConfiguration(config_);
}

Network::~Network() = default;

void Network::Bind(fidl::InterfaceRequest<FNetwork> req) {
  bindings_.AddBinding(this, std::move(req), parent_->dispatcher());
}

void Network::GetConfig(Network::GetConfigCallback callback) {
  Config config;
  config_.Clone(&config);
  callback(std::move(config));
}

void Network::GetName(Network::GetNameCallback callback) { callback(name_); }

void Network::SetConfig(fuchsia::netemul::network::NetworkConfig config,
                        Network::SetConfigCallback callback) {
  if (!CheckConfig(config)) {
    callback(ZX_ERR_INVALID_ARGS);
    return;
  }
  config_ = std::move(config);
  bus_->UpdateConfiguration(config_);
  callback(ZX_OK);
}

zx_status_t Network::AttachEndpoint(std::string name) {
  data::Consumer::Ptr src;
  auto status = parent_->endpoint_manager().InstallSink(
      std::move(name), bus_->GetPointer(), &src);

  if (status != ZX_OK) {
    return status;
  } else if (!src) {
    return ZX_ERR_INTERNAL;
  }

  bus_->sinks().emplace_back(std::move(src));
  return ZX_OK;
}

void Network::AttachEndpoint(::std::string name,
                             Network::AttachEndpointCallback callback) {
  callback(AttachEndpoint(std::move(name)));
}

void Network::RemoveEndpoint(::std::string name,
                             Network::RemoveEndpointCallback callback) {
  data::Consumer::Ptr src;
  auto status =
      parent_->endpoint_manager().RemoveSink(name, bus_->GetPointer(), &src);
  if (status == ZX_OK && src) {
    auto& sinks = bus_->sinks();
    for (auto i = sinks.begin(); i != sinks.end(); i++) {
      if (i->get() == src.get()) {
        sinks.erase(i);
        break;
      }
    }
  }
  callback(status);
}

void Network::CreateFakeEndpoint(
    fidl::InterfaceRequest<fuchsia::netemul::network::FakeEndpoint> ep) {
  FakeEndpoint::Ptr fep = std::make_unique<FakeEndpoint>(
      bus_->GetPointer(), std::move(ep), parent_->dispatcher());

  fep->SetOnDisconnected([this](const FakeEndpoint* ep) {
    // when endpoint is disconnected for whatever reason
    // we remove it from the bus
    auto& feps = bus_->fake_endpoints();
    for (auto i = feps.begin(); i != feps.end(); i++) {
      if (i->get() == ep) {
        feps.erase(i);
        break;
      }
    }
  });

  // save the sink in bus
  bus_->sinks().emplace_back(fep->GetPointer());
  // keep and save endpoint
  bus_->fake_endpoints().emplace_back(std::move(fep));
}

void Network::SetClosedCallback(Network::ClosedCallback cb) {
  closed_callback_ = std::move(cb);
}

bool Network::CheckConfig(const Config& config) {
  if (config.has_packet_loss()) {
    if (config.packet_loss().is_random_rate()) {
      // random rate packet loss must be unsigned byte less or equal to 100
      if (config.packet_loss().random_rate() > 100) {
        return false;
      }
    } else {
      // non random-rate packet loss not supported.
      return false;
    }
  }

  return true;
}

}  // namespace netemul
