/*
**
** Copyright 2008, The Android Open Source Project
** Copyright 2010, Samsung Electronics Co. LTD
**
** 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.
*/

/*!
 * \file      ExynosCameraHWInterface.h
 * \brief     hearder file for Android Camera HAL
 * \author    thun.hwang(thun.hwang@samsung.com)
 * \date      2010/06/03
 *
 * <b>Revision History: </b>
 * - 2011/12/31 : thun.hwang(thun.hwang@samsung.com) \n
 *   Initial version
 *
 * - 2012/03/14 : sangwoo.park(sw5771.park@samsung.com) \n
 *   Change file, class name to ExynosXXX.
 *
 */

#ifndef EXYNOS_CAMERA_HW_INTERFACE_H

#include <utils/threads.h>
#include <utils/RefBase.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <hardware/camera.h>
#include <hardware/gralloc.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
#include <media/hardware/MetadataBufferType.h>

#include "gralloc_priv.h"

#include "exynos_format.h"
#include "csc.h"
#include "ExynosCamera.h"

#include <fcntl.h>
#include <sys/mman.h>

#define USE_EGL                         (1)

#define  NUM_OF_PREVIEW_BUF             (8)
#define  NUM_OF_VIDEO_BUF               (8)
#define  NUM_OF_PICTURE_BUF             (6)
#define  NUM_OF_WAITING_PUT_PICTURE_BUF (1)

#define  NUM_OF_DETECTED_FACES          (32)

namespace android {

class ExynosCameraHWInterface : public virtual RefBase {
public:
    ExynosCameraHWInterface(int cameraId, camera_device_t *dev);
    virtual             ~ExynosCameraHWInterface();

    virtual status_t    setPreviewWindow(preview_stream_ops *w);
    virtual void        setCallbacks(camera_notify_callback notify_cb,
                                     camera_data_callback data_cb,
                                     camera_data_timestamp_callback data_cb_timestamp,
                                     camera_request_memory get_memory,
                                     void *user);

    virtual void        enableMsgType(int32_t msgType);
    virtual void        disableMsgType(int32_t msgType);
    virtual bool        msgTypeEnabled(int32_t msgType);

    virtual status_t    startPreview();
    virtual void        stopPreview();
    virtual bool        previewEnabled();

    virtual status_t    storeMetaDataInBuffers(bool enable);

    virtual status_t    startRecording();
    virtual void        stopRecording();
    virtual bool        recordingEnabled();
    virtual void        releaseRecordingFrame(const void *opaque);

    virtual status_t    autoFocus();
    virtual status_t    cancelAutoFocus();

    virtual status_t    takePicture();
    virtual status_t    cancelPicture();

    virtual status_t    setParameters(const CameraParameters& params);
    virtual CameraParameters  getParameters() const;
    virtual status_t    sendCommand(int32_t command, int32_t arg1, int32_t arg2);

    virtual void        release();

    virtual status_t    dump(int fd) const;

    inline  int         getCameraId() const;

private:
    class PreviewThread : public Thread {
        ExynosCameraHWInterface *mHardware;
    public:
        PreviewThread(ExynosCameraHWInterface *hw):
        Thread(false),
        mHardware(hw) { }
        virtual void onFirstRef() {
            //run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
            run("CameraPreviewThread", PRIORITY_DEFAULT);
        }
        virtual bool threadLoop() {
            mHardware->m_previewThreadFuncWrapper();
            return false;
        }
    };

    class VideoThread : public Thread {
        ExynosCameraHWInterface *mHardware;
    public:
        VideoThread(ExynosCameraHWInterface *hw):
        Thread(false),
        mHardware(hw) { }
        virtual void onFirstRef() {
            run("CameraVideoThread", PRIORITY_DEFAULT);
        }
        virtual bool threadLoop() {
            mHardware->m_videoThreadFuncWrapper();
            return false;
        }
    };

    class PictureThread : public Thread {
        ExynosCameraHWInterface *mHardware;
    public:
        PictureThread(ExynosCameraHWInterface *hw):
        Thread(false),
        mHardware(hw) { }
        virtual bool threadLoop() {
            mHardware->m_pictureThreadFunc();
            return false;
        }
    };

    class AutoFocusThread : public Thread {
        ExynosCameraHWInterface *mHardware;
    public:
        AutoFocusThread(ExynosCameraHWInterface *hw): Thread(false), mHardware(hw) { }
        virtual void onFirstRef() {
            run("CameraAutoFocusThread", PRIORITY_DEFAULT);
        }
        virtual bool threadLoop() {
            mHardware->m_autoFocusThreadFunc();
            return true;
        }
    };

private:
    void        m_initDefaultParameters(int cameraId);

    bool        m_startPreviewInternal(void);
    void        m_stopPreviewInternal(void);

    bool        m_previewThreadFuncWrapper(void);
    bool        m_previewThreadFunc(void);
    bool        m_videoThreadFuncWrapper(void);
    bool        m_videoThreadFunc(void);
    bool        m_autoFocusThreadFunc(void);

    bool        m_startPictureInternal(void);
    bool        m_stopPictureInternal(void);
    bool        m_pictureThreadFunc(void);

    int         m_saveJpeg(unsigned char *real_jpeg, int jpeg_size);
    void        m_savePostView(const char *fname, uint8_t *buf,
                               uint32_t size);
    int         m_decodeInterleaveData(unsigned char *pInterleaveData,
                                       int interleaveDataSize,
                                       int yuvWidth,
                                       int yuvHeight,
                                       int *pJpegSize,
                                       void *pJpegData,
                                       void *pYuvData);
    bool        m_YUY2toNV21(void *srcBuf, void *dstBuf, uint32_t srcWidth, uint32_t srcHeight);
    bool        m_scaleDownYuv422(char *srcBuf, uint32_t srcWidth,
                                  uint32_t srcHight, char *dstBuf,
                                  uint32_t dstWidth, uint32_t dstHight);

