/*
 * Copyright (c) 2018-2020, NVIDIA CORPORATION.  All rights reserved. All
 * information contained herein is proprietary and confidential to NVIDIA
 * Corporation.  Any use, reproduction, or disclosure without the written
 * permission of NVIDIA Corporation is prohibited.
 */

#include <cstring>

#include "CNvMSensor.hpp"

namespace nvsipl
{

CNvMSensor::CNvMSensor()
{
    m_pipelineIndex = 0;
    m_embLinesTop = 0;
    m_embLinesBot = 0;
    m_bEmbDataType = false;
    m_width = 0;
    m_height = 0;
    m_ePixelOrder = 0;
    m_eSurfType = 0;
    m_frameRate = 0.0;
    m_bEnableExtSync = false;
    m_bEnabletpg = false;
    m_patternMode = 0;
}

SIPLStatus CNvMSensor::SetConfig(const SensorInfo *sensorInfo, DeviceParams *params)
{
    SIPLStatus status = NVSIPL_STATUS_OK;

    if (m_eState != CREATED) {
        LOG_ERR("CDI invalid state\n");
        return NVSIPL_STATUS_INVALID_STATE;
    }

    m_embLinesTop = sensorInfo->vcInfo.embeddedTopLines;
    m_embLinesBot = sensorInfo->vcInfo.embeddedBottomLines;
    m_bEmbDataType = sensorInfo->vcInfo.isEmbeddedDataTypeEnabled;
    m_width = sensorInfo->vcInfo.resolution.width;
    m_height = sensorInfo->vcInfo.resolution.height;
    m_eInputFormat.inputFormatType = sensorInfo->vcInfo.inputFormat;

    if (m_embLinesTop == 0 and m_bEmbDataType) {
        LOG_ERR("Embedded data type must be disabled if top emb data lines is 0\n");
        return NVSIPL_STATUS_NOT_SUPPORTED;
    }

    status = SetInputFormatProperty();
    CHK_NVSIPLEERROR_AND_RETURN(status, "CNvMSensor::SetConfig");

    m_ePixelOrder = sensorInfo->vcInfo.cfa;
    m_eSurfType = 0;
    m_frameRate = sensorInfo->vcInfo.fps;
    m_bEnableExtSync = sensorInfo->isTriggerModeEnabled;
    m_bEnabletpg = sensorInfo->isTPGEnabled;
    m_patternMode = sensorInfo->patternMode;
    m_sensorDescription = sensorInfo->description;

    m_oDeviceParams = *params;
    if (!m_oDeviceParams.bEnableSimulator and !m_oDeviceParams.bSlave) {
        m_nativeI2CAddr =  sensorInfo->i2cAddress;
        m_oDeviceParams.pI2CAddrMgr->RegisterNativeI2CAddr(m_nativeI2CAddr);
    }

    status = CNvMSensor::SetSurfaceType();
    CHK_NVSIPLEERROR_AND_RETURN(status, "CNvMSensor::SetSurfaceType");

    m_eState = CDI_DEVICE_CONFIG_SET;

    return NVSIPL_STATUS_OK;
}

void CNvMSensor::SetPipelineIndex(uint32_t index)
{
    m_pipelineIndex = index;
}

uint32_t CNvMSensor::GetPipelineIndex()
{
    return m_pipelineIndex;
}

uint32_t CNvMSensor::GetWidth() const
{
    return m_width;
}

uint32_t CNvMSensor::GetHeight() const
{
    return m_height;
}

uint32_t CNvMSensor::GetEmbLinesTop() const
{
    return m_embLinesTop;
}

uint32_t CNvMSensor::GetEmbLinesBot() const
{
    return m_embLinesBot;
}

bool CNvMSensor::GetEmbDataType() const
{
    return m_bEmbDataType;
}

NvMediaICPInputFormat CNvMSensor::GetInputFormat() const
{
    return m_eInputFormat;
}

NvMediaSurfaceType CNvMSensor::GetSurfaceType() const
{
    return m_eSurfType;
}

float CNvMSensor::GetFrameRate() const
{
    return m_frameRate;
}

bool CNvMSensor::GetEnableExtSync() const
{
    return m_bEnableExtSync;
}

bool CNvMSensor::GetEnableTPG() const
{
    return m_bEnabletpg;
}

uint32_t CNvMSensor::GetPatternMode() const
{
    return m_patternMode;
}

std::string CNvMSensor::GetSensorDescription() const
{
    return m_sensorDescription;
}

SIPLStatus CNvMSensor::SetInputFormatProperty()
{
    SIPLStatus status = NVSIPL_STATUS_OK;

    if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_YUV422) {
        m_eInputFormat.bitsPerPixel = NVMEDIA_BITS_PER_PIXEL_8;
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RGB888) {
        m_eInputFormat.bitsPerPixel = NVMEDIA_BITS_PER_PIXEL_8;
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW10) {
        m_eInputFormat.bitsPerPixel = NVMEDIA_BITS_PER_PIXEL_10;
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW12) {
        m_eInputFormat.bitsPerPixel = NVMEDIA_BITS_PER_PIXEL_12;
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW16) {
        m_eInputFormat.bitsPerPixel = NVMEDIA_BITS_PER_PIXEL_16;
    } else {
        LOG_ERR("Unknown input format %d \n", m_eInputFormat.inputFormatType);
        status = NVSIPL_STATUS_BAD_ARGUMENT;
    }

    return status;
}

SIPLStatus CNvMSensor::SetSurfaceType()
{
    SIPLStatus status = NVSIPL_STATUS_OK;
    NVM_SURF_FMT_DEFINE_ATTR(surfFormatAttrs);

    if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_YUV422) {
        NVM_SURF_FMT_SET_ATTR_YUV(surfFormatAttrs,YUV,422,PLANAR,UINT,8,PL);
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RGB888) {
        NVM_SURF_FMT_SET_ATTR_RGBA(surfFormatAttrs,RGBA,UINT,8,PL);
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW10) {
            NVM_SURF_FMT_SET_ATTR_RAW(surfFormatAttrs,RGGB,UINT,10,PL);
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW12) {
            NVM_SURF_FMT_SET_ATTR_RAW(surfFormatAttrs,RGGB,UINT,12,PL);
    } else if (m_eInputFormat.inputFormatType == NVMEDIA_IMAGE_CAPTURE_INPUT_FORMAT_TYPE_RAW16) {
            NVM_SURF_FMT_SET_ATTR_RAW(surfFormatAttrs,RGGB,UINT,16,PL);
    } else {
        LOG_ERR("Unknown input format %d \n", m_eInputFormat.inputFormatType);
        status = NVSIPL_STATUS_BAD_ARGUMENT;
    }

    surfFormatAttrs[NVM_SURF_ATTR_COMPONENT_ORDER].value = m_ePixelOrder;
    m_eSurfType = NvMediaSurfaceFormatGetType(surfFormatAttrs, NVM_SURF_FMT_ATTR_MAX);

    return status;
}

CNvMSensor::EEPROMRequestHandle CNvMSensor::GetEEPROMRequestHandle()
{
    return m_EEPROMRequestHandle;
}

void CNvMSensor::SetEEPROMRequestHandle(void *handle, uint32_t size)
{
    if (handle == NULL) {
        return;
    }

    m_EEPROMRequestHandle.handle = handle;
    m_EEPROMRequestHandle.size = size;
}

} // end of nvsipl
