/******************************************************************************
 * Function: usbCamSetParameters
 * Description: This function parses the parameter string and stores the
 *              parameters in the camera HAL handle
 *
 * Input parameters:
 *  camHal              - camera HAL handle
 *  params              - pointer to parameter string
 *
 * Return values:
 *      0   Success
 *      -1  Error
 * Notes: none
 *****************************************************************************/
int usbCamSetParameters(camera_hardware_t *camHal, const char *params)
{
    int             rc      = 0;
    String8         str     = String8(params);
    QCameraParameters qParam;

    ALOGD("%s: E", __func__);

    if(params)
        PRINT_PARAM_STR(params);

    qParam.unflatten(str);

    if(usbCamSetPrvwSize(camHal, qParam))
        rc = -1;
    if(usbCamSetPictSize(camHal, qParam))
        rc = -1;
    if(usbCamSetThumbnailSize(camHal, qParam))
        rc = -1;
    if(usbCamSetJpegQlty(camHal, qParam))
        rc = -1;

    ALOGD("%s: X", __func__);
    return rc;
} /* usbCamSetParameters */
/******************************************************************************
 * Function: usbCamSetPictSize
 * Description: This function parses picture width and height from the input
 *              parameters and stores into the context
 *
 * Input parameters:
 *  camHal              - camera HAL handle
 *  params              - QCameraParameters reference
 *
 * Return values:
 *      0   If parameters are valid
 *      -1  If parameters are invalid
 *
 * Notes: none
 *****************************************************************************/
static int usbCamSetPictSize(   camera_hardware_t           *camHal,
                                const QCameraParameters&    params)
{
    int rc = 0, width, height, i, numPictSizes, validSize;
    ALOGD("%s: E", __func__);

    /* parse for picture width and height */
    params.getPictureSize(&width, &height);
    ALOGI("%s: Requested picture size %d x %d", __func__, width, height);

    // Validate the picture size
    numPictSizes = sizeof(picture_sizes) / sizeof(camera_size_type);
    for (i = 0, validSize = 0; i <  numPictSizes; i++) {
        if (width ==  picture_sizes[i].width
           && height ==  picture_sizes[i].height) {
            validSize = 1;

            camHal->qCamParams.setPictureSize(width, height);
            ALOGD("%s: setPictureSize:  width: %d   height: %d",
                __func__, width, height);

            /* TBD: If new pictSize is different from old size, restart prvw */
            camHal->pictWidth   = width;
            camHal->pictHeight  = height;
        }
    }
    if(!validSize)
        ALOGE("%s: Invalid picture size %dx%d requested", __func__,
            width, height);
    rc = (validSize == 0)? -1:0;
    ALOGD("%s: X", __func__);

    return rc;
} /* usbCamSetPictSize */
/*===========================================================================
 * FUNCTION   : UpdateStreamBasedParameters
 *
 * DESCRIPTION: update any stream based settings from parameters
 *
 * PARAMETERS :
 *   @param   : reference to parameters object
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int32_t QCameraChannel::UpdateStreamBasedParameters(QCameraParameters &param)
{
    int32_t rc = NO_ERROR;
    if (param.isPreviewFlipChanged()) {
        // try to find preview stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
                (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW))) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_PREVIEW);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set preview stream flip failed", __func__);
                }
            }
        }
    }
    if (param.isVideoFlipChanged()) {
        // try to find video stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_VIDEO) ||
                (mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_VIDEO))) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_VIDEO);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set video stream flip failed", __func__);
                }
            }
        }
    }
    if (param.isSnapshotFlipChanged()) {
        // try to find snapshot/postview stream
        for (int i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) {
            if (mStreams[i] != NULL &&
                (mStreams[i]->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                 mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                 mStreams[i]->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
                 mStreams[i]->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW) ) ) {
                cam_stream_parm_buffer_t param_buf;
                memset(&param_buf, 0, sizeof(cam_stream_parm_buffer_t));
                param_buf.type = CAM_STREAM_PARAM_TYPE_SET_FLIP;
                param_buf.flipInfo.flip_mask = param.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT);
                rc = mStreams[i]->setParameter(param_buf);
                if (rc != NO_ERROR) {
                    ALOGE("%s: set snapshot stream flip failed", __func__);
                }
            }
        }
    }
    return rc;
}
/******************************************************************************
 * Function: usbCamSetThumbnailSize
 * Description: This function parses picture width and height from the input
 *              parameters and stores into the context
 *
 * Input parameters:
 *  camHal              - camera HAL handle
 *  params              - QCameraParameters reference
 *
 * Return values:
 *      0   If parameters are valid
 *      -1  If parameters are invalid
 *
 * Notes: none
 *****************************************************************************/
