package kr.co.icontrols.ilp300_700.screen;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.view.TextureView;
import android.widget.RelativeLayout;

import com.google.gson.Gson;
import com.orhanobut.logger.Logger;
import com.sensetime.demo.SenseTimeMtc;
import com.sensetime.demo.view.UVCCameraSurfaceView;
import com.sensetime.demo.view.UVCCameraTextureView;
import com.sensetime.mtc.MClient;
import com.sensetime.mtc.MtcCode;
import com.serenegiant.usb.DeviceFilter;
import com.serenegiant.usb.IFrameCallback;
import com.serenegiant.usb.USBMonitor;
import com.serenegiant.usb.UVCCamera;

import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import kr.co.icontrols.ilp300_700.MainActivity;
import kr.co.icontrols.wallpadsupport.WpadScreen;

/*

public class FaceDetect extends WpadScreen {

    private final Object mSyncUVCCamera = new Object();
    private final Object mSyncUSBMonitor = new Object();

    private USBMonitor mUSBMonitor;
    private UVCCamera mUVCCamera;

    private UVCCameraTextureView mUVCCameraView;
    private UVCCameraSurfaceView mTrackView;
    private Matrix mScaleMatrix = new Matrix();
    private boolean isConnect = false;

    private Handler myHandler = new Handler();

    private MClient mClient = MClient.getInstance();
    private static Gson mGson = new Gson();

    Context mContext;

    public FaceDetect(Context context, RelativeLayout layout) {
        super(context, layout);
        try {
            mContext = context;
            initView();

        }
        catch (Exception ex)
        {
            ex.fillInStackTrace();
        }

    }

    protected void initView() {
        mUVCCameraView = new UVCCameraTextureView(mContext);

        mUVCCameraView.setRotation(90);
        mUVCCameraView.setSurfaceTextureListener(mSurfaceTextureListener);
        mUVCCameraView.setAspectRatio(9, 16);
        mUVCCameraView.setScaleX(-1); //NOTE mirror image
        //        mUVCCameraView.setScaleY(-1); // only for debug
    }

    private void initCamera(final USBMonitor.UsbControlBlock ctrlBlock) {

        if (!mUVCCameraView.isAvailable()) {
            return;
        }
        final UVCCamera camera = new UVCCamera();
        try {
            camera.open(ctrlBlock);
        } catch (UnsupportedOperationException e) {
            Logger.e(e.toString());
            return;
        }
        Logger.i("supportedSize:" + camera.getSupportedSize());
        SenseTimeMtc senseTimeMtc = SenseTimeMtc.getInstance();

        int PREVIEW_W, PREVIEW_H;
        if (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0 || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180) {
            PREVIEW_W = senseTimeMtc.getPreviewWidth();
            PREVIEW_H = senseTimeMtc.getPreviewHeight();
        } else {//竖屏状态
            PREVIEW_W = senseTimeMtc.getPreviewHeight();
            PREVIEW_H = senseTimeMtc.getPreviewWidth();
        }
        try {
            camera.setPreviewSize(PREVIEW_W, PREVIEW_H, UVCCamera.FRAME_FORMAT_MJPEG); //可以指定帧格式
            Logger.d("PREVIEW_W:" + PREVIEW_W + ",  PREVIEW_H:" + PREVIEW_H);
        } catch (final IllegalArgumentException e) {
            // fallback to YUV mode
            try {
                camera.setPreviewSize(PREVIEW_W, PREVIEW_H, UVCCamera.DEFAULT_PREVIEW_MODE);
            } catch (final IllegalArgumentException e1) {
                camera.destroy();
                return;
            }
        }
        final SurfaceTexture st = mUVCCameraView.getSurfaceTexture();
        if (st != null) {
            camera.setPreviewTexture(st);
            //camera.setFrameCallback(myIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21, false);
            camera.startPreview();
        }
        synchronized (mSyncUVCCamera) {
            mUVCCamera = camera;
        }
        if (senseTimeMtc.getPreviewHeight() == 360) {
            myHandler.postDelayed(() -> {
                mClient.mtcDeviceScreenSizeSet(0x01, (mtcCode, result) -> {
                    Logger.d(" 360p mtcCode:" + mtcCode);
                    if (mtcCode != MtcCode.SUCCESS) {
                        //showToast(MainActivity.this.getMtcErrorMsg(mtcCode));
                        isConnect = false;
                    } else {
                        isConnect = true;
                    }
                });//360p
            }, 200);
        } else {
            myHandler.postDelayed(() -> {
                mClient.mtcDeviceScreenSizeSet(0x00, (mtcCode, result) -> {
                    Logger.d("720p mtcCode:" + mtcCode);
                    if (mtcCode != MtcCode.SUCCESS) {
                        //showToast(MainActivity.this.getMtcErrorMsg(mtcCode));
                        isConnect = false;
                    } else {
                        isConnect = true;
                    }
                });//720p
            }, 200);
        }
    }

    private static final int DEVICE_PRODUCT_VIP = 4817;
    private static final int DEVICE_PRODUCT_PID = 17185;

    private void requestPermissionDevice() {
        final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(mContext, com.serenegiant.uvccamera.R.xml.device_filter);
        if (filter.size() > 0 && mUSBMonitor != null) {
            List<UsbDevice> usbDeviceList = mUSBMonitor.getDeviceList(filter.get(0));
            for (UsbDevice device : usbDeviceList) {
                if (DEVICE_PRODUCT_VIP == device.getVendorId() && DEVICE_PRODUCT_PID == device.getProductId()) {
                    Logger.d("requestPermission");
                    releaseAndRequestCamera(device);
                }
            }
        }
    }

    @SuppressLint("CheckResult")
    private void releaseAndRequestCamera(UsbDevice device) {
        Logger.d("releaseAndRequestCamera");
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
            synchronized (mSyncUVCCamera) {
                Logger.d("mUVCCamera:" + mUVCCamera);
                if (mUVCCamera != null) {
                    try {
                        mUVCCamera.close();
                        mUVCCamera.destroy();
                    } catch (final Exception e) {
                        e.printStackTrace();
                    }
                    mUVCCamera = null;
                }
                isConnect = false;
            }
            emitter.onNext("complete");
//        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        }).subscribeOn(Schedulers.single()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> {
                    Logger.d("requestPermission device:" + device + ",  mUSBMonitor:" + mUSBMonitor);
                    if (device != null && mUSBMonitor != null) {
                        mUSBMonitor.requestPermission(device);
                    }
                });
    }



    private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {

        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            float scaleX;
            float scaleY;
            float modulus;
            SenseTimeMtc senseTimeMtc = SenseTimeMtc.getInstance();
            int PREVIEW_W, PREVIEW_H;
            if (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0 || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180) {
                PREVIEW_W = senseTimeMtc.getPreviewWidth();
                PREVIEW_H = senseTimeMtc.getPreviewHeight();
            } else {//竖屏状态
                PREVIEW_W = senseTimeMtc.getPreviewHeight();
                PREVIEW_H = senseTimeMtc.getPreviewWidth();
            }
            if (SenseTimeMtc.M10 == senseTimeMtc.getmDeviceModule() && (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0
                    || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180)) {
                modulus = 720.0f / (float) PREVIEW_H;
            } else {
                modulus = 1280.0f / (float) PREVIEW_H;
            }

            if (width > height) {
                scaleX = width / (float) PREVIEW_W / modulus;
                scaleY = height / (float) PREVIEW_H / modulus;
            } else {
                scaleX = height / (float) PREVIEW_H / modulus;
                scaleY = width / (float) PREVIEW_W / modulus;
            }

            Logger.d("onSurfaceTextureAvailable  width:" + width + ",  height:" + height + ",  scaleX:" + scaleX + ",  scaleY:" + scaleY);
            mScaleMatrix.setScale(scaleX, scaleY);
            requestPermissionDevice();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            Logger.d("onSurfaceTextureSizeChanged  width:" + width + ",  height:" + height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            Logger.d("onSurfaceTextureDestroyed   surface:" + surface);
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
//			Logger.d("onSurfaceTextureUpdated  surface:"+surface);
        }
    };
}


*/

