package com.idata.ocr.iocr;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Point;
import android.hardware.Camera;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;

import java.io.IOException;
import java.util.List;

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
    private SurfaceHolder mHolder = null;
    private Camera mCamera = null;
    private static final int ORIENTATION = 90;

    private float mValidWidthRatio = 1f;
    private float mValidHeightRatio = 1f;

    private boolean mIsActivated = false;

    private boolean mTakePic = false;
    private OnTakePicListener mOnTakePicListener = null;

    private OnStateListener mOnStateListener = null;

    public CameraSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        mIsActivated = true;
        openCamera(holder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i("ZWF", "TEST");

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        releaseCamera();

        mIsActivated = false;
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {

        if(mTakePic && mOnTakePicListener != null)
        {
            mTakePic = false;

            Camera.Size size = mCamera.getParameters().getPreviewSize();
            Bitmap bitmap = fetchValidBitmap(data, size.width, size.height);
            mOnTakePicListener.onTakePic(bitmap);
        }
    }

    public void releaseCamera() {
        if (mCamera != null) {
            try {
                mCamera.setPreviewCallback(null);
                mCamera.setPreviewDisplay(null);
                mCamera.stopPreview();
                mCamera.release();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                mCamera = null;
            }
        }
    }

    /**
     * 选取合适的分辨率
     */
    private Camera.Size getProperSize(List<Camera.Size> sizeList, float screenRatio) {
        if(screenRatio > 1)
            screenRatio = 1 / screenRatio;

        int idx = 0;
        Camera.Size size = null;
        float factor = 1f;
        for(int i=0; i<sizeList.size(); i++)
        {
            size = sizeList.get(i);
            float ratio = size.width > size.height ? size.height * 1f / size.width : size.width * 1f / size.height;
            float dis = Math.abs(ratio - screenRatio);
            if(dis < factor)
            {
                idx = i;
                factor = dis;
            }
        }

        return sizeList.get(idx);
    }

    private Point getScreenSize() {
        Point point = new Point();
        WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getRealSize(point);
        return point;
    }

    public void openCamera(SurfaceHolder surfaceHolder)
    {
        try{
            if(mCamera != null )
                return;

            if(mIsActivated == false)
                return;

            mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
            if(mCamera == null)
                return;
            setCameraParams();
            mCamera.setDisplayOrientation(ORIENTATION);
            mCamera.setPreviewDisplay(surfaceHolder);
            mCamera.setPreviewCallback(this);
            mCamera.startPreview();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void setCameraParams() {
        Point screenSize = getScreenSize();
        Camera.Parameters parameters = mCamera.getParameters();
        List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();

        Camera.Size preSize = getProperSize(previewSizeList, screenSize.x * 1f / screenSize.y);
        parameters.setPreviewSize(preSize.width, preSize.height);

        float ratio = preSize.width > preSize.height ? preSize.height * 1f / preSize.width : preSize.width * 1f / preSize.height;
        int viewWidth = getWidth();
        int viewHeight = getHeight();
        int width = viewWidth;
        int height = (int)(width / ratio);
        if(height > viewHeight)
        {
            height = viewHeight;
            width = (int)(height * ratio);
        }

        if(width != viewWidth || height != viewHeight)
        {
            ViewGroup.LayoutParams layoutParams = (ViewGroup.LayoutParams) getLayoutParams();
            layoutParams.width = width;
            layoutParams.height = height;
            setLayoutParams(layoutParams);

            if(mOnStateListener != null)
                mOnStateListener.onSizeChanged(new Size(width, height));
        }
        else if(mOnStateListener != null)
        {
            if(mOnStateListener != null)
                mOnStateListener.onSizeNotChanged(new Size(width, height));
        }

        if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式
        }

        mCamera.setParameters(parameters);
    }

    public void setValidZoneRatio(float widthRatio, float heightRatio)
    {
        mValidWidthRatio = widthRatio;
        mValidHeightRatio = heightRatio;
    }

    public void stopPreview()
    {
        if(mCamera != null)
            mCamera.stopPreview();
    }

    public void startPreview()
    {
        if(mCamera != null)
            mCamera.startPreview();
    }

    private Bitmap fetchValidBitmap(byte[] nv21, int width, int height)
    {
        RenderScript rs = RenderScript.create(getContext());
        ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
        Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
        Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

        Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
        Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);

        in.copyFrom(nv21);

        yuvToRgbIntrinsic.setInput(in);;
        yuvToRgbIntrinsic.forEach(out);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        out.copyTo(bitmap);

        bitmap = rotateBitmap(bitmap, 90);

        int h = bitmap.getHeight();
        int w = bitmap.getWidth();
        int viewWidth = (int)(w * mValidWidthRatio);
        int viewHeight = (int)(h * mValidHeightRatio);
        Bitmap validBitmap = Bitmap.createBitmap(bitmap, (w - viewWidth) / 2, (h - viewHeight) / 2, viewWidth, viewHeight);
        if(validBitmap != bitmap)
            bitmap.recycle();

        Point screenSize = getScreenSize();
        bitmap = scaledBitmap(validBitmap, screenSize.x, screenSize.y);

        return bitmap;
    }

    private Bitmap scaledBitmap(Bitmap srcBitmap, int destWidth, int destHeight)
    {
        int width = srcBitmap.getWidth();
        int height = srcBitmap.getHeight();

        float ratio = width * 1.0f / height;
        if(destHeight * ratio > destWidth)
            destHeight = (int)(destWidth / ratio);
        else
            destWidth = (int)(destHeight * ratio);

        float scaleWidth = destWidth * 1.0f / width;
        float scaleHeight = destHeight * 1.0f / height;
        srcBitmap.setDensity(160);
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);

        Bitmap destBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, width, height, matrix,false);

        if(destBitmap != srcBitmap)
            srcBitmap.recycle();
        return destBitmap;
    }

    private Bitmap rotateBitmap(Bitmap bm, int orientationDegree) {

        Matrix m = new Matrix();
        m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);

        int width = bm.getWidth();
        int height = bm.getHeight();

        try {
            Bitmap bm1 = Bitmap.createBitmap(bm, 0, 0, width, height, m, true);
            if(bm1 != bm)
                bm.recycle();
            return bm1;
        }catch (Exception e){
            e.printStackTrace();
        }
        return bm;
    }

    public void takePicture(OnTakePicListener listener)
    {
        mTakePic = true;
        mOnTakePicListener = listener;
    }

    static public interface OnTakePicListener{
        public void onTakePic(Bitmap bitmap);
    }

    public void setOnStateListener(OnStateListener listener)
    {
        mOnStateListener = listener;
    }

    static public interface OnStateListener{
        public void onSizeChanged(Size size);
        public void onSizeNotChanged(Size size);
    }
}
