package com.vise.face;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Process;
import android.view.Surface;
import android.widget.FrameLayout;

import com.vise.log.ViseLog;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * @Description: 工具类
 * @author: <a href="http://xiaoyaoyou1212.360doc.com">DAWI</a>
 * @date: 2017/8/9 14:54
 */
public class FaceUtil {

    public static int getYUVLight(byte[] data, Rect rect, int width) {
        if (data == null || rect == null) {
            return 0;
        }
        int sum = 0;
        int index = 0;
        if (rect.top < 0 || rect.left < 0 || rect.left > width || rect.right > width) {
            return 0;
        }
        try {
            for (int i = rect.left; i < rect.right; ) {
                for (int j = rect.top; j < rect.bottom; ) {
                    sum += (0xFF & data[i * width + j]);
                    j += 100;
                    index++;
                }
                i += 100;
            }
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        }
        if (sum == 0 || index == 0) {
            return 0;
        }
        return sum / index;
    }

    public static void drawFaceRect(Canvas canvas, Rect rect, int rectColor, boolean drawRect) {
        if (canvas == null) {
            return;
        }

        Paint paint = new Paint();
        paint.setColor(rectColor);
        float len = (rect.bottom - rect.top) / 8;
        if (len / 8 >= 2) paint.setStrokeWidth(len / 8);
        else paint.setStrokeWidth(2);

        if (drawRect) {
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawRect(rect, paint);
        } else {
            float drawl = rect.left - len;
            float drawr = rect.right + len;
            float drawu = rect.top - len;
            float drawd = rect.bottom + len;

            canvas.drawLine(drawl, drawd, drawl, drawd - len, paint);
            canvas.drawLine(drawl, drawd, drawl + len, drawd, paint);
            canvas.drawLine(drawr, drawd, drawr, drawd - len, paint);
            canvas.drawLine(drawr, drawd, drawr - len, drawd, paint);
            canvas.drawLine(drawl, drawu, drawl, drawu + len, paint);
            canvas.drawLine(drawl, drawu, drawl + len, drawu, paint);
            canvas.drawLine(drawr, drawu, drawr, drawu + len, paint);
            canvas.drawLine(drawr, drawu, drawr - len, drawu, paint);
        }
    }

    /**
     * 找出最大像素组合
     *
     * @param cameraSizes
     * @return
     */
    public static Camera.Size findMaxCameraSize(List<Camera.Size> cameraSizes) {
        // 按照分辨率从大到小排序
        List<Camera.Size> supportedResolutions = new ArrayList(cameraSizes);
        Collections.sort(supportedResolutions, new Comparator<Camera.Size>() {
            @Override
            public int compare(Camera.Size a, Camera.Size b) {
                int aPixels = a.height * a.width;
                int bPixels = b.height * b.width;
                if (bPixels < aPixels) {
                    return -1;
                }
                if (bPixels > aPixels) {
                    return 1;
                }
                return 0;
            }
        });
        return supportedResolutions.get(0);
    }

    /**
     * 找出最适合的分辨率
     *
     * @return
     */
    public static Point findBestResolution(List<Camera.Size> cameraSizes, Point screenResolution, boolean isPictureSize, float maxDistortion) {
        Point defaultResolution = new Point();
        if (isPictureSize) {
            defaultResolution.x = 2000;
            defaultResolution.y = 1500;
        } else {
            defaultResolution.x = 1920;
            defaultResolution.y = 1080;
        }
        if (cameraSizes == null) {
            ViseLog.w("Device returned no supported preview sizes; using default");
            return defaultResolution;
        }

        // 按照分辨率从大到小排序
        List<Camera.Size> supportedResolutions = new ArrayList(cameraSizes);
        Collections.sort(supportedResolutions, new Comparator<Camera.Size>() {
            @Override
            public int compare(Camera.Size a, Camera.Size b) {
                int aPixels = a.height * a.width;
                int bPixels = b.height * b.width;
                if (bPixels < aPixels) {
                    return -1;
                }
                if (bPixels > aPixels) {
                    return 1;
                }
                return 0;
            }
        });

        if (supportedResolutions.size() > 0) {
            defaultResolution.x = supportedResolutions.get(0).width;
            defaultResolution.y = supportedResolutions.get(0).height;
        }

        // 移除不符合条件的分辨率
        double screenAspectRatio = (double) screenResolution.x / (double) screenResolution.y;
        Iterator<Camera.Size> it = supportedResolutions.iterator();
        while (it.hasNext()) {
            Camera.Size supportedResolution = it.next();
            int width = supportedResolution.width;
            int height = supportedResolution.height;
            // 移除低于下限的分辨率,尽可能取高分辨率
            if (isPictureSize) {
                if (width * height < 2000 * 1500) {
                    it.remove();
                    continue;
                }
            } else {
                if (width * height < 1280 * 720) {
                    it.remove();
                    continue;
                }
            }

            /**
             * 在camera分辨率与屏幕分辨率宽高比不相等的情况下,找出差距最小的一组分辨率
             * 由于camera的分辨率是width>height,我们设置的portrait模式中,width<height
             * 因此这里要先交换然preview宽高比后在比较
             */
            boolean isCandidatePortrait = width > height;
            int maybeFlippedWidth = isCandidatePortrait ? height : width;
            int maybeFlippedHeight = isCandidatePortrait ? width : height;
            double aspectRatio = (double) maybeFlippedWidth / (double) maybeFlippedHeight;
            double distortion = Math.abs(aspectRatio - screenAspectRatio);
            if (distortion > maxDistortion) {
                it.remove();
                continue;
            }

            // 找到与屏幕分辨率完全匹配的预览界面分辨率直接返回
            if (maybeFlippedWidth == screenResolution.x && maybeFlippedHeight == screenResolution.y) {
                Point exactPoint = new Point(width, height);
                ViseLog.d("found preview resolution exactly matching screen resolutions: " + exactPoint);
                return exactPoint;
            }
        }

        // 如果没有找到合适的,并且还有候选的像素,则设置其中最大尺寸的,对于配置比较低的机器不太合适
        if (!supportedResolutions.isEmpty()) {
            Camera.Size largestPreview = supportedResolutions.get(0);
            Point largestSize = new Point(largestPreview.width, largestPreview.height);
            ViseLog.d("using largest suitable preview resolution: " + largestSize);
            return largestSize;
        }

        // 没有找到合适的,就返回默认的
        ViseLog.d("No suitable preview resolutions, using default: " + defaultResolution);
        return defaultResolution;
    }