public class FaceDetect extends WpadScreen {

    private final Object mSyncUVCCamera = new Object();
    private final Object mSyncUSBMonitor = new Object();

    private USBMonitor mUSBMonitor;
    private UVCCamera mUVCCamera;

    private UVCCameraTextureView mUVCCameraView;
    private UVCCameraSurfaceView mTrackView;
    private Matrix mScaleMatrix = new Matrix();
    private boolean isConnect = false;

    private Handler myHandler = new Handler();

    private MClient mClient = MClient.getInstance();
    private static Gson mGson = new Gson();

    Context mContext;

    public FaceDetect(Context context, RelativeLayout layout) {
        super(context, layout);
        try {
            mContext = context;
            initView();

        }
        catch (Exception ex)
        {
            ex.fillInStackTrace();
        }

    }

    protected void initView() {
        mUVCCameraView = new UVCCameraTextureView(mContext);

        mUVCCameraView.setRotation(90);
        mUVCCameraView.setSurfaceTextureListener(mSurfaceTextureListener);
        mUVCCameraView.setAspectRatio(9, 16);
        mUVCCameraView.setScaleX(-1); //NOTE mirror image
        //        mUVCCameraView.setScaleY(-1); // only for debug
    }

    private void initCamera(final USBMonitor.UsbControlBlock ctrlBlock) {

        if (!mUVCCameraView.isAvailable()) {
            return;
        }
        final UVCCamera camera = new UVCCamera();
        try {
            camera.open(ctrlBlock);
        } catch (UnsupportedOperationException e) {
            Logger.e(e.toString());
            return;
        }
        Logger.i("supportedSize:" + camera.getSupportedSize());
        SenseTimeMtc senseTimeMtc = SenseTimeMtc.getInstance();

        int PREVIEW_W, PREVIEW_H;
        if (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0 || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180) {
            PREVIEW_W = senseTimeMtc.getPreviewWidth();
            PREVIEW_H = senseTimeMtc.getPreviewHeight();
        } else {//竖屏状态
            PREVIEW_W = senseTimeMtc.getPreviewHeight();
            PREVIEW_H = senseTimeMtc.getPreviewWidth();
        }
        try {
            camera.setPreviewSize(PREVIEW_W, PREVIEW_H, UVCCamera.FRAME_FORMAT_MJPEG); //可以指定帧格式
            Logger.d("PREVIEW_W:" + PREVIEW_W + ",  PREVIEW_H:" + PREVIEW_H);
        } catch (final IllegalArgumentException e) {
            // fallback to YUV mode
            try {
                camera.setPreviewSize(PREVIEW_W, PREVIEW_H, UVCCamera.DEFAULT_PREVIEW_MODE);
            } catch (final IllegalArgumentException e1) {
                camera.destroy();
                return;
            }
        }
        final SurfaceTexture st = mUVCCameraView.getSurfaceTexture();
        if (st != null) {
            camera.setPreviewTexture(st);
            //camera.setFrameCallback(myIFrameCallback, UVCCamera.PIXEL_FORMAT_NV21, false);
            camera.startPreview();
        }
        synchronized (mSyncUVCCamera) {
            mUVCCamera = camera;
        }
        if (senseTimeMtc.getPreviewHeight() == 360) {
            myHandler.postDelayed(() -> {
                mClient.mtcDeviceScreenSizeSet(0x01, (mtcCode, result) -> {
                    Logger.d(" 360p mtcCode:" + mtcCode);
                    if (mtcCode != MtcCode.SUCCESS) {
                        //showToast(MainActivity.this.getMtcErrorMsg(mtcCode));
                        isConnect = false;
                    } else {
                        isConnect = true;
                    }
                });//360p
            }, 200);
        } else {
            myHandler.postDelayed(() -> {
                mClient.mtcDeviceScreenSizeSet(0x00, (mtcCode, result) -> {
                    Logger.d("720p mtcCode:" + mtcCode);
                    if (mtcCode != MtcCode.SUCCESS) {
                        //showToast(MainActivity.this.getMtcErrorMsg(mtcCode));
                        isConnect = false;
                    } else {
                        isConnect = true;
                    }
                });//720p
            }, 200);
        }
    }

