/*
 * Copyright (C) 2016-2021 Intel Corporation
 *
 * 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 JpegMaker

#include "JpegMaker.h"

#include "iutils/CameraLog.h"
#include "iutils/Utils.h"

namespace icamera {

JpegMaker::JpegMaker() {
    LOG2("@%s", __func__);
    mExifMaker = std::unique_ptr<EXIFMaker>(new EXIFMaker());
}

JpegMaker::~JpegMaker() {
    LOG2("@%s", __func__);
}

status_t JpegMaker::setupExifWithMetaData(int bufWidth, int bufHeight, const Parameters& parameter,
                                          ExifMetaData* metaData) {
    LOG2("@%s", __func__);

    status_t status = OK;

    status = processJpegSettings(parameter, metaData);
    CheckAndLogError(status != OK, status, "@%s: Process settngs for JPEG failed!", __func__);

    mExifMaker->initialize(bufWidth, bufHeight);
    mExifMaker->pictureTaken(metaData);

    mExifMaker->enableFlash(metaData->flashFired, metaData->v3AeMode, metaData->flashMode);
    mExifMaker->updateSensorInfo(parameter);
    mExifMaker->saveMakernote(parameter);

    status = processExifSettings(parameter, metaData);
    if (status != OK) {
        LOGE("@%s: Process settngs for Exif! %d", __func__, status);
        return status;
    }

    mExifMaker->initializeLocation(metaData);
    mExifMaker->setSensorAeConfig(parameter);

    if (metaData->software) mExifMaker->setSoftware(metaData->software);

    return status;
}

status_t JpegMaker::getExif(const EncodePackage& thumbnailPackage, uint8_t* exifPtr,
                            uint32_t* exifSize) {
    if (thumbnailPackage.encodedDataSize > 0 && thumbnailPackage.quality > 0) {
        mExifMaker->setThumbnail(static_cast<unsigned char*>(thumbnailPackage.outputData),
                                 thumbnailPackage.encodedDataSize, thumbnailPackage.outputWidth,
                                 thumbnailPackage.outputHeight);
    }
    *exifSize = mExifMaker->makeExif(exifPtr);
    return *exifSize > 0 ? OK : UNKNOWN_ERROR;
}

status_t JpegMaker::processExifSettings(const Parameters& params, ExifMetaData* metaData) {
    LOG2("@%s:", __func__);
    status_t status = OK;

    status = processGpsSettings(params, metaData);
    status |= processColoreffectSettings(params, metaData);
    status |= processScalerCropSettings(params, metaData);

    return status;
}

/* copy exif data into output buffer */
void JpegMaker::writeExifData(EncodePackage* package) {
    CheckAndLogError(package == nullptr, VOID_VALUE, "@%s, package is nullptr", __func__);

    if (package->exifDataSize == 0) return;

    CheckAndLogError(!package->outputData, VOID_VALUE, "@%s, outputData is nullptr", __func__);
    CheckAndLogError(!package->exifData, VOID_VALUE, "@%s, exifData is nullptr", __func__);

    unsigned int jSOISize = sizeof(mJpegMarkerSOI);
    unsigned char* jpegOut = reinterpret_cast<unsigned char*>(package->outputData);
    MEMCPY_S(jpegOut, jSOISize, mJpegMarkerSOI, jSOISize);
    jpegOut += jSOISize;

    MEMCPY_S(jpegOut, package->exifDataSize, reinterpret_cast<unsigned char*>(package->exifData),
             package->exifDataSize);
}

/**
 * processJpegSettings
 *
 * Store JPEG settings to the exif metadata
 *
 * \param [IN] jpeg parameters
 * \ metaData [out] metadata of the request
 *
 */
