/*
** Copyright 2008, 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.
*/

#ifndef ANDROID_HARDWARE_QUALCOMM_CAMERA_HARDWARE_H
#define ANDROID_HARDWARE_QUALCOMM_CAMERA_HARDWARE_H

#include <camera/CameraHardwareInterface.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>

extern "C" {
    #include <linux/android_pmem.h>
}

namespace android {

class QualcommCameraHardware : public CameraHardwareInterface {
public:

    virtual sp<IMemoryHeap> getPreviewHeap() const;
    virtual sp<IMemoryHeap> getRawHeap() const;

    virtual status_t    dump(int fd, const Vector<String16>& args) const;
    virtual status_t    startPreview(preview_callback cb, void* user);
    virtual void        stopPreview();
    virtual bool        previewEnabled();
    virtual status_t    startRecording(recording_callback cb, void* user);
    virtual void        stopRecording();
    virtual bool        recordingEnabled();
    virtual void        releaseRecordingFrame(const sp<IMemory>& mem);
    virtual status_t    autoFocus(autofocus_callback, void *user);
    virtual status_t    takePicture(shutter_callback,
                                    raw_callback,
                                    jpeg_callback,
                                    void* user);
    virtual status_t    cancelPicture(bool cancel_shutter,
                                      bool cancel_raw, bool cancel_jpeg);
    virtual status_t    setParameters(const CameraParameters& params);
    virtual CameraParameters  getParameters() const;

    virtual void release();

    static sp<CameraHardwareInterface> createInstance();
    static sp<QualcommCameraHardware> getInstance();

    void* get_preview_mem(uint32_t size, uint32_t *phy_addr, uint32_t index);
    void* get_raw_mem(uint32_t size, uint32_t *phy_addr, uint32_t index);
    void free_preview_mem(uint32_t *phy_addr, uint32_t size, uint32_t index);
    void free_raw_mem(uint32_t *phy_addr, uint32_t size, uint32_t index);

private:

    QualcommCameraHardware();
    virtual ~QualcommCameraHardware();
    status_t startPreviewInternal(preview_callback pcb, void *puser,
                                  recording_callback rcb, void *ruser);
    void stopPreviewInternal();

    static wp<QualcommCameraHardware> singleton;

    /* These constants reflect the number of buffers that libqcamera requires
       for preview and raw, and need to be updated when libqcamera
       changes.
    */
    static const int kPreviewBufferCount = 4;
    static const int kRawBufferCount = 1;
    static const int kJpegBufferCount = 1;
    static const int kRawFrameHeaderSize = 0x48;

    //TODO: put the picture dimensions in the CameraParameters object;
    CameraParameters mParameters;
    int mPreviewHeight;
    int mPreviewWidth;
    int mRawHeight;
    int mRawWidth;

    void receivePreviewFrame(camera_frame_type *frame);

    static void stop_camera_cb(camera_cb_type cb,
            const void *client_data,
            camera_func_type func,
            int32_t parm4);

    static void camera_cb(camera_cb_type cb,
            const void *client_data,
            camera_func_type func,
            int32_t parm4);

    // This class represents a heap which maintains several contiguous
    // buffers.  The heap may be backed by pmem (when pmem_pool contains
    // the name of a /dev/pmem* file), or by ashmem (when pmem_pool == NULL).

    struct MemPool : public RefBase {
        MemPool(int buffer_size, int num_buffers,
                int frame_size,
                int frame_offset,
                const char *name);

        virtual ~MemPool() = 0;

        void completeInitialization();
        bool initialized() const { 
            return mHeap != NULL && mHeap->base() != MAP_FAILED;
        }

        virtual status_t dump(int fd, const Vector<String16>& args) const;

        int mBufferSize;
        int mNumBuffers;
        int mFrameSize;
        int mFrameOffset;
        sp<MemoryHeapBase> mHeap;
        sp<MemoryBase> *mBuffers;

        const char *mName;
    };

    struct AshmemPool : public MemPool {
        AshmemPool(int buffer_size, int num_buffers,
                   int frame_size,
                   int frame_offset,
                   const char *name);
    };