    private static final int DEVICE_PRODUCT_VIP = 4817;
    private static final int DEVICE_PRODUCT_PID = 17185;

    private void requestPermissionDevice() {
        final List<DeviceFilter> filter = DeviceFilter.getDeviceFilters(mContext, com.serenegiant.uvccamera.R.xml.device_filter);
        if (filter.size() > 0 && mUSBMonitor != null) {
            List<UsbDevice> usbDeviceList = mUSBMonitor.getDeviceList(filter.get(0));
            for (UsbDevice device : usbDeviceList) {
                if (DEVICE_PRODUCT_VIP == device.getVendorId() && DEVICE_PRODUCT_PID == device.getProductId()) {
                    Logger.d("requestPermission");
                    releaseAndRequestCamera(device);
                }
            }
        }
    }

    @SuppressLint("CheckResult")
    private void releaseAndRequestCamera(UsbDevice device) {
        Logger.d("releaseAndRequestCamera");
        Observable.create((ObservableOnSubscribe<String>) emitter -> {
                    synchronized (mSyncUVCCamera) {
                        Logger.d("mUVCCamera:" + mUVCCamera);
                        if (mUVCCamera != null) {
                            try {
                                mUVCCamera.close();
                                mUVCCamera.destroy();
                            } catch (final Exception e) {
                                e.printStackTrace();
                            }
                            mUVCCamera = null;
                        }
                        isConnect = false;
                    }
                    emitter.onNext("complete");
//        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                }).subscribeOn(Schedulers.single()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(s -> {
                    Logger.d("requestPermission device:" + device + ",  mUSBMonitor:" + mUSBMonitor);
                    if (device != null && mUSBMonitor != null) {
                        mUSBMonitor.requestPermission(device);
                    }
                });
    }



