/*
 * ********************************************************************************************************************
 *
 *               iFHS7.
 *              ;BBMBMBMc                  rZMBMBR              BMB
 *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
 *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
 *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
 *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
 *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
 *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
 *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
 *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
 *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
 *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
 *         i0BM: SWKHKGO  MBDv
 *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
 *              ,  XMW  ..
 *                  r                                                                     All rights reserved.
 *
 * ********************************************************************************************************************
 */

package com.sybotan.android.views

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.graphics.*
import android.hardware.camera2.*
import android.media.ImageReader
import android.os.Handler
import android.os.HandlerThread
import android.util.AttributeSet
import android.util.Log
import android.util.Size
import android.util.SparseIntArray
import android.view.OrientationEventListener
import android.view.Surface
import android.view.TextureView
import com.sybotan.android.base.comparators.SSizesByAreaComparator
import com.sybotan.views.R
import org.jetbrains.anko.dip
import java.util.*
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit

/**
 * 摄像机View
 *
 * @author
 */
open class SCameraView(context: Context, attrs: AttributeSet? = null) : SAutoFitTextureView(context, attrs) {
    companion object {
        // 日志
        private val TAG = SCameraView::class.java.name
        private val ORIENTATIONS =  SparseIntArray()
        /** 最大预览宽度 */
        private const val MAX_PREVIEW_WIDTH = 1920
        /** 最大预览高度 */
        private const val MAX_PREVIEW_HEIGHT = 1080
    } // companion object



    /** 摄像头管理器 */
    val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    /** 摄像头ID列表 */
    val cameraIdList: Array<out String> = manager.cameraIdList
    var cameraId = "0"
    /** 当前打开的摄像头 */
    var cameraDevice: CameraDevice? = null
    var previewSize = Size(1920, 1080)
    /** 摄像头传感器方向 */
    private var cameraSensorOrientation: Int = 0
    private var previewRequestBuilder: CaptureRequest.Builder? = null
    private var cameraCaptureSession: CameraCaptureSession? = null

    // 摄像机后台线程
    private var cameraThread: HandlerThread? = null
    private var cameraHandler: Handler? = null
    private val cameraOpenCloseLock = Semaphore(1)
    private val stateCallback = CameraStateCallback()
    private val captureCallback = CaptureCallback()

    // 抓图相关
    private var imageReader: ImageReader? = null
    private var imageAvailableListener = ImageAvailableListener()

    /** 旋转方向，默认不旋转 */
    var rotation: Int = Surface.ROTATION_0
        set(value) {
            field = value
            configureTransform(width, height)
        }

    /** 旋转监听器 */
    val orientationEventListener = object : OrientationEventListener(context) {
        /**
         * 方向改变时调用
         *
         * @param   orientation     方向单位度
         */
        override fun onOrientationChanged(orientation: Int) {
            // 防止负值出现（有时会采集到旋转-1，画面会闪动）
            val rot = (orientation + 360) % 360
            Log.v(TAG, "orientation = $rot")
            rotation = when{
                (rot <= 45 || rot > 315) -> Surface.ROTATION_0
                (rot in 46..135) -> Surface.ROTATION_270
                (rot in 136..225) -> Surface.ROTATION_180
                else -> Surface.ROTATION_90
            }
            return
        } // Function onOrientationChanged()
    }

    /** 初始化 */
    init {
        // 保证照片竖直显示的映射关系
        ORIENTATIONS.append(Surface.ROTATION_0, 90)
        ORIENTATIONS.append(Surface.ROTATION_90, 0)
        ORIENTATIONS.append(Surface.ROTATION_180, 270)
        ORIENTATIONS.append(Surface.ROTATION_270, 180)

        // 启动摄像头线程
        startCameraThread()
    } // init

    @SuppressLint("MissingPermission")
    fun openCamera(width:Int = 1920, height: Int = 1080, cameraId: String ="0"): Boolean {
        if (!isAvailable) {
            surfaceTextureListener = TextureListener()
            return true
        }

        setCameraOutputs(cameraId, width, height)
        configureTransform(width, height)

        try {
            if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw RuntimeException("Time out waiting to lock cameraDevice opening.")
            }
            Log.d(TAG, "openCamera(cameraId=$cameraId)")
            manager.openCamera(cameraId, stateCallback, cameraHandler)
        } catch (e: CameraAccessException) {
            e.printStackTrace()
            return false
        } catch (e: InterruptedException) {
            e.printStackTrace()
            return false
        }

