package com.lemonhc.mplus.mcare_plus.activity

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.hardware.camera2.*
import android.hardware.camera2.params.StreamConfigurationMap
import android.media.ImageReader
import android.media.MediaActionSound
import android.os.*
import androidx.core.app.ActivityCompat
import android.util.DisplayMetrics
import android.util.Log
import android.util.Size
import android.view.Surface
import android.view.TextureView
import android.view.View
import android.view.WindowManager
import android.widget.Button
import android.widget.ImageButton
import androidx.lifecycle.Observer
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.MutableLiveData
import com.lemonhc.mplus.framework.util.Exif
import com.lemonhc.mplus.framework.util.kotlinExtension.format
import com.lemonhc.mplus.framework.util.kotlinExtension.isCaptureFlag
import com.lemonhc.mplus.mcare_plus.R
import com.lemonhc.mplus.mcare_plus.activity.PhotoActivity.Companion.user
import com.lemonhc.mplus.mcare_plus.activity.camera.Preview
import com.lemonhc.mplus.model.Photo
import com.lemonhc.mplus.model.save
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.jetbrains.anko.Android
import org.jetbrains.anko.displayMetrics
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.util.*
import java.util.concurrent.Semaphore

/**
 * 커스텀 카메라
 */
class CameraActivity: AppCompatActivity() {
    //원본 저장경로
    var photoPath = "${Environment.getExternalStorageDirectory()}/kunkuk"
    //썸네일 저장경로
    var thumbPath = "${Environment.getExternalStorageDirectory()}/kunkuk/thumb"

    open val cameraReturnCode = 2000

    //카메라 관련 변수

    lateinit var mPreview: Preview
    lateinit var bitmap: Bitmap
    lateinit var cameraPreview: TextureView
    lateinit var mPreviewSize: Size
    lateinit var imageReader: ImageReader

    private var mCameraDevice: CameraDevice? = null
    private var mPreviewSession: CameraCaptureSession? = null
    private var mCameraId: String? = null
    private var mCameraManager: CameraManager? = null
    private val thread = HandlerThread("CameraPreview").also {
        it.start()
    }
    private val backgroundHandler = Handler(thread.looper)

    //캡쳐버튼
    private lateinit var capture: ImageButton
    //종료버튼
    private lateinit var bt_finish: ImageButton
    //앨범버튼
    private lateinit var bt_gallary: ImageButton
    //환자번호
    private lateinit var bt_patientId: Button
    //환자이름
    private lateinit var bt_patientNm: Button
    //환자나이/성별
    private lateinit var bt_ageGender: Button

    private lateinit var imageButton: ImageButton

    private lateinit var bt_deptNm: Button
    private lateinit var bt_treatClsKr: Button
    private lateinit var bt_doctorNm: Button
    private lateinit var bt_title: Button

//    var orientation = 90
    var orientation = 0

    var patientId = MutableLiveData<String>()
    var patientNm = MutableLiveData<String>()
    var ageGender = MutableLiveData<String>()
    var deptNm = MutableLiveData<String>()
    var treatClsKr = MutableLiveData<String>()
    var doctorNm = MutableLiveData<String>()
    var titles = MutableLiveData<String>()

    var isTakePicture = true
    var isCameraRelease = false
    var sound:MediaActionSound = MediaActionSound()

    private lateinit var mRequestBuilder: CaptureRequest.Builder

    /**
     * A [Semaphore] to prevent the app from exiting before closing the camera.
     */
    private val cameraOpenCloseLock = Semaphore(1)