static int usbCamSetThumbnailSize(  camera_hardware_t           *camHal,
                                    const QCameraParameters&    params)
{
    int rc = 0, width, height, i, numThumbnailSizes, validSize;
    char tempStr[FILENAME_LENGTH];
    ALOGD("%s: E", __func__);

    /* parse for thumbnail width and height */
    width = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
    height = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
    ALOGI("%s: Requested thumbnail size %d x %d", __func__, width, height);

    // Validate the thumbnail size
    numThumbnailSizes = sizeof(thumbnail_sizes) / sizeof(camera_size_type);
    for (i = 0, validSize = 0; i <  numThumbnailSizes; i++) {
        if (width ==  thumbnail_sizes[i].width
           && height ==  thumbnail_sizes[i].height) {
            validSize = 1;

            camHal->thumbnailWidth   = width;
            camHal->thumbnailHeight  = height;
            sprintf(tempStr, "%d", camHal->thumbnailWidth);
            camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
                                                        width);
            sprintf(tempStr, "%d", camHal->thumbnailHeight);
            camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
                                                        height);

        }
    }
    if(!validSize)
        ALOGE("%s: Invalid picture size %dx%d requested", __func__,
            width, height);
    rc = (validSize == 0)? -1:0;
    ALOGD("%s: X", __func__);

    return rc;
} /* usbCamSetThumbnailSize */
/******************************************************************************
 * Function: usbCamGetParameters
 * Description: This function allocates memory for parameter string,
 *              composes and returns the parameter string
 *
 * Input parameters:
 *   camHal             - camera HAL handle
 *
 * Return values:
 *      Address to the parameter string
 *
 * Notes: none
 *****************************************************************************/
char* usbCamGetParameters(camera_hardware_t *camHal)
{
    ALOGD("%s: E", __func__);
    char *parms = NULL;
    char* rc = NULL;
    String8 str;

    QCameraParameters qParam = camHal->qCamParams;
    //qParam.dump();
    str = qParam.flatten( );
    rc = (char *)malloc(sizeof(char)*(str.length()+1));
    if(rc != NULL){
        memset(rc, 0, sizeof(char)*(str.length()+1));
        strncpy(rc, str.string(), str.length());
    rc[str.length()] = 0;
    parms = rc;
    }

    PRINT_PARAM_STR(parms);

    ALOGD("%s: X", __func__);
    return (parms);
} /* usbCamGetParameters */
/******************************************************************************
 * Function: usbCamSetJpegQlty
 * Description: This function parses picture and thumbnail JPEG quality and
 *              validates before storing in the context
 *
 * Input parameters:
 *  camHal              - camera HAL handle
 *  params              - QCameraParameters reference
 *
 * Return values:
 *      0   If parameters are valid
 *      -1  If parameters are invalid
 *
 * Notes: none
 *****************************************************************************/