    private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {

        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            float scaleX;
            float scaleY;
            float modulus;
            SenseTimeMtc senseTimeMtc = SenseTimeMtc.getInstance();
            int PREVIEW_W, PREVIEW_H;
            if (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0 || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180) {
                PREVIEW_W = senseTimeMtc.getPreviewWidth();
                PREVIEW_H = senseTimeMtc.getPreviewHeight();
            } else {//竖屏状态
                PREVIEW_W = senseTimeMtc.getPreviewHeight();
                PREVIEW_H = senseTimeMtc.getPreviewWidth();
            }
            if (SenseTimeMtc.M10 == senseTimeMtc.getmDeviceModule() && (senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_0
                    || senseTimeMtc.getmM10_L_P() == SenseTimeMtc.LANDSCAPE_180)) {
                modulus = 720.0f / (float) PREVIEW_H;
            } else {
                modulus = 1280.0f / (float) PREVIEW_H;
            }

            if (width > height) {
                scaleX = width / (float) PREVIEW_W / modulus;
                scaleY = height / (float) PREVIEW_H / modulus;
            } else {
                scaleX = height / (float) PREVIEW_H / modulus;
                scaleY = width / (float) PREVIEW_W / modulus;
            }

            Logger.d("onSurfaceTextureAvailable  width:" + width + ",  height:" + height + ",  scaleX:" + scaleX + ",  scaleY:" + scaleY);
            mScaleMatrix.setScale(scaleX, scaleY);
            requestPermissionDevice();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            Logger.d("onSurfaceTextureSizeChanged  width:" + width + ",  height:" + height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            Logger.d("onSurfaceTextureDestroyed   surface:" + surface);
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
//			Logger.d("onSurfaceTextureUpdated  surface:"+surface);
        }
    };
}