    private val onImageAvailableListener = ImageReader.OnImageAvailableListener {
        val image = it.acquireLatestImage()
        val buffer = image.planes[0].buffer
        val bytes = ByteArray(buffer.remaining())
        buffer.get(bytes)
        onPictureTaken(bytes)
        image.close()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (!isCaptureFlag) {
            window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
        }

        // 레이아웃 초기화
        setContentView(R.layout.activity_camera).run {
            cameraPreview = findViewById(R.id.cPreview)
            capture = findViewById(R.id.btnCam)
            bt_finish = findViewById(R.id.bt_finish)
            bt_gallary = findViewById(R.id.bt_gallary)
            bt_patientId = findViewById(R.id.patientId)
            bt_patientNm = findViewById(R.id.patientNm)
            bt_ageGender = findViewById(R.id.agegender)
            imageButton = findViewById(R.id.imageButton)
            bt_deptNm = findViewById(R.id.deptNm)
            bt_treatClsKr = findViewById(R.id.treatClsKr)
            bt_doctorNm = findViewById(R.id.doctorNm)
            bt_title = findViewById(R.id.titles)
        }

        // 강제 스크린 ON
        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        MainActivity.isVisibleCamera = true
        // 카메라 퍼미션이 있다면
//        if (checkPermissionCamera()) {
//            mPreview = Preview(this@CameraActivity, cameraPreview)
//            // 서페이스뷰가 사용가능하다면 프리뷰를 보여준다.
//            cameraPreview.surfaceTextureListener = object: TextureView.SurfaceTextureListener{
//                override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture?, p1: Int, p2: Int) {
//                }
//                override fun onSurfaceTextureUpdated(p0: SurfaceTexture?) {
//                }
//                override fun onSurfaceTextureDestroyed(p0: SurfaceTexture?): Boolean {
//                    return false
//                }
//                override fun onSurfaceTextureAvailable(p0: SurfaceTexture?, p1: Int, p2: Int) {
//                    openCamera()
//                }
//            }
//        }

        kotlin.run {
            patientId.observe(this, Observer {
                bt_patientId.text = it
            })

            patientNm.observe(this, Observer {
                bt_patientNm.text = it
            })

            ageGender.observe(this, Observer {
                bt_ageGender.text = it
            })

            deptNm.observe(this, Observer {
                bt_deptNm.text = it
            })

            treatClsKr.observe(this, Observer {
                bt_treatClsKr.text = it
            })

            doctorNm.observe(this, Observer {
                bt_doctorNm.text = it
            })

            titles.observe(this, Observer {
                bt_title.text = it
            })
        }

        //종료버튼 클릭리스너
        bt_finish.setOnClickListener(finishAction())
        imageButton.setOnClickListener(finishAction())

        //앨범 클릭리스너
        bt_gallary.setOnClickListener(gallaryAction())

        capture.setOnClickListener(captureAction())

        patientId.value = user.patientId
        patientNm.value = user.patientNm
        ageGender.value = "${user.age} / ${user.gender}"
        deptNm.value = user.deptNm
        treatClsKr.value = user.treatClsKr
        doctorNm.value = user.doctorNm
        titles.value = "${Date().format("yyyy-MM-dd")} ${user.treatClsKr} ${user.deptNm}"

    }

    public override fun onResume() {
        super.onResume()
        if (checkPermissionCamera()) {
            if (cameraPreview.isAvailable) {
                resumeCamera()
            } else {
                mPreview = Preview(this@CameraActivity, cameraPreview)
                // 서페이스뷰가 사용가능하다면 프리뷰를 보여준다.
                cameraPreview.surfaceTextureListener = object: TextureView.SurfaceTextureListener{
                    override fun onSurfaceTextureSizeChanged(p0: SurfaceTexture?, p1: Int, p2: Int) {
                    }
                    override fun onSurfaceTextureUpdated(p0: SurfaceTexture?) {
                    }
                    override fun onSurfaceTextureDestroyed(p0: SurfaceTexture?): Boolean {
                        return false
                    }
                    override fun onSurfaceTextureAvailable(p0: SurfaceTexture?, p1: Int, p2: Int) {
                        openCamera(p1, p2)
                    }
                }
            }
        }
    }

    override fun onPause() {
        super.onPause()
        //when on Pause, release camera in order to be used from other applications
        releaseCamera()
    }

    //가로 세로 변경시 호출. 사진 저장시 rotate값을 넣어주기 위한 함수
    override fun onConfigurationChanged(newConfig: Configuration?) {
        super.onConfigurationChanged(newConfig)

        if(newConfig?.orientation == Configuration.ORIENTATION_LANDSCAPE){
            orientation = 0
        }else{
            orientation = 90
        }
    }

