package com.kdp.starbarcode.camera;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;

import android.view.SurfaceHolder;
import android.widget.Toast;

import com.kdp.starbarcode.core.BarCodeProcessor;
import com.kdp.starbarcode.camera.focus.FocusManager;
import com.kdp.starbarcode.camera.open.OpenCamera;
import com.kdp.starbarcode.camera.open.OpenCameraInterface;
import com.kdp.starbarcode.core.BarCodeScanConfig;
import com.kdp.starbarcode.inter.ICamera;
import com.kdp.starbarcode.view.BarCodePreview;

import java.io.IOException;


/***
 * @author kdp
 * @date 2018/12/11 15:47
 * @description
 */
public class CameraManager implements ICamera {
    private int requestedCameraId = OpenCameraInterface.NO_REQUESTED_CAMERA;
    private OpenCamera mCamera;
    private CameraConfigManager cm;
    private CameraPreviewCallback previewCallback;
    private FocusManager focusManager;
    private BarCodePreview barCodePreview;
    private boolean mInitialized;
    private boolean previewing;
    private Context mContext;

    public CameraManager(BarCodePreview barCodePreview, BarCodeProcessor barCodeProcessor) {
        this.mContext = barCodePreview.getContext();
        this.barCodePreview = barCodePreview;
        this.cm = new CameraConfigManager(mContext);
        this.previewCallback = new CameraPreviewCallback(cm, barCodeProcessor);
    }

    /**
     * 调整识别区域
     */
    private void setRealROI() {
        BarCodeScanConfig barCodeScanConfig = barCodePreview.getBarCodeScanConfig();
        if (barCodeScanConfig == null) return;
        Rect rect = barCodeScanConfig.getROI();
        if (rect == null) return;
        Point cameraResolution = cm.getCameraResolution();
        Point screenResolution = cm.getScreenResolution();
        if (cameraResolution != null && screenResolution != null) {
            checkROIBounds(rect, screenResolution);
            float ratioX, ratioY;
            if (cm.isPortrait()) {
                ratioX = (float) cameraResolution.y / screenResolution.x;
                ratioY = (float) cameraResolution.x / screenResolution.y;
            } else {
                ratioX = (float) cameraResolution.x / screenResolution.x;
                ratioY = (float) cameraResolution.y / screenResolution.y;
            }
            rect.left = (int) (rect.left * ratioX);
            rect.right = (int) (rect.right * ratioX);
            rect.top = (int) (rect.top * ratioY);
            rect.bottom = (int) (rect.bottom * ratioY);
        }
    }


    /**
     * 检查边界
     *
     * @param rect
     * @param resolution
     */
    private void checkROIBounds(Rect rect, Point resolution) {
        if (rect.left < 0) rect.left = 0;
        else if (rect.left > resolution.x) rect.left = resolution.x;
        if (rect.right < rect.left) rect.right = rect.left;
        else if (rect.right > resolution.x) rect.right = resolution.x;
        if (rect.top < 0) rect.top = 0;
        else if (rect.top > resolution.y) rect.top = resolution.y;
        if (rect.bottom < rect.top) rect.bottom = rect.top;
        else if (rect.bottom > resolution.y) rect.bottom = resolution.y;
        //识别区域不能小于1
        if (rect.width() < 1) rect.set(0, rect.top, 1, rect.bottom);
        if (rect.height() < 1) rect.set(rect.left, 0, rect.right, 1);
    }


    /**
     * 打开摄像头
     */
    @Override
    public void openCamera(SurfaceHolder holder) {
        if (holder == null || isOpenCamera()) return;
        OpenCamera openCamera = mCamera;
        //打开摄像头
        if (openCamera == null) {
            openCamera = OpenCameraInterface.open(requestedCameraId);
            if (openCamera == null) {
                try {
                    throw new IOException("Camera.open() failed to return object from driver");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mCamera = openCamera;
        }
        if (openCamera == null) return;
        setCameraParametersAndROI(openCamera);
        Camera camera = openCamera.getCamera();
        camera.setOneShotPreviewCallback(previewCallback);
        try {
            camera.setPreviewDisplay(holder);
        } catch (IOException e) {
            e.printStackTrace();
        }
        startPreview();
    }

    @Override
    public void closeCamera() {
        stopPreview();
        try {
            if (isOpenCamera()) {
                Camera theCamera = mCamera.getCamera();
                theCamera.release();
                mCamera = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /**
     * 摄像头参数
     *
     * @param openCamera
     */
    private void setCameraParametersAndROI(OpenCamera openCamera) {

        if (!mInitialized) {
            mInitialized = true;
            cm.initCameraParameters(openCamera);
            setZoom(barCodePreview.getBarCodeScanConfig().getZoom());
            setRealROI();
        }
        cm.setDesiredCameraParameters(openCamera);
    }

    private boolean isOpenCamera() {
        return mCamera != null;
    }

    /**
     * 停止预览
     */
    @Override
    public void stopPreview() {
        if (isOpenCamera() && previewing) {
            try {
                Camera theCamera = mCamera.getCamera();
                if (focusManager != null) {
                    focusManager.stop();
                    focusManager = null;
                }
                theCamera.setOneShotPreviewCallback(null);
                theCamera.stopPreview();
                previewing = false;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 开始预览
     */

    @Override
    public void startPreview() {
        if (isOpenCamera() && !previewing) {
            try {
                Camera theCamera = mCamera.getCamera();
                theCamera.startPreview();
                previewing = true;
                if (focusManager == null) {
                    focusManager = new FocusManager(mContext, theCamera, barCodePreview.getBarCodeScanConfig());
                }
                focusManager.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    public void requestPreviewFrame() {
        if (isOpenCamera() && previewing) {
            try {
                mCamera.getCamera().setOneShotPreviewCallback(previewCallback);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 打开闪光灯
     */
    @Override
    public void turnOnFlashLight() {
        if (!isSupportFlight()) {
            Toast.makeText(mContext, "当前设备不支持闪光灯", Toast.LENGTH_SHORT).show();
            return;
        }
        if (isOpenCamera() && previewing) {
            CameraConfigUtils.setTorch(mCamera.getCamera(), true);
        }
    }

    /**
     * 关闭闪光灯
     */
    @Override
    public void turnOffFlashLight() {
        if (isSupportFlight() && isOpenCamera() && previewing) {
            CameraConfigUtils.setTorch(mCamera.getCamera(), false);
        }
    }

    private boolean isSupportFlight() {
        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
    }

    /**
     * 放大焦距
     */
    public void adjustFocalDistance() {
        if (isOpenCamera() && previewing) {
            CameraConfigUtils.adjustFocalDistance(mCamera.getCamera());
        }
    }

    /**
     * 设置焦距
     * @param zoomValue
     */
    public void setZoom(int zoomValue){
        CameraConfigUtils.setZoom(zoomValue,mCamera.getCamera());
    }

}