/*
 * Copyright (C) 2021 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.
 */

#define LOG_TAG "NeuralNetworksShim"

#include "NeuralNetworksShim.h"

#include <android-base/logging.h>
#include <nnapi/Types.h>

#include <limits>
#include <string>
#include <utility>
#include <vector>

#include "ShimDevice.h"
#include "ShimDeviceManager.h"

static_assert(offsetof(NnApiSLDriverImplFL5, base.implFeatureLevel) == 0,
              ".base.implFeatureLevel is not at offset 0 of a NnApiSLDriverImplFL5 struct");
static_assert(offsetof(NnApiSLDriverImpl, implFeatureLevel) == 0,
              ".implFeatureLevel is not at offset 0 of a NnApiSLDriverImpl struct");

static_assert(sizeof(NnApiSLDriverImpl) == sizeof(int64_t), "NnApiSLDriverImpl size changed");

// 71 real ones and 1 synthetic placeholder to algin to 8 bytes on 32 bit archs
static_assert(sizeof(NnApiSLDriverImplFL5) == sizeof(int64_t) + 78 * sizeof(void*),
              "NnApiSLDriverImplFL5 size changed");

static_assert(ANNSHIM_NO_ERROR == 0, "ANNSHIM_NO_ERROR has changed");
static_assert(ANNSHIM_FAILED_TO_LOAD_SL == 1, "ANNSHIM_FAILED_TO_LOAD_SL has changed");
static_assert(ANNSHIM_FAILED_TO_REGISTER_SERVICE == 2,
              "ANNSHIM_FAILED_TO_REGISTER_SERVICE has changed");
static_assert(ANNSHIM_GENERAL_ERROR == 3, "ANNSHIM_GENERAL_ERROR has changed");
static_assert(ANNSHIM_INVALID_ARGUMENT == 4, "ANNSHIM_INVALID_ARGUMENT has changed");

using android::neuralnetworks::shim::registerDevices;
using android::neuralnetworks::shim::RegistrationParams;
using android::neuralnetworks::shim::ShimDeviceInfo;

int ANeuralNetworksShim_registerSupportLibraryService(
        const ANeuralNetworksShimRegistrationParams* registrationParams) {
    if (registrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, registrationParams == nullptr ";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    const auto* params = reinterpret_cast<const RegistrationParams*>(registrationParams);

    NnApiSLDriverImpl* const nnapiImpl = params->nnapiSupportLibraryPackage;
    const auto& deviceInfos = params->deviceInfos;
    const uint32_t numberOfListenerThreads = params->numberOfListenerThreads;
    const bool registerAsLazyService = params->registerAsLazyService;
    const bool fallbackToMinimumSupportDevice = params->fallbackToMinimumSupportDevice;

    return static_cast<int>(registerDevices(nnapiImpl, deviceInfos, numberOfListenerThreads,
                                            registerAsLazyService, fallbackToMinimumSupportDevice));
}

int ANeuralNetworksShimDeviceInfo_create(ANeuralNetworksShimDeviceInfo** deviceInfo,
                                         const char* deviceName, const char* serviceName) {
    if (deviceInfo != nullptr) {
        *deviceInfo = nullptr;
    }

    if (deviceName == nullptr) {
        LOG(ERROR) << "Invalid arguments, deviceName passed a nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }

    auto result = new (std::nothrow)
            ShimDeviceInfo{.deviceName = std::string(deviceName),
                           .serviceName = (serviceName == nullptr || strlen(serviceName) == 0)
                                                  ? std::string(deviceName)
                                                  : std::string(serviceName)};
    if (result == nullptr) {
        return ANNSHIM_GENERAL_ERROR;
    }
    *deviceInfo = reinterpret_cast<ANeuralNetworksShimDeviceInfo*>(result);
    return ANNSHIM_NO_ERROR;
}

void ANeuralNetworksShimDeviceInfo_free(ANeuralNetworksShimDeviceInfo* deviceInfo) {
    delete reinterpret_cast<ShimDeviceInfo*>(deviceInfo);
}

int ANeuralNetworksShimRegistrationParams_create(
        NnApiSLDriverImpl* nnapiSupportLibraryPackage,
        ANeuralNetworksShimRegistrationParams** outRegistrationParams) {
    if (outRegistrationParams != nullptr) {
        *outRegistrationParams = nullptr;
    }

    if (nnapiSupportLibraryPackage == nullptr) {
        LOG(ERROR) << "Invalid arguments, nnapiSupportLibraryPackage == nullptr ";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    if (outRegistrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, outRegistrationParams == nullptr ";
        return ANNSHIM_INVALID_ARGUMENT;
    }

    auto result = new (std::nothrow) RegistrationParams{
            .nnapiSupportLibraryPackage = nnapiSupportLibraryPackage,
            .registerAsLazyService = false,
            .fallbackToMinimumSupportDevice = false,
    };
    if (result == nullptr) {
        return ANNSHIM_GENERAL_ERROR;
    }
    *outRegistrationParams = reinterpret_cast<ANeuralNetworksShimRegistrationParams*>(result);
    return ANNSHIM_NO_ERROR;
}

void ANeuralNetworksShimRegistrationParams_free(
        ANeuralNetworksShimRegistrationParams* registrationParams) {
    delete reinterpret_cast<RegistrationParams*>(registrationParams);
}

int ANeuralNetworksShimRegistrationParams_addDeviceInfo(
        ANeuralNetworksShimRegistrationParams* registrationParams,
        const ANeuralNetworksShimDeviceInfo* deviceInfo) {
    if (registrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    if (deviceInfo == nullptr) {
        LOG(ERROR) << "Invalid arguments, deviceInfo == nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }

    auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
    auto info = reinterpret_cast<const ShimDeviceInfo*>(deviceInfo);
    params->deviceInfos.push_back(*info);
    return ANNSHIM_NO_ERROR;
}

int ANeuralNetworksShimRegistrationParams_setNumberOfListenerThreads(
        ANeuralNetworksShimRegistrationParams* registrationParams,
        uint32_t numberOfListenerThreads) {
    if (registrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    if (registrationParams == 0) {
        LOG(ERROR) << "Invalid arguments, numberOfListenerThreads == 0";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
    params->numberOfListenerThreads = numberOfListenerThreads;
    return ANNSHIM_NO_ERROR;
}

int ANeuralNetworksShimRegistrationParams_registerAsLazyService(
        ANeuralNetworksShimRegistrationParams* registrationParams, bool asLazy) {
    if (registrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
    params->registerAsLazyService = asLazy;
    return ANNSHIM_NO_ERROR;
}

int ANeuralNetworksShimRegistrationParams_fallbackToMinimumSupportDevice(
        ANeuralNetworksShimRegistrationParams* registrationParams, bool fallback) {
    if (registrationParams == nullptr) {
        LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
        return ANNSHIM_INVALID_ARGUMENT;
    }
    auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
    params->fallbackToMinimumSupportDevice = fallback;
    return ANNSHIM_NO_ERROR;
}