    /**
     * 카메라를 얻어와 전역변수에 세팅하고 프리뷰 이미지를 보여준다.
     */
    @SuppressLint("MissingPermission")
    fun openCamera(width: Int, height: Int) {
        this.mCameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
        try {
            this.mCameraId = getBackFacingCameraId(mCameraManager!!)

            val characteristics: CameraCharacteristics = this.mCameraManager!!.getCameraCharacteristics(this.mCameraId)
            val map: StreamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)

            val largest = Collections.max(Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)), CompareSizesByArea())
            imageReader = ImageReader.newInstance(largest.width, largest.height, ImageFormat.JPEG, /*maxImages*/ 2).apply {
                setOnImageAvailableListener(onImageAvailableListener, backgroundHandler)
            }

            // 실제 레이아웃의 프리뷰 사이즈를 구한다
            var test  = cameraPreview.width
            var test2 = cameraPreview.height


            var displayMetrics:DisplayMetrics = DisplayMetrics()
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
var height1 = displayMetrics.heightPixels;
var width1 = displayMetrics.widthPixels;

            // 카메라로 얻은 프리뷰의 사이즈를 잘라서 적용한다.




//            mPreviewSize = map.getOutputSizes(SurfaceTexture::class.java).first()

            // Find out if we need to swap dimension to get the preview size relative to sensor
            // coordinate.
            val displayRotation = this.windowManager.defaultDisplay.rotation

            orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION)
            val swappedDimensions = areDimensionsSwapped(displayRotation)

            val displaySize = Point()
            this.windowManager.defaultDisplay.getSize(displaySize)
            val rotatedPreviewWidth = if (swappedDimensions) height else width
            val rotatedPreviewHeight = if (swappedDimensions) width else height
            var maxPreviewWidth = if (swappedDimensions) displaySize.y else displaySize.x
            var maxPreviewHeight = if (swappedDimensions) displaySize.x else displaySize.y

            if (maxPreviewWidth > 1920) maxPreviewWidth = 1920
            if (maxPreviewHeight > 1080) maxPreviewHeight = 1080

            // Danger, W.R.! Attempting to use too large a preview size could  exceed the camera
            // bus' bandwidth limitation, resulting in gorgeous previews but the storage of
            // garbage capture data.
            mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture::class.java), rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth, maxPreviewHeight, largest)


            configureTransform(width, height)

            val callback = object: CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    cameraOpenCloseLock.release()
                    mCameraDevice = camera
                    startPreview()
                }
                override fun onDisconnected(p0: CameraDevice) {
                    cameraOpenCloseLock.release()
                    p0.close()
                    mCameraDevice = null
                }
                override fun onError(p0: CameraDevice, p1: Int) {
                    onDisconnected(p0)
                }
            }
            this.mCameraManager!!.openCamera(this.mCameraId, callback, backgroundHandler)
        } catch(e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    /**
     * back 카메라를 얻어온다.
     */
    private fun getBackFacingCameraId(manager: CameraManager): String? {
        try {
            for (cameraId: String in manager.cameraIdList) {
                val characteristics: CameraCharacteristics = manager.getCameraCharacteristics(cameraId)
                val cOrientation: Int = characteristics.get(CameraCharacteristics.LENS_FACING)
                if (cOrientation == 1) {
                    return cameraId
                }
            }
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * 프리뷰 실행을 위한 세션 생성
     */
    fun startPreview() {
        val unit = try {
            val texture: SurfaceTexture = cameraPreview.surfaceTexture ?: return
            texture.setDefaultBufferSize(mPreviewSize.width, mPreviewSize.height)
            val surface = Surface(texture)

            // 사진 촬영을 위한 리더객체를 세션에 추가한다.
//            imageReader = ImageReader.newInstance(mPreviewSize.width, mPreviewSize.height, ImageFormat.JPEG, 1).apply {
//                setOnImageAvailableListener(onImageAvailableListener, backgroundHandler)
//            }

            mRequestBuilder = mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            // 프리뷰를 보여줄 타겟팅...미리보기 이므로 textureView
            mRequestBuilder.addTarget(surface)

            val callback = object : CameraCaptureSession.StateCallback() {
                override fun onConfigured(cameraCaptureSession: CameraCaptureSession?) {
                    // The camera is already closed
                    this@CameraActivity.mCameraDevice ?: return

                    // When the session is ready, we start displaying the preview.
                    mPreviewSession = cameraCaptureSession
                    try {

                        if (isAutoFocusSupported()) {

                            this@CameraActivity.mRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO)
                            this@CameraActivity.mRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) // 삼성폰에서만 그런건지..


                            mPreviewSession?.setRepeatingRequest(this@CameraActivity.mRequestBuilder.build(), null, backgroundHandler)
                        } else {

                            this@CameraActivity.mRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
                            mPreviewSession?.setRepeatingRequest(this@CameraActivity.mRequestBuilder.build(), null, backgroundHandler)
                        }

                    } catch (e: CameraAccessException) {
                        e.printStackTrace()
                    }
                }

                override fun onConfigureFailed(session: CameraCaptureSession?) {
                }


            }
            mCameraDevice?.createCaptureSession(listOf(surface, imageReader.surface), callback, null)
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    /**
     * 액티비티 재실행
     */
    private fun resumeCamera() {
        openCamera(mPreviewSize.width, mPreviewSize.height)
    }

    /**
     * 액티비티 종료
     */
    private fun releaseCamera() {
        mCameraDevice?.close()
        mCameraDevice = null
    }

    /**
     * 사진 촬영
     */
    fun takePicture() {
        try {
            val builder: CaptureRequest.Builder? = mCameraDevice?.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
            // 캡쳐실행을 위한 리퀘스트 타겟을 리더 객체로 생성한다.
            builder?.addTarget(imageReader.surface)
            builder?.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
            builder?.set(CaptureRequest.JPEG_ORIENTATION, orientation)

            val captureCallback = object: CameraCaptureSession.CaptureCallback() {
                override fun onCaptureCompleted(session: CameraCaptureSession, request: CaptureRequest, result: TotalCaptureResult) {
                    unlockFocus()
                }
            }

            // 프리뷰를 멈춤
            mPreviewSession?.apply {
                stopRepeating()
                abortCaptures()
                capture(builder?.build(), captureCallback, null)
            }

            // 사운드와 애니메이션 실행
            CoroutineScope(Dispatchers.Default).launch {
                sound = MediaActionSound()
                sound.play(MediaActionSound.SHUTTER_CLICK)

                shutterCallback()
            }
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    fun isAutoFocusSupported(): Boolean{
        getMinimumFocusDistance()
        return isHardwareLevelSupported(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) || getMinimumFocusDistance() > 0
    }

    private fun isHardwareLevelSupported(requiredLevel:Int):Boolean{
        var res = false
        if (this.mCameraId == null) {
            return res
        }
        val cameraCharacteristics:CameraCharacteristics = this.mCameraManager!!.getCameraCharacteristics(this.mCameraId)

        val deviceLevel:Int = cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)

        when(deviceLevel){

            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 -> {

            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL ->{

            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY ->{

            }
            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED ->{

            }

        }

        if( deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY){
            res = requiredLevel == deviceLevel
        } else {
            res = requiredLevel <= deviceLevel
        }
        return res
    }

    private fun getMinimumFocusDistance():Float {
        if (this.mCameraId == null){
            return 0.0f
        }
        var minimumLens:Float? = null
        var c:CameraCharacteristics = this.mCameraManager!!.getCameraCharacteristics(this.mCameraId)
        minimumLens = c.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)

        if (minimumLens != null){
            return minimumLens
        }else{
            return 0.0f
        }
    }

    // shutter action animation
    private fun shutterCallback() {
        CoroutineScope(Dispatchers.Main).launch {
            cameraPreview.visibility = View.INVISIBLE

            // 안드로이드 7.1보다 낮은 기계는 메모리 이슈가 있으므로 딜레이를 많이 준다.
            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
                delay(500)
                sound.release() // 저사양 단말에서 메모리 딸리면 셔터소리가 안나서, 한번 소리내고 메모리 해제함. 근데 가비지 컬랙션은 일 안하냐?
            } else {
                delay(100)
            }
            CoroutineScope(Dispatchers.Main).launch {
                cameraPreview.visibility = View.VISIBLE

            }
        }
    }

    /**
     * 멈춘 프리뷰를 재 실행
     */
    fun unlockFocus() {
        try {
            this@CameraActivity.mRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL)
            this@CameraActivity.mPreviewSession?.capture(this@CameraActivity.mRequestBuilder.build(), null, backgroundHandler)
            this@CameraActivity.mPreviewSession?.setRepeatingRequest(this@CameraActivity.mRequestBuilder.build(), null, backgroundHandler)
        } catch (e: CameraAccessException) {
            e.printStackTrace()
        }
    }

    /**
     * Determines if the dimensions are swapped given the phone's current rotation.
     *
     * @param displayRotation The current rotation of the display
     *
     * @return true if the dimensions are swapped, false otherwise.
     */
    private fun areDimensionsSwapped(displayRotation: Int): Boolean {
        var swappedDimensions = false
        when (displayRotation) {
            Surface.ROTATION_0, Surface.ROTATION_180 -> {
                if (orientation == 90 || orientation == 270) {
                    swappedDimensions = true
                }
            }
            Surface.ROTATION_90, Surface.ROTATION_270 -> {
                if (orientation == 0 || orientation == 180) {
                    swappedDimensions = true
                }
            }
            else -> {
                Log.e("##########", "Display rotation is invalid: $displayRotation")
            }
        }
        return swappedDimensions
    }

    /**
     * Configures the necessary [android.graphics.Matrix] transformation to `textureView`.
     * This method should be called after the camera preview size is determined in
     * setUpCameraOutputs and also the size of `textureView` is fixed.
     *
     * @param viewWidth  The width of `textureView`
     * @param viewHeight The height of `textureView`
     */
    private fun configureTransform(viewWidth: Int, viewHeight: Int) {
        val rotation = this.windowManager.defaultDisplay.rotation
        val matrix = Matrix()
        val viewRect = RectF(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())
        val bufferRect = RectF(0f, 0f, mPreviewSize.height.toFloat(), mPreviewSize.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())
            val scale = Math.max(
                    viewHeight.toFloat() / mPreviewSize.height,
                    viewWidth.toFloat() / mPreviewSize.width)
            with(matrix) {
                setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL)
                postScale(scale, scale, centerX, centerY)
                postRotate((90 * (rotation - 2)).toFloat(), centerX, centerY)
            }
        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180f, centerX, centerY)
        }
        cameraPreview.setTransform(matrix)
    }

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

            // Collect the supported resolutions that are at least as big as the preview Surface
            val bigEnough = ArrayList<Size>()
            // Collect the supported resolutions that are smaller than the preview Surface
            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.
            if (bigEnough.size > 0) {
                return Collections.min(bigEnough, CompareSizesByArea())
            } else if (notBigEnough.size > 0) {
                return Collections.max(notBigEnough, CompareSizesByArea())
            } else {
                Log.e("######### ", "Couldn't find any suitable preview size")
                return choices[0]
            }
        }
    }

}

