/*
 * Copyright (C) 2018 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 <android/hardware/camera/device/3.2/types.h>
#include <cutils/properties.h>
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>

#include <aidl/AidlUtils.h>
#include <hidl/AidlCameraDeviceCallbacks.h>
#include <hidl/HidlCameraDeviceUser.h>
#include <hidl/Utils.h>
#include <android/hardware/camera/device/3.2/types.h>
#include <android-base/properties.h>

namespace android {
namespace frameworks {
namespace cameraservice {
namespace device {
namespace V2_1 {
namespace implementation {

using hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
using hardware::cameraservice::utils::conversion::convertToHidl;
using hardware::cameraservice::utils::conversion::convertFromHidl;
using hardware::cameraservice::utils::conversion::B2HStatus;

using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
using hardware::hidl_vec;
using hardware::Return;
using hardware::Void;
using HSubmitInfo = device::V2_0::SubmitInfo;
using hardware::camera2::params::OutputConfiguration;
using hardware::camera2::params::SessionConfiguration;

static constexpr int32_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;
static constexpr int32_t CAMERA_RESULT_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;

Return<void> HidlCameraDeviceUser::disconnect() {
    mDeviceRemote->disconnect();
    return Void();
}

HidlCameraDeviceUser::HidlCameraDeviceUser(
    const sp<hardware::camera2::ICameraDeviceUser> &deviceRemote)
  : mDeviceRemote(deviceRemote) {
    mInitSuccess = initDevice();
    mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
}

bool HidlCameraDeviceUser::initDevice() {
    // TODO: Get request and result metadata queue size from a system property.
    int32_t reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE;

    mCaptureRequestMetadataQueue =
        std::make_unique<CaptureRequestMetadataQueue>(static_cast<size_t>(reqFMQSize),
                                                      false /* non blocking */);
    if (!mCaptureRequestMetadataQueue->isValid()) {
        ALOGE("%s: invalid request fmq", __FUNCTION__);
        return false;
    }

    int32_t resFMQSize = CAMERA_RESULT_METADATA_QUEUE_SIZE;
    mCaptureResultMetadataQueue =
        std::make_shared<CaptureResultMetadataQueue>(static_cast<size_t>(resFMQSize),
                                                     false /* non blocking */);
    if (!mCaptureResultMetadataQueue->isValid()) {
        ALOGE("%s: invalid result fmq", __FUNCTION__);
        return false;
    }
    return true;
}

Return<void> HidlCameraDeviceUser::getCaptureRequestMetadataQueue(
    getCaptureRequestMetadataQueue_cb _hidl_cb) {
    if (mInitSuccess) {
        _hidl_cb(*mCaptureRequestMetadataQueue->getDesc());
    }
    return Void();
}

Return<void> HidlCameraDeviceUser::getCaptureResultMetadataQueue(
    getCaptureResultMetadataQueue_cb _hidl_cb) {
    if (mInitSuccess) {
        _hidl_cb(*mCaptureResultMetadataQueue->getDesc());
    }
    return Void();
}

/**
 * To be used only by submitRequestList implementation, since it requires
 * clients to call this method serially, incase fmq is used to send metadata.
 */
bool HidlCameraDeviceUser::copyPhysicalCameraSettings(
    const hidl_vec<HPhysicalCameraSettings> &hPhysicalCameraSettings,
    std::vector<CaptureRequest::PhysicalCameraSettings> *physicalCameraSettings) {
    bool converted = false;
    for (auto &e : hPhysicalCameraSettings) {
        physicalCameraSettings->emplace_back();
        CaptureRequest::PhysicalCameraSettings &physicalCameraSetting =
            physicalCameraSettings->back();
        physicalCameraSetting.id = e.id;

        // Read the settings either from the fmq or straightaway from the
        // request. We don't need any synchronization, since submitRequestList
        // is guaranteed to be called serially by the client if it decides to
        // use fmq.
        if (e.settings.getDiscriminator() ==
            V2_0::FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
            /**
             * Get settings from the fmq.
             */
            HCameraMetadata settingsFmq;
            settingsFmq.resize(e.settings.fmqMetadataSize());
            bool read = mCaptureRequestMetadataQueue->read(settingsFmq.data(),
                                                           e.settings.fmqMetadataSize());
            if (!read) {
                ALOGE("%s capture request settings could't be read from fmq size",
                      __FUNCTION__);
                converted = false;
            } else {
                converted = convertFromHidl(settingsFmq, &physicalCameraSetting.settings);
            }
        } else {
            /**
             * The settings metadata is contained in request settings field.
             */
            converted =
                convertFromHidl(e.settings.metadata(),
                                &physicalCameraSetting.settings);
        }
        if (!converted) {
          ALOGE("%s: Unable to convert physicalCameraSettings from HIDL to AIDL.", __FUNCTION__);
          return false;
        }
    }
    return true;
}

bool HidlCameraDeviceUser::convertRequestFromHidl(const HCaptureRequest &hRequest,
                                                  CaptureRequest *request) {
    // No reprocessing support.
    request->mIsReprocess = false;
    for (const auto &streamAndWindowId : hRequest.streamAndWindowIds) {
        request->mStreamIdxList.push_back(streamAndWindowId.streamId);
        request->mSurfaceIdxList.push_back(streamAndWindowId.windowId);
    }
    return copyPhysicalCameraSettings(hRequest.physicalCameraSettings,
                                      &(request->mPhysicalCameraSettings));
}

