// Copyright 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "webserv_common/binder_constants.h"

#include "libwebserv/binder_request_handler.h"
#include "libwebserv/binder_server.h"
#include "libwebserv/protocol_handler.h"
#include "libwebserv/request_handler_callback.h"

#include <map>
#include <set>
#include <string>
#include <vector>

using android::sp;
using android::IBinder;
using android::binder::Status;
using android::webservd::IProtocolHandler;
using android::webservd::IRequestHandler;
using std::map;
using std::pair;
using std::set;
using std::string;
using std::unique_ptr;
using std::vector;

namespace libwebserv {

class RequestHandlerRegistration {
 public:
  RequestHandlerRegistration(const string& url,
                             const string& method,
                             unique_ptr<RequestHandlerInterface> handler)
      : url_(url),
        method_(method),
        handler_(std::move(handler)),
        binder_handler_(new BinderRequestHandler(handler_.get())) {}

  ~RequestHandlerRegistration() { DropRemotes(); }

  void AddRemote(sp<IProtocolHandler> handler) {
    string guid;

    if (!handler->AddRequestHandler(url_,
                                    method_,
                                    binder_handler_,
                                    &guid).isOk()) {
      LOG(WARNING) << "Remote protocol handler failed to "
                   << "register new request handler.";
    }

    protos_.emplace_back(handler, guid);
  }

  void DropRemotes() {
    for (auto& proto : protos_) {
      if (!proto.first->RemoveRequestHandler(proto.second).isOk()) {
        LOG(WARNING) << "Could not remove request handler from remote.";
      }
    }
  }

 private:
  string url_;
  string method_;
  unique_ptr<RequestHandlerInterface> handler_;
  sp<IRequestHandler> binder_handler_;
  vector<pair<sp<IProtocolHandler>, string>> protos_;

  DISALLOW_COPY_AND_ASSIGN(RequestHandlerRegistration);
};

// This is libwebserv's binder based process local protocol
// handler.  It wraps around a group of remote protocol handlers
// that share a common name.  It exists independently of the
// lifetime of the remote protocol handlers and is created on
// either of:
//   1) The local process requests a protocol handler by name
//   2) We connect to the remote webservd process and it has a protocol
//      handler with the given name.
class BinderProtocolHandler : public ProtocolHandler {
 public:
  explicit BinderProtocolHandler(const string& name)
      : name_(name) {}

  virtual ~BinderProtocolHandler() {
    ResetRemoteProtocolHandlers();
  }

  bool AddRemote(sp<IProtocolHandler> handler) {
    string name;
    int32_t port;
    string protocol;

    if (!handler->GetName(&name).isOk()) {
      LOG(INFO) << "Could not get name of remote protocol handler.";
      return false;
    }

    CHECK(name == name_);

    if (!handler->GetPort(&port).isOk()) {
      LOG(INFO) << "Could not get port for remote protocol handler.";
      return false;
    }

    if (!handler->GetProtocol(&protocol).isOk()) {
      LOG(INFO) << "Could not get protocol for remote protocol handler.";
      return false;
    }

    ports_.insert(uint16_t(port));
    protocols_.insert(protocol);
    remote_handlers_.push_back(handler);

    for (auto& request_handler : request_handler_ids_) {
      request_handler.second->AddRemote(handler);
    }

    return true;
  }

  int AddHandler(const string& url,
                 const string& method,
                 unique_ptr<RequestHandlerInterface> handler) override {
    unique_ptr<RequestHandlerRegistration> registration(
        new RequestHandlerRegistration(url, method, std::move(handler)));

    for (sp<IProtocolHandler> remote : remote_handlers_) {
      registration->AddRemote(remote);
    }

    int id = last_handler_id_++;

    request_handler_ids_.emplace(id, std::move(registration));

    return id;
  }

  int AddHandlerCallback(
      const string& url,
      const string& method,
      const base::Callback<RequestHandlerInterface::HandlerSignature>&
          handler_callback) override {
    std::unique_ptr<RequestHandlerInterface> handler{
        new RequestHandlerCallback{handler_callback}};
    return AddHandler(url, method, std::move(handler));
  }

  bool RemoveHandler(int handler_id) override {
    return request_handler_ids_.erase(handler_id) > 0;
  }

  void ResetRemoteProtocolHandlers() {
    for (auto& it : request_handler_ids_) {
      it.second->DropRemotes();
    }

    remote_handlers_.clear();
  }

  bool IsConnected() const override { return !remote_handlers_.empty(); }
  string GetName() const override { return name_; }
  set<uint16_t> GetPorts() const override { return ports_; }
  set<string> GetProtocols() const override { return protocols_; }

  brillo::Blob GetCertificateFingerprint() const override {
    brillo::Blob result;

    for (auto& handler : remote_handlers_) {
      Status status = handler->GetCertificateFingerprint(&result);
      if (!status.isOk()) {
        LOG(WARNING) << "Could not get certificate fingerprint "
                     << "from protocol handler: " << status.toString8();
      } else if (!result.empty()) {
        break;
      }
    }

    return result;
  }

 private:
  int last_handler_id_ = 0;
  set<uint16_t> ports_;
  set<string> protocols_;
  string name_;
  vector<sp<IProtocolHandler>> remote_handlers_;

  // Map of local handler IDs to objects containing the various bits of IPC
  // state we need to maintain those handlers on the remote end.
  map<int,unique_ptr<RequestHandlerRegistration>> request_handler_ids_;