/**
 * 카메라 촬영버튼 이후 들어오는 콜백
 */
fun CameraActivity.onPictureTaken(data: ByteArray) {
    // 시간이 오래 걸리므로 백그라운드로 돌린다
    CoroutineScope(Dispatchers.Default).launch {
        // 바이트어레이로 비트맵을 만든다
        bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)

        val width: Int = bitmap.width
        val height: Int = bitmap.height
        var ratio = 1
        if (width > 1280) {
            ratio = width / 1280
        }

        bitmap = Bitmap.createScaledBitmap(bitmap, width / ratio, height / ratio, true)
        // 90도 각도로 정렬한다
        bitmap = Exif.rotate(bitmap, orientation)

        val directory = File(this@onPictureTaken.photoPath)
        val imageName = "kunkuk_${System.currentTimeMillis()}.jpg"
        try {
            // sdk 24 이상, 누가(7.0) 분기처리
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                val file = File(directory, imageName)
                FileOutputStream(file).apply {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 70, this@apply)
                    flush()
                    close()
                }
            } else {
                val photoFile = "${this@onPictureTaken.photoPath}/$imageName"
                val file = File(photoFile)
                FileOutputStream(file).apply {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 70, this@apply)
                    flush()
                    close()
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }

        // 썸네일 이미지를 만든다
        startMakeThumnails(imageName)
        val photo:Photo = Photo(user, this@onPictureTaken).apply {
            val toDay: String = Date().format("yyyy-MM-dd")
            var treatCls = ""
            when (user.treatCls) {
                "O" -> treatCls = "외래"
                "I" -> treatCls = "입원"
                "E" -> treatCls = "응급"
            }
            file = imageName
            date = toDay
            key = "$toDay ${user.patientNm} $treatCls, ${user.deptNm}"
            isSended = false
        }
        photo.save()
    }

    CoroutineScope(Dispatchers.Main).launch {
//        Toast.makeText(this@onPictureTaken, "저장완료!", Toast.LENGTH_SHORT).show()
        delay(1000)
        if (!isCameraRelease) {
        }
        isTakePicture = true
    }
}

