/*
 * Copyright (C) 2016 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_NDEBUG 0
#define LOG_TAG "ACameraCaptureSession"

#include "ACameraCaptureSession.h"

using namespace android;

ACameraCaptureSession::~ACameraCaptureSession() {
    ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
    sp<CameraDevice> dev = getDeviceSp();
    if (dev != nullptr && !dev->isClosed()) {
        dev->lockDeviceForSessionOps();
        {
            Mutex::Autolock _l(mSessionLock);
            dev->notifySessionEndOfLifeLocked(this);
        }
        dev->unlockDevice();
    }
    // Fire onClosed callback
    (*mUserSessionCallback.onClosed)(mUserSessionCallback.context, this);
    ALOGV("~ACameraCaptureSession: %p is deleted", this);
}

void
ACameraCaptureSession::closeByApp() {
    {
        Mutex::Autolock _l(mSessionLock);
        if (mClosedByApp) {
            // Do not close twice
            return;
        }
        mClosedByApp = true;
    }

    sp<CameraDevice> dev = getDeviceSp();
    if (dev != nullptr) {
        dev->lockDeviceForSessionOps();
    }

    {
        Mutex::Autolock _l(mSessionLock);

        if (!mIsClosed && dev != nullptr) {
            camera_status_t ret = dev->stopRepeatingLocked();
            if (ret != ACAMERA_OK) {
                ALOGE("Stop repeating request failed while closing session %p", this);
            }
        }
        mIsClosed = true;
    }

    if (dev != nullptr) {
        dev->unlockDevice();
    }
    this->decStrong((void*) ACameraDevice_createCaptureSession);
}

camera_status_t
ACameraCaptureSession::stopRepeating() {
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return ACAMERA_ERROR_SESSION_CLOSED;
    }

    camera_status_t ret;
    dev->lockDeviceForSessionOps();
    {
        Mutex::Autolock _l(mSessionLock);
        ret = dev->stopRepeatingLocked();
    }
    dev->unlockDevice();
    return ret;
}

camera_status_t
ACameraCaptureSession::abortCaptures() {
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return ACAMERA_ERROR_SESSION_CLOSED;
    }

    camera_status_t ret;
    dev->lockDeviceForSessionOps();
    {
        Mutex::Autolock _l(mSessionLock);
        ret = dev->flushLocked(this);
    }
    dev->unlockDevice();
    return ret;
}

camera_status_t
ACameraCaptureSession::setRepeatingRequest(
        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
        int numRequests, ACaptureRequest** requests,
        /*optional*/int* captureSequenceId) {
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return ACAMERA_ERROR_SESSION_CLOSED;
    }

    camera_status_t ret;
    dev->lockDeviceForSessionOps();
    {
        Mutex::Autolock _l(mSessionLock);
        ret = dev->setRepeatingRequestsLocked(
                this, cbs, numRequests, requests, captureSequenceId);
    }
    dev->unlockDevice();
    return ret;
}

camera_status_t ACameraCaptureSession::capture(
        /*optional*/ACameraCaptureSession_captureCallbacks* cbs,
        int numRequests, ACaptureRequest** requests,
        /*optional*/int* captureSequenceId) {
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return ACAMERA_ERROR_SESSION_CLOSED;
    }
    camera_status_t ret;
    dev->lockDeviceForSessionOps();
    {
        Mutex::Autolock _l(mSessionLock);
        ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
    }
    dev->unlockDevice();
    return ret;
}

camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return ACAMERA_ERROR_SESSION_CLOSED;
    }

    camera_status_t ret;
    dev->lockDeviceForSessionOps();
    {
        Mutex::Autolock _l(mSessionLock);
        ret = dev->updateOutputConfigurationLocked(output);
    }
    dev->unlockDevice();
    return ret;
}

ACameraDevice*
ACameraCaptureSession::getDevice() {
    Mutex::Autolock _l(mSessionLock);
    sp<CameraDevice> dev = getDeviceSp();
    if (dev == nullptr) {
        ALOGE("Error: Device associated with session %p has been closed!", this);
        return nullptr;
    }
    return dev->getWrapper();
}

void
ACameraCaptureSession::closeByDevice() {
    Mutex::Autolock _l(mSessionLock);
    mIsClosed = true;
}

sp<CameraDevice>
ACameraCaptureSession::getDeviceSp() {
    sp<CameraDevice> device = mDevice.promote();
    if (device == nullptr || device->isClosed()) {
        ALOGW("Device is closed but session %d is not notified", mId);
        return nullptr;
    }
    return device;
}