  DISALLOW_COPY_AND_ASSIGN(BinderProtocolHandler);
};

BinderServer::BinderServer(brillo::MessageLoop* message_loop,
                           const base::Closure& on_server_online,
                           const base::Closure& on_server_offline,
                           android::BinderWrapper* binder_wrapper)
    : message_loop_{message_loop},
      on_server_online_{on_server_online},
      on_server_offline_{on_server_offline},
      binder_wrapper_{binder_wrapper} {
  message_loop_->PostTask(FROM_HERE,
                          base::Bind(&BinderServer::TryConnecting,
                                     weak_ptr_factory_.GetWeakPtr()));
}

void BinderServer::TryConnecting() {
  ClearLocalState();
  sp<IBinder> binder = binder_wrapper_->GetService(
      webservd::kWebserverBinderServiceName);
  if (!binder.get()) {
    LOG(INFO) << "Webservd has not registered with service manager.";
  } else if (!BuildLocalState(binder)) {
    ClearLocalState();
  } else {
    if (!on_server_online_.is_null()) {
        message_loop_->PostTask(FROM_HERE, on_server_online_);
    }

    // Got a binder, built up appropriate local state, our job is done.
    return;
  }
  message_loop_->PostDelayedTask(FROM_HERE,
                                 base::Bind(&BinderServer::TryConnecting,
                                            weak_ptr_factory_.GetWeakPtr()),
                                 base::TimeDelta::FromSeconds(1));
}

void BinderServer::ClearLocalState() {
  for (auto& local_handler: local_protocol_handlers_) {
    local_handler.second->ResetRemoteProtocolHandlers();
    if (!on_protocol_handler_disconnected_.is_null()) {
      message_loop_->PostTask(
          FROM_HERE, base::Bind(on_protocol_handler_disconnected_,
                                base::Unretained(local_handler.second.get())));
    }
  }

  if (remote_server_.get() && !on_server_offline_.is_null()) {
      message_loop_->PostTask(FROM_HERE, on_server_offline_);
  }
  remote_server_.clear();
}

bool BinderServer::BuildLocalState(sp<IBinder> server) {
  remote_server_ = android::interface_cast<RemoteServer>(server);
  vector<sp<IBinder>> remote_raw_binders;
  if (!remote_server_->GetProtocolHandlers("", &remote_raw_binders).isOk()) {
    // Possibly the server died, this is not necessarily an error.
    LOG(INFO) << "Webservd failed to tell us about protocol handlers.";
    return false;
  }

  // Tell the local wrappers about the remote handlers that exist now.
  for (auto& raw_binder: remote_raw_binders) {
    sp<RemoteProtocolHandler> remote_handler =
        android::interface_cast<RemoteProtocolHandler>(raw_binder);
    string name;
    if (!remote_handler->GetName(&name).isOk()) {
      LOG(INFO) << "Remote handler could not report its name.";
      return false;
    }

    auto it = local_protocol_handlers_.find(name);

    if (it == local_protocol_handlers_.end()) {
      unique_ptr<BinderProtocolHandler> local_handler(
          new BinderProtocolHandler(name));
      it = local_protocol_handlers_.emplace(name,
                                            std::move(local_handler)).first;
    }

    it->second->AddRemote(remote_handler);
    if (!on_protocol_handler_connected_.is_null()) {
      message_loop_->PostTask(FROM_HERE,
                              base::Bind(on_protocol_handler_connected_,
                                         base::Unretained(it->second.get())));
    }
  }
  return true;
}

ProtocolHandler* BinderServer::GetDefaultHttpHandler() {
  return GetProtocolHandler(ProtocolHandler::kHttp);
}

ProtocolHandler* BinderServer::GetDefaultHttpsHandler() {
  return GetProtocolHandler(ProtocolHandler::kHttps);
}

ProtocolHandler* BinderServer::GetProtocolHandler(const string& name) {
  auto it = local_protocol_handlers_.find(name);

  if (it == local_protocol_handlers_.end()) {
    unique_ptr<BinderProtocolHandler> local_handler(
        new BinderProtocolHandler(name));
    it = local_protocol_handlers_.emplace(name,
                                          std::move(local_handler)).first;
  }

  return it->second.get();
}

bool BinderServer::IsConnected() const {
  return remote_server_.get() != nullptr;
}

void BinderServer::OnProtocolHandlerConnected(
    const base::Callback<void(ProtocolHandler*)>& callback) {
  on_protocol_handler_connected_ = callback;

  for (auto& handler : local_protocol_handlers_) {
    if (handler.second->IsConnected()) {
      message_loop_->PostTask(
          FROM_HERE,
          base::Bind(callback, base::Unretained(handler.second.get())));
    }
  }
}

void BinderServer::OnProtocolHandlerDisconnected(
    const base::Callback<void(ProtocolHandler*)>& callback) {
  on_protocol_handler_disconnected_ = callback;

  for (auto& handler : local_protocol_handlers_) {
    if (!handler.second->IsConnected()) {
      message_loop_->PostTask(
          FROM_HERE,
          base::Bind(callback, base::Unretained(handler.second.get())));
    }
  }
}

base::TimeDelta BinderServer::GetDefaultRequestTimeout() const {
  int32_t timeout_seconds;
  if (!remote_server_->GetDefaultRequestTimeout(&timeout_seconds).isOk()) {
    LOG(ERROR) << "Could not get request timeout from remote server.";

    // Precedent from the DBus server says this is the error return value.
    return base::TimeDelta::Max();
  }

  return base::TimeDelta::FromSeconds(timeout_seconds);
}

}  // namespace libwebserv