    struct PmemPool : public MemPool {
        PmemPool(const char *pmem_pool,
                int buffer_size, int num_buffers,
                int frame_size,
                int frame_offset,
                const char *name);
        virtual ~PmemPool() { }
        int mFd;
        uint32_t mAlignedSize;
        struct pmem_region mSize;
    };

    struct PreviewPmemPool : public PmemPool {
        virtual ~PreviewPmemPool();
        PreviewPmemPool(int buffer_size, int num_buffers,
                        int frame_size,
                        int frame_offset,
                        const char *name);
    };

    struct RawPmemPool : public PmemPool {
        virtual ~RawPmemPool();
        RawPmemPool(const char *pmem_pool,
                    int buffer_size, int num_buffers,
                    int frame_size,
                    int frame_offset,
                    const char *name);
    };

    sp<PreviewPmemPool> mPreviewHeap;
    sp<RawPmemPool> mRawHeap;
    sp<AshmemPool> mJpegHeap;

    void startCameraIfNecessary();
    bool initPreview();
    void deinitPreview();
    bool initRaw(bool initJpegHeap);

    void initDefaultParameters();
    void initCameraParameters();
    void setCameraDimensions();

    // The states described by qualcomm_camera_state are very similar to the
    // CAMERA_FUNC_xxx notifications reported by libqcamera.  The differences
    // are that they reflect not only the response from libqcamera, but also
    // the requests made by the clients of this object.  For example,
    // QCS_PREVIEW_REQUESTED is a state that we enter when we call
    // QualcommCameraHardware::startPreview(), and stay in until libqcamera
    // confirms that it has received the start-preview command (but not
    // actually initiated preview yet).
    //
    // NOTE: keep those values small; they are used internally as indices
    //       into a array of strings.
    // NOTE: if you add to this enumeration, make sure you update
    //       getCameraStateStr().

    enum qualcomm_camera_state {
        QCS_INIT,
        QCS_IDLE,
        QCS_ERROR,
        QCS_PREVIEW_IN_PROGRESS,
        QCS_WAITING_RAW,
        QCS_WAITING_JPEG,
        /* internal states */
        QCS_INTERNAL_PREVIEW_STOPPING,
        QCS_INTERNAL_PREVIEW_REQUESTED,
        QCS_INTERNAL_RAW_REQUESTED,
        QCS_INTERNAL_STOPPING,
    };

    volatile qualcomm_camera_state mCameraState;
    static const char* const getCameraStateStr(qualcomm_camera_state s);
    qualcomm_camera_state change_state(qualcomm_camera_state new_state,
                                       bool lock = true);

    void notifyShutter();
    void receiveJpegPictureFragment(JPEGENC_CBrtnType *encInfo);

    void receivePostLpmRawPicture(camera_frame_type *frame);
    void receiveRawPicture(camera_frame_type *frame);
    void receiveJpegPicture(void);

    Mutex mLock; // API lock -- all public methods
    Mutex mCallbackLock;
    Mutex mStateLock;
    Condition mStateWait;

    /* mJpegSize keeps track of the size of the accumulated JPEG.  We clear it
       when we are about to take a picture, so at any time it contains either
       zero, or the size of the last JPEG picture taken.
    */
    uint32_t mJpegSize;
    camera_handle_type camera_handle;
    camera_encode_properties_type encode_properties;
    camera_position_type pt;

    shutter_callback    mShutterCallback;
    raw_callback        mRawPictureCallback;
    jpeg_callback       mJpegPictureCallback;
    void                *mPictureCallbackCookie;

    autofocus_callback  mAutoFocusCallback;
    void                *mAutoFocusCallbackCookie;

    preview_callback    mPreviewCallback;
    void                *mPreviewCallbackCookie;
    recording_callback  mRecordingCallback;
    void                *mRecordingCallbackCookie;
    bool setCallbacks(preview_callback pcb, void *pu,
                      recording_callback rcb, void *ru);

    int                 mPreviewFrameSize;
    int                 mRawSize;
    int                 mJpegMaxSize;

    // hack to prevent black frame on first preview
    int                 mPreviewCount;

#if DLOPEN_LIBQCAMERA == 1
    void *libqcamera;
#endif
};

}; // namespace android

#endif