    bool        m_checkVideoStartMarker(unsigned char *pBuf);
    bool        m_checkEOIMarker(unsigned char *pBuf);
    bool        m_findEOIMarkerInJPEG(unsigned char *pBuf,
                                      int dwBufSize, int *pnJPEGsize);
    bool        m_splitFrame(unsigned char *pFrame, int dwSize,
                             int dwJPEGLineLength, int dwVideoLineLength,
                             int dwVideoHeight, void *pJPEG,
                             int *pdwJPEGSize, void *pVideo,
                             int *pdwVideoSize);
    void        m_setSkipFrame(int frame);
    bool        m_isSupportedPreviewSize(const int width, const int height) const;

    void        m_getAlignedYUVSize(int colorFormat, int w, int h, ExynosBuffer *buf);

    bool        m_getResolutionList(String8 & string8Buf, char * strBuf, int w, int h);

    bool        m_getZoomRatioList(String8 & string8Buf, char * strBuf, int maxZoom, int start, int end);

    int         m_bracketsStr2Ints(char *str, int num, ExynosRect2 *rect2s, int *weights);
    bool        m_subBracketsStr2Ints(int num, char *str, int *arr);
    bool        m_getRatioSize(int  src_w,  int   src_h,
                               int  dst_w,  int   dst_h,
                               int *crop_x, int *crop_y,
                               int *crop_w, int *crop_h,
                               int zoom);
    int         m_calibratePosition(int w, int new_w, int x);
#ifdef LOG_NDEBUG
    bool        m_fileDump(char *filename, void *srcBuf, uint32_t size);
#endif

private:
    sp<PreviewThread>   m_previewThread;
    sp<VideoThread>     m_videoThread;
    sp<AutoFocusThread> m_autoFocusThread;
    sp<PictureThread>   m_pictureThread;

    /* used by auto focus thread to block until it's told to run */
    mutable Mutex       m_focusLock;
    mutable Condition   m_focusCondition;
            bool        m_exitAutoFocusThread;

    /* used by preview thread to block until it's told to run */
    mutable Mutex       m_previewLock;
    mutable Condition   m_previewCondition;
    mutable Condition   m_previewStoppedCondition;
            bool        m_previewRunning;
            bool        m_exitPreviewThread;
            bool        m_previewStartDeferred;

    mutable Mutex       m_videoLock;
    mutable Condition   m_videoCondition;
    mutable Condition   m_videoStoppedCondition;
            bool        m_videoRunning;
            bool        m_videoStart;
            bool        m_exitVideoThread;
            bool        m_recordingHint;

    void               *m_grallocVirtAddr[NUM_OF_PREVIEW_BUF];
    int                 m_matchedGrallocIndex[NUM_OF_PREVIEW_BUF];
    ExynosBuffer        m_pictureBuf;
    ExynosBuffer        copy_previewBuf;

    struct ExynosBufferQueue {
        ExynosBuffer       buf;
        ExynosBufferQueue *next;
    };

    ExynosBufferQueue  *m_oldPictureBufQueueHead;
    ExynosBufferQueue   m_oldPictureBufQueue[NUM_OF_PICTURE_BUF];
    mutable Mutex       m_pictureLock;
    mutable Condition   m_pictureCondition;
            bool        m_pictureRunning;
            bool        m_captureInProgress;
            int         m_numOfAvaliblePictureBuf;

    ExynosRect          m_orgPreviewRect;
    ExynosRect          m_orgPictureRect;
    ExynosRect          m_orgVideoRect;

    void               *m_exynosPreviewCSC;
    void               *m_exynosPictureCSC;
    void               *m_exynosVideoCSC;

            preview_stream_ops *m_previewWindow;

    /* used to guard threading state */
    mutable Mutex       m_stateLock;

    CameraParameters    m_params;
    CameraParameters    m_internalParams;

    camera_memory_t    *m_previewHeap[NUM_OF_PREVIEW_BUF];
    buffer_handle_t    *m_previewBufHandle[NUM_OF_PREVIEW_BUF];
    int                 m_previewStride[NUM_OF_PREVIEW_BUF];
    bool                m_avaliblePreviewBufHandle[NUM_OF_PREVIEW_BUF];
    bool                m_flagGrallocLocked[NUM_OF_PREVIEW_BUF];
    int                 m_minUndequeuedBufs;
    int                 m_numOfAvailableVideoBuf;
    int                 m_cntVideoBuf;

    camera_memory_t    *m_videoHeap[NUM_OF_VIDEO_BUF];
    camera_memory_t    *m_resizedVideoHeap[NUM_OF_VIDEO_BUF];
    camera_memory_t    *m_pictureHeap[NUM_OF_PICTURE_BUF];
    int			m_pictureFds[NUM_OF_PICTURE_BUF][3];
    camera_memory_t    *m_rawHeap;
    int			m_ion_client;

    camera_frame_metadata_t  m_frameMetadata;
    camera_face_t            m_faces[NUM_OF_DETECTED_FACES];
    bool                     m_faceDetected;

    ExynosCamera       *m_secCamera;

    mutable Mutex       m_skipFrameLock;
            int         m_skipFrame;

    camera_notify_callback     m_notifyCb;
    camera_data_callback       m_dataCb;
    camera_data_timestamp_callback m_dataCbTimestamp;
    camera_request_memory      m_getMemoryCb;
    void                      *m_callbackCookie;

            int32_t     m_msgEnabled;

           Vector<Size> m_supportedPreviewSizes;

    camera_device_t *m_halDevice;
    static gralloc_module_t const* m_grallocHal;
};

}; // namespace android

#endif