    /**
     * 检查相机权限
     *
     * @param context
     * @return
     */
    public static boolean checkCameraPermission(Context context) {
        if (context != null) {
            int status = context.checkPermission(Manifest.permission.CAMERA, Process.myPid(), Process.myUid());
            if (PackageManager.PERMISSION_GRANTED == status) {
                return true;
            }
        }
        return false;
    }

    /**
     * 在摄像头启动前设置参数
     *
     * @param cameraPreview
     * @param faceDetector
     * @param camera
     * @param cameraId
     * @param width
     * @param height
     * @param <T>
     */
    public static <T> int setCameraParams(CameraPreview cameraPreview, IFaceDetector<T> faceDetector, Camera camera,
                                          int cameraId, int width, int height) {
        if (camera == null) {
            return 0;
        }
        // 获取摄像头支持的pictureSize列表
        Camera.Parameters parameters = camera.getParameters();
        List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
        // 从列表中选择合适的分辨率
        Point pictureSize = FaceUtil.findBestResolution(pictureSizeList, new Point(width, height), true, 0.15f);
        // 根据选出的PictureSize重新设置SurfaceView大小
        parameters.setPictureSize(pictureSize.x, pictureSize.y);

        // 获取摄像头支持的PreviewSize列表
        List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
        Point preSize = FaceUtil.findBestResolution(previewSizeList, new Point(width, height), false, 0.15f);
        parameters.setPreviewSize(preSize.x, preSize.y);

        float w = preSize.x;
        float h = preSize.y;
        float scale = 1.0f;
        int tempW = (int) (height * (h / w));
        int tempH = (int) (width * (w / h));
        if (cameraPreview != null) {
            if (tempW >= width) {
                cameraPreview.setLayoutParams(new FrameLayout.LayoutParams(tempW, height));
                scale = tempW / h;
            } else if (tempH >= height) {
                cameraPreview.setLayoutParams(new FrameLayout.LayoutParams(width, tempH));
                scale = tempH / w;
            } else {
                cameraPreview.setLayoutParams(new FrameLayout.LayoutParams(width, height));
            }
        }
        if (faceDetector != null) {
            faceDetector.setZoomRatio(5f * scale);
            faceDetector.setPreviewWidth((int) w);
            faceDetector.setPreviewHeight((int) h);
        }

        parameters.setJpegQuality(100);
        if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            // 连续对焦
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }
        camera.cancelAutoFocus();
        int displayOrientation = setCameraDisplayOrientation(cameraPreview.getContext(), faceDetector, camera, cameraId);
        camera.setParameters(parameters);
        return displayOrientation;
    }

    /**
     * 设置相机显示方向
     *
     * @param context
     * @param faceDetector
     * @param camera
     * @param cameraId
     * @param <T>
     * @return
     */
    public static <T> int setCameraDisplayOrientation(Context context, IFaceDetector<T> faceDetector, Camera camera, int cameraId) {
        if (context == null) {
            return 0;
        }
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = ((Activity) context).getWindowManager().getDefaultDisplay().getRotation();
        int degree = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degree = 0;
                break;
            case Surface.ROTATION_90:
                degree = 90;
                break;
            case Surface.ROTATION_180:
                degree = 180;
                break;
            case Surface.ROTATION_270:
                degree = 270;
                break;
        }
        if (faceDetector != null) {
            faceDetector.setOrientionOfCamera(info.orientation);
        }

        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            result = (info.orientation + degree) % 360;
            result = (360 - result) % 360;
        } else {
            result = (info.orientation - degree + 360) % 360;
        }
        if (camera != null) {
            camera.setDisplayOrientation(result);
        }
        return result;
    }

}