#include "TerminalDevice.h"
/*
 * Copyright 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.
 *
 */

#define LOG_TAG "CameraTestHelpers"

#include "Camera.h"

#include <android/log.h>
#include <AndroidHelper.h>

CCamera::CCamera()
{
}

CCamera::~CCamera()
{
	closeCamera();
}

int CCamera::initCamera(ANativeWindow *imgReaderAnw) {
	if (imgReaderAnw == nullptr) {
		ALOGE("Cannot initialize camera before image reader get initialized.");
		return -1;
	}

	mImgReaderAnw = imgReaderAnw;
	mCameraManager = ACameraManager_create();
	if (mCameraManager == nullptr) {
		ALOGE("Failed to create ACameraManager.");
		return -1;
	}

	int ret = ACameraManager_getCameraIdList(mCameraManager, &mCameraIdList);
	if (ret != AMEDIA_OK) {
		ALOGE("Failed to get cameraIdList: ret=%d", ret);
		return ret;
	}
	if (mCameraIdList->numCameras < 1) {
		ALOGW("Device has no NDK compatible camera.");
		return 0;
	}
	ALOGI("Found %d camera(s).", mCameraIdList->numCameras);

	// We always use the first camera.
	mCameraId = mCameraIdList->cameraIds[0];
	if (mCameraId == nullptr) {
		ALOGE("Failed to get cameraId.");
		return -1;
	}

	ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb,&mDevice);
	if (ret != AMEDIA_OK || mDevice == nullptr) {
		ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
		ret = ACAMERA_ERROR_INVALID_PARAMETER;
		return -1;
	}

	ret = ACameraManager_getCameraCharacteristics(mCameraManager, mCameraId,
		&mCameraMetadata);
	if (ret != ACAMERA_OK || mCameraMetadata == nullptr) {
		ALOGE("Get camera %s characteristics failure. ret %d, metadata %p",
			mCameraId, ret, mCameraMetadata);
		return -1;
	}

	if (!isCapabilitySupported(
		ACAMERA_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE)) {
		ALOGW("Camera does not support BACKWARD_COMPATIBLE.");
		return 0;
	}

	// Create capture session
	ret = ACaptureSessionOutputContainer_create(&mOutputs);
	if (ret != AMEDIA_OK) {
		ALOGE("ACaptureSessionOutputContainer_create failed, ret=%d", ret);
		return ret;
	}
	ret = ACaptureSessionOutput_create(mImgReaderAnw, &mImgReaderOutput);
	if (ret != AMEDIA_OK) {
		ALOGE("ACaptureSessionOutput_create failed, ret=%d", ret);
		return ret;
	}
	ret = ACaptureSessionOutputContainer_add(mOutputs, mImgReaderOutput);
	if (ret != AMEDIA_OK) {
		ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
		return ret;
	}
	ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb,
		&mSession);
	if (ret != AMEDIA_OK) {
		ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
		return ret;
	}

	// Create capture request
	ret = ACameraDevice_createCaptureRequest(mDevice, TEMPLATE_RECORD,
		&mCaptureRequest);
	if (ret != AMEDIA_OK) {
		ALOGE("ACameraDevice_createCaptureRequest failed, ret=%d", ret);
		return ret;
	}
	ret = ACameraOutputTarget_create(mImgReaderAnw, &mReqImgReaderOutput);
	if (ret != AMEDIA_OK) {
		ALOGE("ACameraOutputTarget_create failed, ret=%d", ret);
		return ret;
	}
	ret = ACaptureRequest_addTarget(mCaptureRequest, mReqImgReaderOutput);
	if (ret != AMEDIA_OK) {
		ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
		return ret;
	}

	mIsCameraReady = true;
	return 0;
}

bool CCamera::isCapabilitySupported(
	acamera_metadata_enum_android_request_available_capabilities_t cap) {
	ACameraMetadata_const_entry entry;
	ACameraMetadata_getConstEntry(mCameraMetadata,
		ACAMERA_REQUEST_AVAILABLE_CAPABILITIES, &entry);
	for (uint32_t i = 0; i < entry.count; i++) {
		if (entry.data.u8[i] == cap) {
			return true;
		}
	}
	return false;
}

void CCamera::closeCamera() {
	// Destroy capture request
	if (mReqImgReaderOutput) {
		ACameraOutputTarget_free(mReqImgReaderOutput);
		mReqImgReaderOutput = nullptr;
	}
	if (mCaptureRequest) {
		ACaptureRequest_free(mCaptureRequest);
		mCaptureRequest = nullptr;
	}
	// Destroy capture session
	if (mSession != nullptr) {
		ACameraCaptureSession_close(mSession);
		mSession = nullptr;
	}
	if (mImgReaderOutput) {
		ACaptureSessionOutput_free(mImgReaderOutput);
		mImgReaderOutput = nullptr;
	}
	if (mOutputs) {
		ACaptureSessionOutputContainer_free(mOutputs);
		mOutputs = nullptr;
	}
	// Destroy camera device
	if (mDevice) {
		ACameraDevice_close(mDevice);
		mDevice = nullptr;
	}
	if (mCameraMetadata) {
		ACameraMetadata_free(mCameraMetadata);
		mCameraMetadata = nullptr;
	}
	// Destroy camera manager
	if (mCameraIdList) {
		ACameraManager_deleteCameraIdList(mCameraIdList);
		mCameraIdList = nullptr;
	}
	if (mCameraManager) {
		ACameraManager_delete(mCameraManager);
		mCameraManager = nullptr;
	}
	mIsCameraReady = false;
}

int CCamera::takePicture()
{
	return ACameraCaptureSession_capture(mSession, nullptr, 1, &mCaptureRequest,
		nullptr);
}