status_t JpegMaker::processJpegSettings(const Parameters& params, ExifMetaData* metaData) {
    LOG2("@%s:", __func__);
    status_t status = OK;

    CheckAndLogError(!metaData, UNKNOWN_ERROR, "MetaData struct not intialized");

    // make jpeg with thumbnail or not
    camera_resolution_t thumbSize = {0};
    params.getJpegThumbnailSize(thumbSize);
    LOG2("%s request thumbname size %dx%d", __func__, thumbSize.width, thumbSize.height);

    uint8_t new_jpeg_quality = DEFAULT_JPEG_QUALITY;
    int ret = params.getJpegQuality(&new_jpeg_quality);
    if (ret != icamera::OK) {
        LOGW("cannot find jpeg quality, use default");
    }
    metaData->mJpegSetting.jpegQuality = new_jpeg_quality;

    uint8_t new_jpeg_thumb_quality = DEFAULT_JPEG_QUALITY;
    params.getJpegThumbnailQuality(&new_jpeg_thumb_quality);
    metaData->mJpegSetting.jpegThumbnailQuality = new_jpeg_thumb_quality;
    metaData->mJpegSetting.thumbWidth = thumbSize.width;
    metaData->mJpegSetting.thumbHeight = thumbSize.height;

    int new_rotation = 0;
    params.getJpegRotation(new_rotation);
    metaData->mJpegSetting.orientation = new_rotation;

    LOG1("jpegQuality=%d,thumbQuality=%d,thumbW=%d,thumbH=%d,orientation=%d",
         metaData->mJpegSetting.jpegQuality, metaData->mJpegSetting.jpegThumbnailQuality,
         metaData->mJpegSetting.thumbWidth, metaData->mJpegSetting.thumbHeight,
         metaData->mJpegSetting.orientation);

    params.getAeMode(metaData->aeMode);
    params.getAwbMode(metaData->awbMode);

    metaData->currentFocusDistance = 0.0;
    float focusDistance = 0.0;
    params.getFocusDistance(focusDistance);
    if (focusDistance != 0) {
        metaData->currentFocusDistance = ceil(1000.0 / focusDistance);
    }
    LOG2("aeMode=%d, awbMode=%d, currentFocusDistance=%f", metaData->aeMode, metaData->awbMode,
         metaData->currentFocusDistance);

    return status;
}

/**
 * This function will get GPS metadata from request setting
 *
 * \param[in] settings The Anroid metadata to process GPS settings from
 * \param[out] metadata The EXIF data where the GPS setting are written to
 */
status_t JpegMaker::processGpsSettings(const Parameters& param, ExifMetaData* metadata) {
    LOG2("@%s:", __func__);
    status_t status = OK;

    // gps latitude
    double new_gps_latitude = 0.0;
    param.getJpegGpsLatitude(new_gps_latitude);
    metadata->mGpsSetting.latitude = new_gps_latitude;

    double new_gps_longitude = 0.0;
    param.getJpegGpsLongitude(new_gps_longitude);
    metadata->mGpsSetting.longitude = new_gps_longitude;

    double new_gps_altitude = 0.0;
    param.getJpegGpsAltitude(new_gps_altitude);
    metadata->mGpsSetting.altitude = new_gps_altitude;

    // gps timestamp
    int64_t new_gps_timestamp = 0;
    param.getJpegGpsTimeStamp(new_gps_timestamp);
    metadata->mGpsSetting.gpsTimeStamp = new_gps_timestamp;

    // gps processing method
    char new_gps_processing_method[MAX_NUM_GPS_PROCESSING_METHOD + 1];
    CLEAR(new_gps_processing_method);
    param.getJpegGpsProcessingMethod(MAX_NUM_GPS_PROCESSING_METHOD, new_gps_processing_method);
    if (strlen(new_gps_processing_method) != 0) {
        snprintf(metadata->mGpsSetting.gpsProcessingMethod,
                 sizeof(metadata->mGpsSetting.gpsProcessingMethod), "%s",
                 new_gps_processing_method);
    }

    return status;
}

status_t JpegMaker::processColoreffectSettings(const Parameters& param, ExifMetaData* metaData) {
    LOG2("@%s:", __func__);
    status_t status = OK;

    camera_effect_mode_t new_image_effect = CAM_EFFECT_NONE;
    param.getImageEffect(new_image_effect);
    metaData->effectMode = new_image_effect;
    LOG2("effect mode=%d", metaData->effectMode);

    return status;
}

status_t JpegMaker::processScalerCropSettings(const Parameters& param, ExifMetaData* metaData) {
    LOG2("@%s:", __func__);
    status_t status = OK;

    return status;
}

}  // namespace icamera