/**
 * 앨범버튼 이벤트 리스너
 */
fun CameraActivity.gallaryAction(): View.OnClickListener {
    return View.OnClickListener {
        val intent = Intent(this, GallaryActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
        this.startActivity(intent)
        finish()
    }
}

/**
 * 종료버튼 이벤트 리스너
 */
fun CameraActivity.finishAction(): View.OnClickListener {
    return View.OnClickListener {
        finish()
    }
}

/**
 * 촬영버튼 이벤트 리스너
 */
fun CameraActivity.captureAction(): View.OnClickListener {
    return View.OnClickListener {
        if (isTakePicture) {
            isTakePicture = false
            takePicture()
        }
    }
}

/**
 * 썸네일을 만든다
 */
fun CameraActivity.startMakeThumnails(imageName: String) {
    // 코루틴 사용 asyncTask 대치
    CoroutineScope(Dispatchers.Default).launch {
        // 썸네일 디렉토리를 만든다
        val directory = File(this@startMakeThumnails.thumbPath)
        if (!directory.exists()) {
            directory.mkdirs()
        }

        // 원본이미지를 얻어와 썸네일을 만든다
        var bitmap: Bitmap = BitmapDrawable("$photoPath/$imageName").bitmap ?: return@launch
        val height: Int = bitmap.height
        val width: Int = bitmap.width

        bitmap = Bitmap.createScaledBitmap(bitmap, 160, height / (width / 160), true)
        var file: File?
        try{
            // sdk 24 이상, 누가(7.0)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                file = File(directory, imageName)
            } else {//sdk 23 이하, 7.0 미만
                file = File("${this@startMakeThumnails.thumbPath}/$imageName")
            }
            file?.let {
                FileOutputStream(file).apply {
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, this@apply)
                    flush()
                    close()
                }
            }
        } catch (e:IOException) {
            e.printStackTrace()
        }
    }
}

/**
 * 카메라 퍼미션 확인
 */
fun CameraActivity.checkPermissionCamera(): Boolean {
    val chkPerStorage: Boolean = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
    val chkPerCameara: Boolean = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
    if (chkPerStorage || chkPerCameara) {
        val shoPerStorage:Boolean = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
        val shoPerCamera:Boolean = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)
        if (shoPerStorage && shoPerCamera) { // 사용자 권한 취소로 인한 권한 재요청
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA), this.cameraReturnCode)
        } else { // 최초로 권한을 요청
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA), this.cameraReturnCode)
        }
        return false
    } else {
        return true
    }
}
