// Copyright 2024 The Cobalt Authors. All Rights Reserved.
//
// 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 "starboard/linux/shared/platform_service.h"

#include <map>
#include <memory>
#include <string>

#include "starboard/common/log.h"
#include "starboard/common/string.h"
#include "starboard/configuration.h"
#include "starboard/linux/shared/pre_app_recommendation_service.h"
#include "starboard/linux/shared/soft_mic_platform_service.h"
#include "starboard/shared/starboard/application.h"
#if SB_IS(EVERGREEN_COMPATIBLE)
#include "starboard/elf_loader/evergreen_config.h"
#endif  // SB_IS(EVERGREEN_COMPATIBLE)

// Omit namespace linux due to symbol name conflict.
namespace starboard {
namespace shared {

namespace {

struct cmp_str {
  bool operator()(char const* a, char const* b) const {
    return std::strcmp(a, b) < 0;
  }
};

std::map<const char*, const void* (*)(), cmp_str> platform_service_registry = {
    {kSoftMicPlatformServiceName, GetSoftMicPlatformServiceApi},
    {kPreappRecommendationServiceName, GetPreappRecommendationServiceApi}};

bool Has(const char* name) {
  // Checks whether Cobalt platform service registry has service name
  // registered.
  if (platform_service_registry.find(name) == platform_service_registry.end()) {
    SB_LOG(ERROR) << "service name isn't registered: " << name;
    return false;
  }

  const CobaltPlatformServiceApi* api =
      reinterpret_cast<const CobaltPlatformServiceApi*>(
          platform_service_registry.at(name)());

  return api->Has(name);
}

CobaltExtensionPlatformService Open(void* context,
                                    const char* name,
                                    ReceiveMessageCallback receive_callback) {
  SB_DCHECK(context);

  CobaltExtensionPlatformService service;

  if (!Has(name)) {
    SB_LOG(ERROR) << "Open() failed in service: " << name;
    service = kCobaltExtensionPlatformServiceInvalid;
  } else {
    const CobaltPlatformServiceApi* api =
        reinterpret_cast<const CobaltPlatformServiceApi*>(
            platform_service_registry.at(name)());

    service = new CobaltExtensionPlatformServicePrivate(
        {context, receive_callback, (std::string)name});

    service->platform_service_impl = std::unique_ptr<PlatformServiceImpl>(
        api->Open(context, receive_callback));
    SB_LOG(INFO) << "Open() created service: " << name;
  }

#if SB_IS(EVERGREEN_COMPATIBLE)
  const bool is_evergreen = elf_loader::EvergreenConfig::GetInstance() != NULL;
#else
  const bool is_evergreen = false;
#endif  // SB_IS(EVERGREEN_COMPATIBLE)

  // The name parameter memory is allocated in h5vcc_platform_service::Open()
  // with new[] and must be deallocated here.
  // If we are in an Evergreen build, the name parameter must be deallocated
  // with free (), since new[] will map to malloc()
  // in an Evergreen build.
  if (is_evergreen) {
    free((void*)name);  // NOLINT
  } else {
    delete[] name;
  }

  return service;
}

void Close(CobaltExtensionPlatformService service) {
  SB_LOG(INFO) << "Close() Service.";

  const CobaltPlatformServiceApi* api =
      reinterpret_cast<const CobaltPlatformServiceApi*>(
          platform_service_registry.at(service->name.c_str())());
  api->Close(service->platform_service_impl.get());

  delete static_cast<CobaltExtensionPlatformServicePrivate*>(service);
}
void* Send(CobaltExtensionPlatformService service,
           void* data,
           uint64_t length,
           uint64_t* output_length,
           bool* invalid_state) {
  SB_DCHECK(service);
  SB_DCHECK(output_length);

  const CobaltPlatformServiceApi* api =
      reinterpret_cast<const CobaltPlatformServiceApi*>(
          platform_service_registry.at(service->name.c_str())());
  return api->Send(service->platform_service_impl.get(), data, length,
                   output_length, invalid_state);
}

const CobaltExtensionPlatformServiceApi kPlatformServiceApi = {
    kCobaltExtensionPlatformServiceName,
    1,  // API version that's implemented.
    &Has,
    &Open,
    &Close,
    &Send};

}  // namespace

const void* GetPlatformServiceApi() {
  return &kPlatformServiceApi;
}

}  // namespace shared
}  // namespace starboard