        return true
    } // Function openCamera()

    /**
     * 关闭摄像头
     */
    fun closeCamera() {
        try {
            cameraOpenCloseLock.acquire()
            if (null != cameraCaptureSession) {
                cameraCaptureSession!!.close()
                cameraCaptureSession = null
            }
            if (null != cameraDevice) {
                cameraDevice!!.close()
                cameraDevice = null
            }
            if (null != imageReader) {
                imageReader!!.close()
                imageReader = null
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            cameraOpenCloseLock.release()
        }
        return
    } // Function closeCamera()

    /**
     * 判断摄像头是否打开
     *
     * @return  如果打开返回true，否则返回false。
     */
    @Synchronized
    fun isOpen(): Boolean {
        return cameraDevice != null
    } // Function isOpen()

    /**
     * 将焦点锁定为静态图像捕获的第一步。（对焦）
     */
    private fun lockFocus() {
        try {
            // 摄像头对焦
            previewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START)
            // 修改状态
            //mState = STATE_WAITING_LOCK;
            cameraCaptureSession!!.capture(previewRequestBuilder!!.build(), captureCallback, cameraHandler)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return
    } // Function lockFocus()

    /**
     * 解锁焦点
     */
    private fun unlockFocus() {
        try {
            // 重置自动对焦
            previewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
            //setAutoFlash(previewRequestBuilder)
            cameraCaptureSession!!.capture(previewRequestBuilder!!.build(), captureCallback, cameraHandler)
            // 将相机恢复正常的预览状态。
            //mState = STATE_PREVIEW;
            // 打开连续取景模式
            // cameraCaptureSession!!.setRepeatingRequest(previewRequest, captureCallback, cameraHandler)
        } catch (e: Exception) {
            e.printStackTrace()
        }

        return
    } // Function unlockFocus()

//    /**
//     * 初始化摄像头
//     */
//    private fun initCamera(holder: SurfaceHolder) {
//        try {
//            Log.e(TAG, "cameraList ===================")
//            openCamera("0")
//        } catch (e: Exception) {
//
//        }
//        return
//    } // Function initCamera()

    /**
     * 启动摄像头线程
     */
    private fun startCameraThread() {
        if (cameraThread != null) {
            return
        }

        cameraThread = HandlerThread("CameraBackground")
        cameraThread!!.start()
        cameraHandler = Handler(cameraThread!!.looper)
        return
    } // Function startCameraThread()

    /**
     * 停止摄像机线程
     */
    private fun stopCameraThread() {
        cameraThread!!.quitSafely()
        try {
            cameraThread!!.join()
            cameraThread = null
            cameraHandler = null
        } catch (e: InterruptedException) {
            e.printStackTrace()
        }
        return
    } // Function stopBackgroundThread()

    /**
     * 设置摄像头输出
     *
     * @param   cameraId    摄像头ID
     * @param   width       宽度
     * @param   height      高度
     */
    private fun setCameraOutputs(cameraId: String, width: Int, height: Int) {
        // 获得某个摄像头的特征，支持的参数
        val characteristics = manager.getCameraCharacteristics(cameraId)
        // 支持的STREAM CONFIGURATION
        val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
        val largest = Collections.max(Arrays.asList<Size>(*map.getOutputSizes(ImageFormat.YUV_420_888)), SSizesByAreaComparator())

        imageReader = ImageReader.newInstance(largest.width, largest.height, ImageFormat.YUV_420_888, 2)
        //设置图片的质量
        imageReader!!.setOnImageAvailableListener(imageAvailableListener, cameraHandler)


        var swappedDimensions = false
        cameraSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: 0
        when (rotation) {
            Surface.ROTATION_0, Surface.ROTATION_180 -> {
                if (cameraSensorOrientation == 90 || cameraSensorOrientation == 270) {
                    swappedDimensions = true
                }
            }
            Surface.ROTATION_90, Surface.ROTATION_270 -> {
                if (cameraSensorOrientation == 0 || cameraSensorOrientation == 180) {
                    swappedDimensions = true
                }
            }
            else -> {
                Log.e(TAG, "Display rotation is invalid: " + rotation)
            }
        }

        val displaySize = Point()
        //activity.getWindowManager().getDefaultDisplay().getSize(displaySize)
        var rotatedPreviewWidth = width
        var rotatedPreviewHeight = height
        var maxPreviewWidth = displaySize.x
        var maxPreviewHeight = displaySize.y

        if (swappedDimensions) {
            rotatedPreviewWidth = height
            rotatedPreviewHeight = width
            maxPreviewWidth = displaySize.y
            maxPreviewHeight = displaySize.x
        }

        if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
            maxPreviewWidth = MAX_PREVIEW_WIDTH
        }

        if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
            maxPreviewHeight = MAX_PREVIEW_HEIGHT
        }

        previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java),
                rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                maxPreviewHeight, largest)

        // 根据配置是横屏还是竖屏设置比例
        val orientation = resources.configuration.orientation
        aspectRatio = if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Size(width, height)
        } else {
            Size(height, width)
        }

        return
    } // Function setCameraOutputs()

    private fun chooseOptimalSize(choices: Array<Size>, textureViewWidth: Int,
                                  textureViewHeight: Int, maxWidth: Int, maxHeight: Int, aspectRatio: Size): Size {

        val bigEnough = ArrayList<Size>()
        val notBigEnough = ArrayList<Size>()
        val w = aspectRatio.width
        val h = aspectRatio.height
        for (option in choices) {
            if (option.width <= maxWidth && option.height <= maxHeight &&
                    option.height == option.width * h / w) {
                if (option.width >= textureViewWidth && option.height >= textureViewHeight) {
                    bigEnough.add(option)
                } else {
                    notBigEnough.add(option)
                }
            }
        }

        // Pick the smallest of those big enough. If there is no one big enough, pick the
        // largest of those not big enough.
        return when {
            bigEnough.size > 0 -> Collections.min(bigEnough, SSizesByAreaComparator())
            notBigEnough.size > 0 -> Collections.max(notBigEnough, SSizesByAreaComparator())
            else -> {
                choices[0]
            }
        }
    } // Function chooseOptimalSize()

    /**
     * 配置摄像头变换,使画面的显示与摄像头相同
     *
     * @param   viewWidth       视图宽度
     * @param   viewHeight      视图高度
     */
    private fun configureTransform(viewWidth: Int, viewHeight: Int) {
        val matrix = Matrix()
        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
        val bufferRect = RectF(0f, 0f, previewSize.height.toFloat(), previewSize.width.toFloat())
        val centerX = viewRect.centerX()
        val centerY = viewRect.centerY()

        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY())
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
            val scale = Math.max( viewHeight.toFloat() / previewSize.height, viewWidth.toFloat() / previewSize.width)
            matrix.postScale(scale, scale, centerX, centerY)
            matrix.postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180f, centerX, centerY)
        }

        setTransform(matrix)
        return
    } // Function configureTransform()

    /**
     * 创建摄像头预览会话
     */
    private fun createCameraPreviewSession(){
        Log.d(TAG, "createCameraPreviewSession")
        try {
            val surface = Surface(surfaceTexture)
            previewRequestBuilder = cameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            previewRequestBuilder!!.addTarget(surface)
            cameraDevice!!.createCaptureSession(arrayListOf(surface, imageReader!!.surface), CaptureSessionStateCallback(), null)
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
        return
    } // Function createCameraPreviewSession()

    /**
     * 纹理监听器
     *
     * @author 庞利祥(sybotan@126.com)
     */
    inner class TextureListener : TextureView.SurfaceTextureListener {
        /**
         * 纹理表表创建完成
         *
         * @param   surface     纹理表面
         * @param   width       宽度
         * @param   height      高度
         */
        override fun onSurfaceTextureAvailable(surface: SurfaceTexture?, width: Int, height: Int) {
            Log.d("SCAMERA","size ===== ${width}, ${height}")
            openCamera(dip(width), dip(height), cameraId)
            return
        } // Function onSurfaceTextureAvailable

        /**
         * 纹理大小变更回调
         *
         * @param   surface     纹理表面
         * @param   width       宽度
         * @param   height      高度
         */
        override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture?, width: Int, height: Int) {
            configureTransform(width, height)
            return
        } // Function onSurfaceTextureSizeChanged()

        /**
         * 纹理更新完成
         *
         * @param   surface     纹理表面
         */
        override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {
            // DO NOTHING
            return
        } // Function onSurfaceTextureUpdated()

        /**
         * 纹理注销时调用
         *
         * @param   surface     纹理表面
         */
        override fun onSurfaceTextureDestroyed(surface: SurfaceTexture?): Boolean {
            return true
        } // Function onSurfaceTextureDestroyed

    } // Class TextureListener

    /**
     * 摄像头状态回调
     *
     * @author 庞利祥(sybotan@126.com)
     */
    inner class CameraStateCallback: CameraDevice.StateCallback() {
        /**
         * 打开摄像头
         */
        override fun onOpened(camera: CameraDevice) {
            cameraOpenCloseLock.release()
            cameraDevice = camera
            createCameraPreviewSession()
            return
        } // Function onOpened()

        /**
         * 断开连接
         */
        override fun onDisconnected(camera: CameraDevice) {
            cameraOpenCloseLock.release()
            if (null != cameraDevice) {
                cameraDevice!!.close()
                cameraDevice = null
            }
            return
        } // Function onDisconnected()

        /**
         * 错误
         */
        override fun onError(camera: CameraDevice, error: Int) {
            onDisconnected(camera)
            return
        } // Function onError()

    } // Class CameraStateCallback

    /**
     * 捕获会话状态回调
     *
     * @author
     */
    inner class CaptureSessionStateCallback : CameraCaptureSession.StateCallback() {
        /**
         * 配置完成时回调
         *
         * @param   session     捕捉会话
         */
        override fun onConfigured(session: CameraCaptureSession?) {
            if (null == cameraDevice) {     // 摄像头关闭
                return
            }
            cameraCaptureSession = session
            try {
                // 启动自动对焦
                previewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
                // Flash is automatically enabled when necessary.
                // setAutoFlash(previewRequestBuilder)

                // 启动显示
                val previewRequest = previewRequestBuilder!!.build()
                cameraCaptureSession!!.setRepeatingRequest(previewRequest, captureCallback, cameraHandler)
            } catch (e: CameraAccessException) {
                e.printStackTrace()
            }


            return
        } // Function onConfigured()

        /**
         * 配置失败
         *
         * @param   session     捕捉会话
         */
        override fun onConfigureFailed(session: CameraCaptureSession?) {
            Log.e(TAG, "onConfigureFailed")
            return
        } // Function onConfigureFailed()
    } // Class CaptureSessionStateCallback

    inner class CaptureCallback : CameraCaptureSession.CaptureCallback() {

        override fun onCaptureProgressed(session: CameraCaptureSession,
                                         request: CaptureRequest,
                                         partialResult: CaptureResult) {
            //process(partialResult)
            return
        } // Function onCaptureProgressed()

        override fun onCaptureCompleted(session: CameraCaptureSession,
                                        request: CaptureRequest,
                                        result: TotalCaptureResult) {
            //process(result)
            return
        } // Function onCaptureCompleted()
    } // Class CaptureSessionCaptureCallback

    /**
     * 捕捉图像装备好事件
     *
     * @author  Andy
     */
    inner class ImageAvailableListener : ImageReader.OnImageAvailableListener {
        override fun onImageAvailable(reader: ImageReader) {
            val image = reader.acquireNextImage()
            if (image != null) {
                val buffer = image.planes[0].buffer
                val bytes = ByteArray(buffer.remaining())
                buffer.get(bytes)
                image.close()
            }
            return
        } // Function onImageAvailable()

    } // Function ImageAvailableListener()
} // Class SCameraView