/*
 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
 * 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 "kits/native/include/camera/metadata_output.h"
#include "impl/metadata_output_impl.h"
#include "camera_log.h"
#include "hilog/log.h"
#include "impl/camera_manager_impl.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @since 11
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_RegisterCallback(Camera_MetadataOutput* metadataOutput,
    MetadataOutput_Callbacks* callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    CHECK_RETURN_RET_ELOG(callback->onMetadataObjectAvailable == nullptr, CAMERA_INVALID_ARGUMENT,
        "Invalid argument, callback onMetadataObjectAvailable is null!");
    CHECK_RETURN_RET_ELOG(
        callback->onError == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback onError is null!");

    metadataOutput->RegisterCallback(callback);
    return CAMERA_OK;
}

/**
 * @since 11
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_UnregisterCallback(Camera_MetadataOutput* metadataOutput,
    MetadataOutput_Callbacks* callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, previewOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    CHECK_RETURN_RET_ELOG(callback->onMetadataObjectAvailable == nullptr, CAMERA_INVALID_ARGUMENT,
        "Invalid argument, callback onMetadataObjectAvailable is null!");
    CHECK_RETURN_RET_ELOG(
        callback->onError == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback onError is null!");

    metadataOutput->UnregisterCallback(callback);
    return CAMERA_OK;
}

/**
 * @since 11
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_Start(Camera_MetadataOutput* metadataOutput)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");

    return metadataOutput->Start();
}

/**
 * @since 11
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_Stop(Camera_MetadataOutput* metadataOutput)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");

    return metadataOutput->Stop();
}

/**
 * @since 11
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_Release(Camera_MetadataOutput* metadataOutput)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");

    Camera_ErrorCode retCode = metadataOutput->Release();
    if (metadataOutput != nullptr) {
        delete metadataOutput;
    }
    return retCode;
}

/**
 * @since 23
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_AddMetadataObjectTypes(Camera_MetadataOutput* metadataOutput,
    Camera_MetadataObjectType* types, uint32_t size)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(
        types == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, types is null!");
    CHECK_RETURN_RET_ELOG(
        size == 0, CAMERA_INVALID_ARGUMENT, "Invalid argument, size is 0!");

    const int32_t minTypeValue = 0;
    const int32_t maxTypeValue = 8;
    for (uint32_t i = 0; i < size; i++) {
        CHECK_RETURN_RET_ELOG(static_cast<int32_t>(types[i]) < minTypeValue
                              || static_cast<int32_t>(types[i]) > maxTypeValue,
                              CAMERA_INVALID_ARGUMENT,
                              "Invalid argument, metadataObjectTypes need to be 0 - 8");
    }
    MEDIA_DEBUG_LOG("OH_MetadataOutput_AddMetadataObjectTypes"); 
    Camera_ErrorCode retCode = metadataOutput->AddMetadataObjectTypes(types, size);
    return retCode;
}

/**
 * @since 23
 * @version 1.0
 */
Camera_ErrorCode OH_MetadataOutput_RemoveMetadataObjectTypes(Camera_MetadataOutput* metadataOutput, 
    Camera_MetadataObjectType* types, uint32_t size)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    MEDIA_DEBUG_LOG("OH_MetadataOutput_RemoveMetadataObjectTypes"); 
    CHECK_RETURN_RET_ELOG(
        types == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, types is null!");
    CHECK_RETURN_RET_ELOG(
        size == 0, CAMERA_INVALID_ARGUMENT, "Invalid argument, size is 0!");

    const int32_t minTypeValue = 0;
    const int32_t maxTypeValue = 8;
    for (uint32_t i = 0; i < size; i++) {
        CHECK_RETURN_RET_ELOG(static_cast<int32_t>(types[i]) < minTypeValue
                              || static_cast<int32_t>(types[i]) > maxTypeValue,
                              CAMERA_INVALID_ARGUMENT,
                              "Invalid argument, metadataObjectTypes need to be 0 - 8");
    }
    Camera_ErrorCode retCode = metadataOutput->RemoveMetadataObjectTypes(types, size);
    return retCode;
}

bool OH_MetadataOutput_IsLockMetadataObjectTrackingSupported(
    const Camera_MetadataOutput* metadataOutput)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, false, "Invalid argument, metadataOutput is null!");

    return metadataOutput->IsLockMetadataObjectTrackingSupported();
}


Camera_ErrorCode OH_MetadataOutput_LockMetadataObjectTracking(
    Camera_MetadataOutput* metadataOutput, Camera_Point* pointOfInterest)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(
        pointOfInterest == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, pointOfInterest is null!");

    return metadataOutput->LockMetadataObjectTracking(pointOfInterest);
}

Camera_ErrorCode OH_MetadataOutput_UnlockMetadataObjectTracking(
    Camera_MetadataOutput* metadataOutput)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");

    return metadataOutput->UnlockMetadataObjectTracking();
}

Camera_ErrorCode OH_MetadataOutput_RegisterMetadataObjectExtAvailableCallback(Camera_MetadataOutput* metadataOutput,
    void* context, OH_MetadataOutput_OnMetadataObjectExtAvailable callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    return metadataOutput->RegisterMetadataObjectExtAvailableCallback(context, callback);
}

Camera_ErrorCode OH_MetadataOutput_UnregisterMetadataObjectExtAvailableCallback(Camera_MetadataOutput* metadataOutput,
    void* context, OH_MetadataOutput_OnMetadataObjectExtAvailable callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    return metadataOutput->UnregisterMetadataObjectExtAvailableCallback(context, callback);
}

Camera_ErrorCode OH_MetadataOutput_RegisterErrorExtCallback(Camera_MetadataOutput* metadataOutput,
    void* context, OH_MetadataOutput_OnErrorExt callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    return metadataOutput->RegisterErrorCallback(context, callback);
}

Camera_ErrorCode OH_MetadataOutput_UnregisterErrorExtCallback(Camera_MetadataOutput* metadataOutput,
    void* context, OH_MetadataOutput_OnErrorExt callback)
{
    CHECK_RETURN_RET_ELOG(
        metadataOutput == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, metadataOutput is null!");
    CHECK_RETURN_RET_ELOG(callback == nullptr, CAMERA_INVALID_ARGUMENT, "Invalid argument, callback is null!");
    return metadataOutput->UnregisterErrorCallback(context, callback);
}

#ifdef __cplusplus
}
#endif