Return<void> HidlCameraDeviceUser::submitRequestList(const hidl_vec<HCaptureRequest>& hRequestList,
                                                     bool streaming,
                                                     submitRequestList_cb _hidl_cb) {
    hardware::camera2::utils::SubmitInfo submitInfo;
    HSubmitInfo hSubmitInfo;
    /**
     * Create AIDL CaptureRequest from requestList and graphicBufferProducers.
     */
    std::vector<hardware::camera2::CaptureRequest> requests;
    for (auto &hRequest : hRequestList) {
        requests.emplace_back();
        auto &request = requests.back();
        if (!convertRequestFromHidl(hRequest, &request)) {
            _hidl_cb(HStatus::ILLEGAL_ARGUMENT, hSubmitInfo);
            return Void();
        }
    }
    mDeviceRemote->submitRequestList(requests, streaming, &submitInfo);
    mRequestId = submitInfo.mRequestId;
    convertToHidl(submitInfo, &hSubmitInfo);
    _hidl_cb(HStatus::NO_ERROR, hSubmitInfo);
    return Void();
}

Return<void> HidlCameraDeviceUser::cancelRepeatingRequest(cancelRepeatingRequest_cb _hidl_cb) {
    int64_t lastFrameNumber = 0;
    binder::Status ret = mDeviceRemote->cancelRequest(mRequestId, &lastFrameNumber);
    _hidl_cb(B2HStatus(ret), lastFrameNumber);
    return Void();
}

Return<HStatus> HidlCameraDeviceUser::beginConfigure() {
    binder::Status ret = mDeviceRemote->beginConfigure();
    return B2HStatus(ret);
}

Return<HStatus> HidlCameraDeviceUser::endConfigure(StreamConfigurationMode operatingMode,
                                                   const hidl_vec<uint8_t>& sessionParams) {
    return endConfigure_2_1(operatingMode, sessionParams, systemTime());
}

Return<HStatus> HidlCameraDeviceUser::endConfigure_2_1(StreamConfigurationMode operatingMode,
                                                   const hidl_vec<uint8_t>& sessionParams,
                                                   nsecs_t startTimeNs) {
    android::CameraMetadata cameraMetadata;
    if (!convertFromHidl(sessionParams, &cameraMetadata)) {
        return HStatus::ILLEGAL_ARGUMENT;
    }

    std::vector<int> offlineStreamIds;
    binder::Status ret = mDeviceRemote->endConfigure(convertFromHidl(operatingMode),
                                                     cameraMetadata, ns2ms(startTimeNs),
                                                     &offlineStreamIds);
    return B2HStatus(ret);
}

Return<HStatus> HidlCameraDeviceUser::deleteStream(int32_t streamId) {
    binder::Status ret = mDeviceRemote->deleteStream(streamId);
    return B2HStatus(ret);
}

Return<void> HidlCameraDeviceUser::createStream(const HOutputConfiguration& hOutputConfiguration,
                                                createStream_cb hidl_cb_) {
    OutputConfiguration outputConfiguration =
        convertFromHidl(hOutputConfiguration);
    int32_t newStreamId = 0;
    binder::Status ret = mDeviceRemote->createStream(outputConfiguration, &newStreamId);
    HStatus status = B2HStatus(ret);
    hidl_cb_(status, newStreamId);
    return Void();
}

Return<void> HidlCameraDeviceUser::createDefaultRequest(TemplateId templateId,
                                                        createDefaultRequest_cb _hidl_cb) {
    android::CameraMetadata cameraMetadata;
    binder::Status ret = mDeviceRemote->createDefaultRequest(convertFromHidl(templateId),
                                                             &cameraMetadata);

    HCameraMetadata hidlMetadata;
    if (filterVndkKeys(mVndkVersion, cameraMetadata, /*isStatic*/false) != OK) {
        ALOGE("%s: Unable to filter vndk metadata keys for version %d",
              __FUNCTION__, mVndkVersion);
        _hidl_cb(HStatus::UNKNOWN_ERROR, hidlMetadata);
        return Void();
    }

    HStatus hStatus = B2HStatus(ret);
    const camera_metadata_t *rawMetadata = cameraMetadata.getAndLock();
    convertToHidl(rawMetadata, &hidlMetadata);
    _hidl_cb(hStatus, hidlMetadata);
    cameraMetadata.unlock(rawMetadata);
    return Void();
}

Return<HStatus> HidlCameraDeviceUser::waitUntilIdle() {
    binder::Status ret = mDeviceRemote->waitUntilIdle();
    return B2HStatus(ret);
}

Return<void> HidlCameraDeviceUser::flush(flush_cb _hidl_cb) {
    int64_t lastFrameNumber = 0;
    binder::Status ret = mDeviceRemote->flush(&lastFrameNumber);
    _hidl_cb(B2HStatus(ret),lastFrameNumber);
    return Void();
}

Return<HStatus> HidlCameraDeviceUser::updateOutputConfiguration(
    int32_t streamId,
    const HOutputConfiguration& hOutputConfiguration) {
    OutputConfiguration outputConfiguration = convertFromHidl(hOutputConfiguration);
    binder::Status ret = mDeviceRemote->updateOutputConfiguration(streamId, outputConfiguration);
    return B2HStatus(ret);
}

Return<void> HidlCameraDeviceUser::isSessionConfigurationSupported(
    const HSessionConfiguration& hSessionConfiguration,
    isSessionConfigurationSupported_cb _hidl_cb) {
    bool supported = false;
    SessionConfiguration sessionConfiguration = convertFromHidl(hSessionConfiguration);
    binder::Status ret = mDeviceRemote->isSessionConfigurationSupported(
            sessionConfiguration, &supported);
    HStatus status = B2HStatus(ret);
    _hidl_cb(status, supported);
    return Void();
}

} // implementation
} // V2_0
} // device
} // cameraservice
} // frameworks
} // android