static int usbCamSetJpegQlty(   camera_hardware_t           *camHal,
                                const QCameraParameters&    params)
{
    int rc = 0, quality = 0;
    char tempStr[FILENAME_LENGTH];
    ALOGD("%s: E", __func__);

    /**/
    quality = params.getInt(QCameraParameters::KEY_JPEG_QUALITY);
    ALOGI("%s: Requested picture qlty %d", __func__, quality);

    if (quality >= 0 && quality <= 100) {
        camHal->pictJpegQlty = quality;
        sprintf(tempStr, "%d", camHal->pictJpegQlty);
        camHal->qCamParams.set(QCameraParameters::KEY_JPEG_QUALITY, quality);
    } else {
        ALOGE("Invalid jpeg quality=%d", quality);
        rc = -1;
    }

    quality = params.getInt(QCameraParameters::KEY_JPEG_THUMBNAIL_QUALITY);
    ALOGI("%s: Requested thumbnail qlty %d", __func__, quality);

    if (quality >= 0 && quality <= 100) {
        camHal->thumbnailJpegQlty = quality;
        sprintf(tempStr, "%d", camHal->thumbnailJpegQlty);
        camHal->qCamParams.set(QCameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
                                    tempStr);
    } else {
        ALOGE("Invalid jpeg thumbnail quality=%d", quality);
        rc = -1;
    }

    ALOGD("%s: X rc:%d", __func__, rc);

    return rc;
}
int set_parameters(struct camera_device * device, const char *parms)

{
  ALOGV("Q%s: E", __func__);
  int rc = -1;
  QualcommCameraHardware * hardware = util_get_Hal_obj(device);
  if(hardware != NULL && parms){
    // = util_get_HAL_parameter(device);
    g_str = String8(parms);

   g_param.unflatten(g_str);
   rc = hardware->setParameters( g_param );
  }
  return rc;
}
char* get_parameters(struct camera_device * device)
{
  ALOGV("Q%s: E", __func__);
  char* rc = NULL;

  QCameraParameters param;
  QualcommCameraHardware * hardware = util_get_Hal_obj(device);
  if(hardware != NULL){
    g_param = hardware->getParameters( );
    g_str = g_param.flatten( );
    rc = (char *)g_str.string( );
    if (!rc) {
      ALOGE("get_parameters: NULL string");
    } else {
      //ALOGE("get_parameters: %s", rc);
    }
  }
  ALOGV("get_parameters X");
  return rc;
}
/******************************************************************************
 * Function: usbCamSetPrvwSize
 * Description: This function parses preview width and height from the input
 *              parameters and stores into the context
 *
 * Input parameters:
 *  camHal              - camera HAL handle
 *  params              - QCameraParameters reference
 *
 * Return values:
 *      0   If parameters are valid
 *      -1  If parameters are invalid
 *
 * Notes: none
 *****************************************************************************/
static int usbCamSetPrvwSize(   camera_hardware_t           *camHal,
                                const QCameraParameters&    params)
{
    int rc = 0, width, height, i, numPrvwSizes, validSize;
    ALOGD("%s: E", __func__);

    params.getPreviewSize(&width, &height);
    ALOGI("%s: Requested preview size %d x %d", __func__, width, height);

    // Validate the preview size
    numPrvwSizes = sizeof(previewSizes) / sizeof(camera_size_type);
    for (i = 0, validSize = 0; i <  numPrvwSizes; i++) {
        if (width ==  previewSizes[i].width
           && height ==  previewSizes[i].height) {
            validSize = 1;

            camHal->qCamParams.setPreviewSize(width, height);
            ALOGD("%s: setPreviewSize:  width: %d   height: %d",
                __func__, width, height);

            camHal->prevWidth   = width;
            camHal->prevHeight  = height;
            camHal->dispWidth   = width;
            camHal->dispHeight  = height;

            /* TBD: restrict pictures size and video to preview size */
        }
    }
    if(!validSize)
        ALOGE("%s: Invalid preview size %dx%d requested", __func__,
            width, height);

    rc = (validSize == 0)? -1:0;
    ALOGD("%s: X", __func__);

    return rc;
} /* usbCamSetPrvwSize */
/*===========================================================================
 * FUNCTION   : addReprocStreamsFromSource
 *
 * DESCRIPTION: add reprocess streams from input source channel
 *
 * PARAMETERS :
 *   @allocator      : stream related buffer allocator
 *   @config         : pp feature configuration
 *   @pSrcChannel    : ptr to input source channel that needs reprocess
 *   @minStreamBufNum: number of stream buffers needed
 *   @burstNum       : number of burst captures needed
 *   @paddingInfo    : padding information
 *   @param          : reference to parameters
 *   @contStream     : continous streaming mode or burst
 *   @offline        : configure for offline reprocessing
 *
 * RETURN     : int32_t type of status
 *              NO_ERROR  -- success
 *              none-zero failure code
 *==========================================================================*/
