// 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 <fidl/test/compatibility/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/zx/channel.h>
#include <src/lib/fxl/logging.h>
#include <zircon/types.h>

#include <cstdlib>
#include <string>

#include "garnet/public/lib/fidl/compatibility_test/echo_client_app.h"

namespace fidl {
namespace test {
namespace compatibility {

class EchoServerApp : public Echo {
 public:
  explicit EchoServerApp(async::Loop* loop)
      : loop_(loop), context_(sys::ComponentContext::Create()) {
    context_->outgoing()->AddPublicService(bindings_.GetHandler(this));
  }

  ~EchoServerApp() {}

  void EchoStruct(Struct value, std::string forward_to_server,
                  EchoStructCallback callback) override {
    if (!forward_to_server.empty()) {
      EchoClientApp app;
      bool failed = false;
      app.echo().set_error_handler(
          [this, &forward_to_server, &failed](zx_status_t status) {
            failed = true;
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app.Start(forward_to_server);
      bool called_back = false;
      app.echo()->EchoStruct(std::move(value), "",
                             [this, &called_back, &callback](Struct resp) {
                               called_back = true;
                               callback(std::move(resp));
                               loop_->Quit();
                             });
      while (!called_back && !failed) {
        loop_->Run();
      }
      loop_->ResetQuit();
    } else {
      callback(std::move(value));
    }
  }

  void EchoStructNoRetVal(Struct value,
                          std::string forward_to_server) override {
    if (!forward_to_server.empty()) {
      std::unique_ptr<EchoClientApp> app(new EchoClientApp);
      app->echo().set_error_handler(
          [this, &forward_to_server](zx_status_t status) {
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app->Start(forward_to_server);
      app->echo().events().EchoEvent = [this](Struct resp) {
        this->HandleEchoEvent(std::move(resp));
      };
      app->echo()->EchoStructNoRetVal(std::move(value), "");
      client_apps_.push_back(std::move(app));
    } else {
      for (const auto& binding : bindings_.bindings()) {
        Struct to_send;
        value.Clone(&to_send);
        binding->events().EchoEvent(std::move(to_send));
      }
    }
  }

  void EchoArrays(ArraysStruct value, std::string forward_to_server,
                  EchoArraysCallback callback) override {
    if (!forward_to_server.empty()) {
      EchoClientApp app;
      bool failed = false;
      app.echo().set_error_handler(
          [this, &forward_to_server, &failed](zx_status_t status) {
            failed = true;
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app.Start(forward_to_server);
      bool called_back = false;
      app.echo()->EchoArrays(
          std::move(value), "",
          [this, &called_back, &callback](ArraysStruct resp) {
            called_back = true;
            callback(std::move(resp));
            loop_->Quit();
          });
      while (!called_back && !failed) {
        loop_->Run();
      }
      loop_->ResetQuit();
    } else {
      callback(std::move(value));
    }
  }

  void EchoVectors(VectorsStruct value, std::string forward_to_server,
                   EchoVectorsCallback callback) override {
    if (!forward_to_server.empty()) {
      EchoClientApp app;
      bool failed = false;
      app.echo().set_error_handler(
          [this, &forward_to_server, &failed](zx_status_t status) {
            failed = true;
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app.Start(forward_to_server);
      bool called_back = false;
      app.echo()->EchoVectors(
          std::move(value), "",
          [this, &called_back, &callback](VectorsStruct resp) {
            called_back = true;
            callback(std::move(resp));
            loop_->Quit();
          });
      while (!called_back && !failed) {
        loop_->Run();
      }
      loop_->ResetQuit();
    } else {
      callback(std::move(value));
    }
  }

  void EchoTable(AllTypesTable value, std::string forward_to_server,
                 EchoTableCallback callback) override {
    if (!forward_to_server.empty()) {
      EchoClientApp app;
      bool failed = false;
      app.echo().set_error_handler(
          [this, &forward_to_server, &failed](zx_status_t status) {
            failed = true;
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app.Start(forward_to_server);
      bool called_back = false;
      app.echo()->EchoTable(
          std::move(value), "",
          [this, &called_back, &callback](AllTypesTable resp) {
            called_back = true;
            callback(std::move(resp));
            loop_->Quit();
          });
      while (!called_back && !failed) {
        loop_->Run();
      }
      loop_->ResetQuit();
    } else {
      callback(std::move(value));
    }
  }

  void EchoXunions(std::vector<AllTypesXunion> value,
                   std::string forward_to_server,
                   EchoXunionsCallback callback) override {
    if (!forward_to_server.empty()) {
      EchoClientApp app;
      bool failed = false;
      app.echo().set_error_handler(
          [this, &forward_to_server, &failed](zx_status_t status) {
            failed = true;
            loop_->Quit();
            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
                           << ": " << status;
          });
      app.Start(forward_to_server);
      bool called_back = false;
      app.echo()->EchoXunions(
          std::move(value), "",
          [this, &called_back, &callback](std::vector<AllTypesXunion> resp) {
            called_back = true;
            callback(std::move(resp));
            loop_->Quit();
          });
      while (!called_back && !failed) {
        loop_->Run();
      }
      loop_->ResetQuit();
    } else {
      callback(std::move(value));
    }
  }

 private:
  void HandleEchoEvent(Struct value) {
    for (const auto& binding : bindings_.bindings()) {
      Struct to_send;
      value.Clone(&to_send);
      binding->events().EchoEvent(std::move(to_send));
    }
  }

  EchoPtr server_ptr;
  EchoServerApp(const EchoServerApp&) = delete;
  EchoServerApp& operator=(const EchoServerApp&) = delete;

  async::Loop* loop_;
  std::unique_ptr<sys::ComponentContext> context_;
  fidl::BindingSet<Echo> bindings_;
  std::vector<std::unique_ptr<EchoClientApp>> client_apps_;
};

}  // namespace compatibility
}  // namespace test
}  // namespace fidl

int main(int argc, const char** argv) {
  // The FIDL support lib requires async_get_default_dispatcher() to return
  // non-null.
  async::Loop loop(&kAsyncLoopConfigAttachToThread);

  fidl::test::compatibility::EchoServerApp app(&loop);
  loop.Run();
  return EXIT_SUCCESS;
}