int32_t QCameraReprocessChannel::addReprocStreamsFromSource(QCameraAllocator& allocator,
                                                            cam_pp_feature_config_t &config,
                                                            QCameraChannel *pSrcChannel,
                                                            uint8_t minStreamBufNum,
                                                            uint32_t burstNum,
                                                            cam_padding_info_t *paddingInfo,
                                                            QCameraParameters &param,
                                                            bool contStream,
                                                            bool offline)
{
    int32_t rc = 0;
    QCameraStream *pStream = NULL;
    QCameraHeapMemory *pStreamInfoBuf = NULL;
    cam_stream_info_t *streamInfo = NULL;

    memset(mSrcStreamHandles, 0, sizeof(mSrcStreamHandles));

    for (int i = 0; i < pSrcChannel->getNumOfStreams(); i++) {
        pStream = pSrcChannel->getStreamByIndex(i);
        if (pStream != NULL) {
            if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA) ||
                pStream->isTypeOf(CAM_STREAM_TYPE_RAW)) {
                // Skip metadata&raw for reprocess now because PP module cannot handle
                // meta data&raw. May need furthur discussion if Imaginglib need meta data
                continue;
            }

            if (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
                pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW)) {
                // Skip postview: in non zsl case, dont want to send
                // thumbnail through reprocess.
                // Skip preview: for same reason for zsl case
                continue;
            }

            if(pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
               pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW) ||
               pStream->isOrignalTypeOf(CAM_STREAM_TYPE_PREVIEW) ||
               pStream->isOrignalTypeOf(CAM_STREAM_TYPE_POSTVIEW)) {
                  uint32_t feature_mask = config.feature_mask;

                  if ((feature_mask & ~CAM_QCOM_FEATURE_HDR) == 0
                      && param.isHDREnabled()
                      && !param.isHDRThumbnailProcessNeeded()) {

                      // Skip thumbnail stream reprocessing in HDR
                      // if only hdr is enabled
                      continue;
                  }

                  // skip thumbnail reprocessing if not needed
                  if (!param.needThumbnailReprocess(&feature_mask)) {
                      continue;
                  }

                  //Don't do WNR for thumbnail
                  feature_mask &= ~CAM_QCOM_FEATURE_DENOISE2D;
                  if(!feature_mask) {
                    // Skip thumbnail stream reprocessing since no other
                    //reprocessing is enabled.
                      continue;
                  }
            }

            pStreamInfoBuf = allocator.allocateStreamInfoBuf(CAM_STREAM_TYPE_OFFLINE_PROC);
            if (pStreamInfoBuf == NULL) {
                ALOGE("%s: no mem for stream info buf", __func__);
                rc = NO_MEMORY;
                break;
            }

            streamInfo = (cam_stream_info_t *)pStreamInfoBuf->getPtr(0);
            memset(streamInfo, 0, sizeof(cam_stream_info_t));
            streamInfo->stream_type = CAM_STREAM_TYPE_OFFLINE_PROC;
            rc = pStream->getFormat(streamInfo->fmt);
            rc = pStream->getFrameDimension(streamInfo->dim);
            if ( contStream ) {
                streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;
                streamInfo->num_of_burst = 0;
            } else {
                streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST;
                streamInfo->num_of_burst = burstNum;
            }

            cam_stream_reproc_config_t rp_cfg;
            memset(&rp_cfg, 0, sizeof(cam_stream_reproc_config_t));
            if (offline) {
                cam_frame_len_offset_t offset;
                memset(&offset, 0, sizeof(cam_frame_len_offset_t));

                rp_cfg.pp_type = CAM_OFFLINE_REPROCESS_TYPE;
                pStream->getFormat(rp_cfg.offline.input_fmt);
                pStream->getFrameDimension(rp_cfg.offline.input_dim);
                pStream->getFrameOffset(offset);
                rp_cfg.offline.input_buf_planes.plane_info = offset;
                rp_cfg.offline.input_type = pStream->getMyType();
                //For input metadata + input buffer
                rp_cfg.offline.num_of_bufs = 2;
            } else {
                rp_cfg.pp_type = CAM_ONLINE_REPROCESS_TYPE;
                rp_cfg.online.input_stream_id = pStream->getMyServerID();
                rp_cfg.online.input_stream_type = pStream->getMyType();
            }
            streamInfo->reprocess_config = rp_cfg;
            streamInfo->reprocess_config.pp_feature_config = config;

            if (!(pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT) ||
                pStream->isOrignalTypeOf(CAM_STREAM_TYPE_SNAPSHOT))) {
                streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_CAC;
                //Don't do WNR for thumbnail
                streamInfo->reprocess_config.pp_feature_config.feature_mask &= ~CAM_QCOM_FEATURE_DENOISE2D;

                if (param.isHDREnabled()
                  && !param.isHDRThumbnailProcessNeeded()){
                    streamInfo->reprocess_config.pp_feature_config.feature_mask
                      &= ~CAM_QCOM_FEATURE_HDR;
                }
            }

            if (streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_ROTATION) {
                if (streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_90 ||
                    streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_270) {
                    // rotated by 90 or 270, need to switch width and height
                    int32_t temp = streamInfo->dim.height;
                    streamInfo->dim.height = streamInfo->dim.width;
                    streamInfo->dim.width = temp;
                }
            }

            if (param.isZSLMode() &&
                (streamInfo->reprocess_config.online.input_stream_type == CAM_STREAM_TYPE_SNAPSHOT)) {
                // ZSL mode snapshot need reprocess to do the flip
                int flipMode =
                    param.getFlipMode(streamInfo->reprocess_config.online.input_stream_type);
                if (flipMode > 0) {
                    streamInfo->reprocess_config.pp_feature_config.feature_mask |= CAM_QCOM_FEATURE_FLIP;
                    streamInfo->reprocess_config.pp_feature_config.flip = flipMode;
                }
            }

            if(streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_SCALE){
                //we only Scale Snapshot frame
                if(pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT)){
                    //also check whether rotation is needed
                    if((streamInfo->reprocess_config.pp_feature_config.feature_mask & CAM_QCOM_FEATURE_ROTATION) &&
                       (streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_90 ||
                        streamInfo->reprocess_config.pp_feature_config.rotation == ROTATE_270)){
                        //need swap
                        streamInfo->dim.width = streamInfo->reprocess_config.pp_feature_config.scale_param.output_height;
                        streamInfo->dim.height = streamInfo->reprocess_config.pp_feature_config.scale_param.output_width;
                    }else{
                        streamInfo->dim.width = streamInfo->reprocess_config.pp_feature_config.scale_param.output_width;
                        streamInfo->dim.height = streamInfo->reprocess_config.pp_feature_config.scale_param.output_height;
                    }
                }
                CDBG_HIGH("%s: stream width=%d, height=%d.", __func__, streamInfo->dim.width, streamInfo->dim.height);
            }

            // save source stream handler
            mSrcStreamHandles[m_numStreams] = pStream->getMyHandle();

            // add reprocess stream
            rc = addStream(allocator,
                           pStreamInfoBuf, minStreamBufNum,
                           paddingInfo,
                           NULL, NULL, false);
            if (rc != NO_ERROR) {
                ALOGE("%s: add reprocess stream failed, ret = %d", __func__, rc);
                break;
            }
        }
    }

    if (rc == NO_ERROR) {
        m_pSrcChannel = pSrcChannel;
    }
    return rc;
}