package com.cv.tnn.activity;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.camera.core.CameraX;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageAnalysisConfig;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.PreviewConfig;
import androidx.camera.core.UseCase;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.LifecycleOwner;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.media.ExifInterface;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Size;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

import com.cv.tnn.R;
import com.cv.tnn.model.FrameInfo;
import com.cv.tnn.model.Detector;
import com.cv.tnn.model.DrawImage;
import com.cv.tnn.model.Skeleton;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;


import wseemann.media.FFmpegMediaMetadataRetriever;
import android.media.AudioManager;
import android.media.ToneGenerator;


public class MainActivity extends AppCompatActivity {
    public static boolean USE_GPU = false;
    public static int MODEL_ID = 0;
    public static int NUM_THREAD = 1;
    public static CameraX.LensFacing CAMERA_ID = CameraX.LensFacing.FRONT;
    private static final int REQUEST_CAMERA = 1;
    private static final String TAG = "MainActivity";
    private static final int REQUEST_PICK_IMAGE = 2;
    private static final int REQUEST_PICK_VIDEO = 3;
    private static String[] PERMISSIONS_CAMERA = {
            Manifest.permission.CAMERA,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
    };
    private static int max_image_size = 1500;
    private Toolbar toolbar;
    private ImageView resultImageView;
    private TextView tvIouTH;
    private TextView tvScoreTH;
    private SeekBar sbIouTH;
    private SeekBar sbScoreTH;
    private TextView tvIouScoreInfo;
    private TextView tvLogInfo;
    private Button btnPhoto;
    private Button btnVideo;
    private Button btnCamera;
    private Button btnTest;
    private MediaPlayer mediaPlayer;
    private ToggleButton btnSWCamera;
    private float score_threshold = 0.5f;
    private float iou_threshold = 0.5f;
    private TextureView viewFinder;
    private SeekBar sbVideo;
    private int consecutiveDetections = 0; // 类成员变量，跟踪连续的检测次数
    private AlertDialog currentAlertDialog; // 用于跟踪当前显示的弹窗
    private SeekBar sbVideoSpeed;
    protected float videoSpeed = 5.0f;
    protected long videoCurFrameLoc = 0;
    public static int VIDEO_SPEED_MAX = 20 + 1;
    public static int VIDEO_SPEED_MIN = 1;

    private AtomicBoolean detectCamera = new AtomicBoolean(false);
    private AtomicBoolean detectPhoto = new AtomicBoolean(false);
    private AtomicBoolean detectVideo = new AtomicBoolean(false);

    private long per_time = 0;
    private long total_time = 0;
    private int width;
    private int height;
    int fps_count = 0;
    protected Bitmap mutableBitmap;

    ExecutorService detectService = Executors.newSingleThreadExecutor();
    private static Thread thread;
    FFmpegMediaMetadataRetriever mmr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
        if (permission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(
                    this,
                    PERMISSIONS_CAMERA,
                    REQUEST_CAMERA
            );
            finish();
        }

        mediaPlayer = new MediaPlayer();
        try {
            // 设置要播放的.wav文件
            mediaPlayer = MediaPlayer.create(this, R.raw.alret);  // 这里的alarm_sound是.wav文件的文件名，不需要扩展名
            // 播放音频
            //mediaPlayer.start();
        } catch (Exception e) {
            System.out.println("no found==============================");
            e.printStackTrace();
        }

        initModel();
        initViewID();
        initViewListener();

    }

    protected void initViewListener() {
        toolbar.setNavigationIcon(R.mipmap.actionbar_dark_back_icon);
        toolbar.setNavigationOnClickListener(v -> finish());

        sbIouTH.setEnabled(true);
        sbIouTH.setVisibility(View.VISIBLE);
        tvIouTH.setVisibility(View.VISIBLE);

        sbScoreTH.setEnabled(true);
        sbScoreTH.setVisibility(View.VISIBLE);
        tvScoreTH.setVisibility(View.VISIBLE);

        tvIouScoreInfo.setVisibility(View.VISIBLE);

        sbIouTH.setProgress((int) (iou_threshold * 100));
        sbScoreTH.setProgress((int) (score_threshold * 100));
        sbVideoSpeed.setProgress((int) videoSpeed);
        sbVideo.setProgress((int) 0);
        final String format = "score_threshold: %.2f, iou_threshold: %.2f";
        tvIouScoreInfo.setText(String.format(Locale.ENGLISH, format, score_threshold, iou_threshold));
        sbIouTH.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                iou_threshold = i / 100.f;
                tvIouScoreInfo.setText(String.format(Locale.ENGLISH, format, score_threshold, iou_threshold));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
        sbScoreTH.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                score_threshold = i / 100.f;
                tvIouScoreInfo.setText(String.format(Locale.ENGLISH, format, score_threshold, iou_threshold));
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
        btnPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int permission = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE);
                if (permission != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(
                            MainActivity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                            777
                    );
                } else {
                    Intent intent = new Intent(Intent.ACTION_PICK);
                    intent.setType("image/*");
                    startActivityForResult(intent, REQUEST_PICK_IMAGE);
                }
            }
        });

        btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //startCamera();
                detectCamera.set(false);
                detectVideo.set(false);
                detectPhoto.set(true);
                sbVideo.setVisibility(View.GONE);
                sbVideoSpeed.setVisibility(View.GONE);
                viewFinder.setVisibility(View.GONE);
                Bitmap image = null;
                AssetManager am = getResources().getAssets();
                try {
                    InputStream is = am.open(WelcomeActivity.TEST_IMAGES[MODEL_ID]);
                    image = BitmapFactory.decodeStream(is);
                    is.close();
                    detBitmap(image, 100);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });


        btnVideo.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int permission = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE);
                if (permission != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(
                            MainActivity.this,
                            new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                            777
                    );
                } else {
                    Intent intent = new Intent(Intent.ACTION_PICK);
                    intent.setType("video/*");
                    startActivityForResult(intent, REQUEST_PICK_VIDEO);
                }
            }
        });

        btnCamera.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                detectPhoto.set(false);
                detectVideo.set(false);
                sbVideo.setVisibility(View.GONE);
                sbVideoSpeed.setVisibility(View.GONE);
                if (!detectCamera.get()) startCamera();
            }

        });


        btnSWCamera.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    CAMERA_ID = CameraX.LensFacing.FRONT;
                } else {
                    CAMERA_ID = CameraX.LensFacing.BACK;
                }
                detectPhoto.set(false);
                detectVideo.set(false);
                sbVideo.setVisibility(View.GONE);
                sbVideoSpeed.setVisibility(View.GONE);
                startCamera();

            }
        });


        viewFinder.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
                updateTransform();
            }
        });

        viewFinder.post(new Runnable() {
            @Override
            public void run() {
                //startCamera();
                Bitmap image = null;
                AssetManager am = getResources().getAssets();
                try {
                    InputStream is = am.open(WelcomeActivity.TEST_IMAGES[MODEL_ID]);
                    image = BitmapFactory.decodeStream(is);
                    is.close();
                    detBitmap(image, 1);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });


        sbVideoSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                videoSpeed = i;
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                Toast.makeText(MainActivity.this, "Video Speed:" + seekBar.getProgress(), Toast.LENGTH_SHORT).show();
            }
        });

        sbVideo.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                videoCurFrameLoc = i;
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                videoCurFrameLoc = seekBar.getProgress();
            }
        });
    }

    protected void initViewID() {
        toolbar = findViewById(R.id.tool_bar);
        resultImageView = findViewById(R.id.imageView);
        tvIouScoreInfo = findViewById(R.id.tv_iou_score_info);
        tvLogInfo = findViewById(R.id.tv_log_info);
        tvIouTH = findViewById(R.id.tv_iou_th);
        tvScoreTH = findViewById(R.id.tv_score_th);
        sbIouTH = findViewById(R.id.sb_iou_th);
        sbScoreTH = findViewById(R.id.sb_score_th);
        btnPhoto = findViewById(R.id.open_photo);
        btnTest = findViewById(R.id.test_image);
        btnVideo = findViewById(R.id.btn_video);
        btnCamera = findViewById(R.id.btn_camera);
        btnSWCamera = findViewById(R.id.btn_sw_camera);
        viewFinder = findViewById(R.id.view_finder);
        sbVideo = findViewById(R.id.sb_video);
        sbVideo.setVisibility(View.GONE);
        sbVideoSpeed = findViewById(R.id.sb_video_speed);
        //sbVideoSpeed.setMin(VIDEO_SPEED_MIN);
        sbVideoSpeed.setMax(VIDEO_SPEED_MAX);
        sbVideoSpeed.setVisibility(View.GONE);
    }

    protected void initModel() {
        String root = this.getFilesDir() + File.separator;
        //String tnnproto = WelcomeActivity.TNN_MODEL_FILES[MODEL_ID] + ".tnnproto";
        //String tnnmodel = WelcomeActivity.TNN_MODEL_FILES[MODEL_ID] + ".tnnmodel";
        int length = WelcomeActivity.TNN_MODEL_FILES.length;
        String det_model = WelcomeActivity.TNN_MODEL_FILES[MODEL_ID];// 检测模型
        String cls_model = WelcomeActivity.TNN_MODEL_FILES[length - 1];//默认最后一个是识别模型
        Detector.init(det_model, cls_model, root, MODEL_ID, NUM_THREAD, USE_GPU);
    }

    private void updateTransform() {
        Matrix matrix = new Matrix();
        // Compute the center of the view finder
        float centerX = viewFinder.getWidth() / 2f;
        float centerY = viewFinder.getHeight() / 2f;
        float[] rotations = {0, 90, 180, 270};
        // Correct preview output to account for display rotation
        float rotationDegrees = rotations[viewFinder.getDisplay().getRotation()];
        matrix.postRotate(-rotationDegrees, centerX, centerY);
        // Finally, apply transformations to our TextureView
        viewFinder.setTransform(matrix);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data == null) {
            return;
        }
        if (requestCode == REQUEST_PICK_IMAGE) {
            // photo
            runByPhoto(requestCode, resultCode, data);
        } else if (requestCode == REQUEST_PICK_VIDEO) {
            // video
            runByVideo(requestCode, resultCode, data);
        } else {
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        }
    }


    public void runByPhoto(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode != RESULT_OK || data == null) {
            Toast.makeText(this, "Photo error", Toast.LENGTH_SHORT).show();
            return;
        }
        if (detectVideo.get()) {
            try {
                detectVideo.set(false);
                thread.join();
            } catch (Exception e) {
                Toast.makeText(this, "Video is running", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        detectCamera.set(false);
        detectVideo.set(false);
        detectPhoto.set(true);
        sbVideo.setVisibility(View.GONE);
        sbVideoSpeed.setVisibility(View.GONE);
        viewFinder.setVisibility(View.GONE);
        final Bitmap image = getPicture(data.getData());
        detBitmap(image, 1);
    }

    public void runByVideo(int requestCode, int resultCode, @Nullable Intent data) {
        if (resultCode != RESULT_OK || data == null) {
            Toast.makeText(this, "Video error", Toast.LENGTH_SHORT).show();
            return;
        }
        if (detectVideo.get()) {
            try {
                detectVideo.set(false);
                thread.join();
            } catch (Exception e) {
                Toast.makeText(this, "Video is running", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        detectCamera.set(false);
        detectVideo.set(true);
        detectPhoto.set(false);
        viewFinder.setVisibility(View.GONE);
        try {
            Uri uri = data.getData();
            String[] thumbColumns = {MediaStore.Video.Thumbnails.DATA,
                    MediaStore.Video.Thumbnails.VIDEO_ID};
            String[] mediaColumns = {MediaStore.Video.Media._ID,
                    MediaStore.Video.Media.DATA, MediaStore.Video.Media.TITLE,
                    MediaStore.Video.Media.MIME_TYPE};
            //fix bug: huawei
            Cursor cursor = getContentResolver().query(uri, mediaColumns, null, null, null);
            //Cursor cursor = getContentResolver().query(uri, null, null, null, null);
            Log.w(TAG, "video uri:" + uri);
            if (cursor != null) {
                cursor.moveToFirst();
                // String imgNo = cursor.getString(0); // 编号
                String v_path = cursor.getString(1); // 文件路径
                String v_size = cursor.getString(2); // 大小
                String v_name = cursor.getString(3); // 文件名
                Log.w(TAG, "video path:" + v_path + ",size:" + v_size + ",name:" + v_name);
                detectOnVideo(v_path);
            } else {
                Toast.makeText(this, "Video is null", Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "Video is null", Toast.LENGTH_SHORT).show();
        }
    }

    public void detectOnVideo(final String path) {
        detectVideo.set(true);
        Toast.makeText(MainActivity.this, "FPS is not accurate!", Toast.LENGTH_SHORT).show();
        sbVideo.setVisibility(View.VISIBLE);
        sbVideoSpeed.setVisibility(View.VISIBLE);
        CameraX.unbindAll();
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                mmr = new FFmpegMediaMetadataRetriever();
                mmr.setDataSource(path);
                String dur = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);  // ms
                String sfps = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_FRAMERATE);  // fps
                //String sWidth = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);  // w
                //String sHeight = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);  // h
                String rota = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);  // rotation
                int duration = Integer.parseInt(dur);
                float fps = Float.parseFloat(sfps);
                float rotate = 0;
                if (rota != null) {
                    rotate = Float.parseFloat(rota);
                }
                sbVideo.setMax(duration * 1000);
                float frameDis = 1.0f / fps * 1000 * 1000 * videoSpeed;
                videoCurFrameLoc = 0;
                set_time();
                while (detectVideo.get() && (videoCurFrameLoc) < (duration * 1000)) {
                    videoCurFrameLoc = (long) (videoCurFrameLoc + frameDis);
                    sbVideo.setProgress((int) videoCurFrameLoc);
                    final Bitmap b = mmr.getFrameAtTime(videoCurFrameLoc, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
                    if (b == null) {
                        continue;
                    }
                    Matrix matrix = new Matrix();
                    matrix.postRotate(rotate);
                    width = b.getWidth();
                    height = b.getHeight();
                    final Bitmap bitmap = Bitmap.createBitmap(b, 0, 0, width, height, matrix, false);
                    detectAndDraw(bitmap);
                    showResultOnUI();
                    frameDis = 1.0f / fps * 1000 * 1000 * videoSpeed;
                }
                mmr.release();
                if (detectVideo.get()) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //sbVideo.setVisibility(View.GONE);
                            //sbVideoSpeed.setVisibility(View.GONE);
                            Toast.makeText(MainActivity.this, "Video end!", Toast.LENGTH_LONG).show();
                        }
                    });
                }
                detectVideo.set(false);
            }
        }, "video detect");
        thread.start();
    }


    private void startCamera() {
        CameraX.unbindAll();
        // 1. preview
        PreviewConfig previewConfig = new PreviewConfig.Builder()
                .setLensFacing(CAMERA_ID)
                //.setTargetAspectRatio(Rational.NEGATIVE_INFINITY)  // 宽高比
                .setTargetResolution(new Size(480, 640))  // 分辨率
                .build();

        Preview preview = new Preview(previewConfig);
        preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
            @Override
            public void onUpdated(Preview.PreviewOutput output) {
                ViewGroup parent = (ViewGroup) viewFinder.getParent();
                parent.removeView(viewFinder);
                parent.addView(viewFinder, 0);

                viewFinder.setSurfaceTexture(output.getSurfaceTexture());
                updateTransform();
            }
        });
        DetectAnalyzer detectAnalyzer = new DetectAnalyzer();
        CameraX.bindToLifecycle((LifecycleOwner) this, preview, gainAnalyzer(detectAnalyzer));
    }

    private UseCase gainAnalyzer(DetectAnalyzer detectAnalyzer) {
        ImageAnalysisConfig.Builder analysisConfigBuilder = new ImageAnalysisConfig.Builder()
                .setLensFacing(CAMERA_ID);
        analysisConfigBuilder.setImageReaderMode(ImageAnalysis.ImageReaderMode.ACQUIRE_LATEST_IMAGE);
        analysisConfigBuilder.setTargetResolution(new Size(480, 640));  // 输出预览图像尺寸
        ImageAnalysisConfig config = analysisConfigBuilder.build();
        ImageAnalysis analysis = new ImageAnalysis(config);
        analysis.setAnalyzer(detectAnalyzer);
        return analysis;
    }


    private class DetectAnalyzer implements ImageAnalysis.Analyzer {

        @Override
        public void analyze(ImageProxy image, final int rotationDegrees) {
            Log.w(TAG, "analyze：" + String.valueOf(rotationDegrees));
            runByCamera(image, rotationDegrees);
        }
    }

    private void runByCamera(ImageProxy image, final int rotationDegrees) {
        if (detectCamera.get() || detectPhoto.get() || detectVideo.get()) {
            return;
        }
        set_time();
        detectCamera.set(true);
        viewFinder.setVisibility(View.GONE);
        final Bitmap bitmapsrc = imageToBitmap(image);  // 格式转换
        if (detectService == null) {
            detectCamera.set(false);
            return;
        }
        detectService.execute(new Runnable() {
            @Override
            public void run() {
                Matrix matrix = new Matrix();
                matrix.postRotate(rotationDegrees);
                width = bitmapsrc.getWidth();
                height = bitmapsrc.getHeight();
                Bitmap bitmap = Bitmap.createBitmap(bitmapsrc, 0, 0, width, height, matrix, false);
                detectAndDraw(bitmap);
                showResultOnUI();
            }
        });
    }


    @Override
    protected void onDestroy() {
        detectCamera.set(false);
        detectVideo.set(false);
        if (detectService != null) {
            detectService.shutdown();
            detectService = null;
        }
        if (mmr != null) {
            mmr.release();
        }
        if (mediaPlayer != null) {
            mediaPlayer.release(); // 释放MediaPlayer资源
            mediaPlayer = null;
        }
        CameraX.unbindAll();
        super.onDestroy();
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Camera Permission!", Toast.LENGTH_SHORT).show();
                this.finish();
            }
        }
    }

    public Bitmap getPicture(Uri selectedImage) {
        String[] filePathColumn = {MediaStore.Images.Media.DATA};
        Cursor cursor = this.getContentResolver().query(selectedImage, filePathColumn, null, null, null);
        if (cursor == null) {
            return null;
        }
        cursor.moveToFirst();
        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();
        Bitmap bitmap = BitmapFactory.decodeFile(picturePath);
        bitmap = resizeBitmap(bitmap);
        if (bitmap == null) {
            return null;
        }
        int rotate = readPictureDegree(picturePath);
        return rotateBitmapByDegree(bitmap, rotate);
    }

    public Bitmap resizeBitmap(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        if (width > max_image_size) {
            bitmap = DrawImage.resizeBitmap(bitmap, max_image_size, -1);
        } else if (height > max_image_size) {
            bitmap = DrawImage.resizeBitmap(bitmap, -1, max_image_size);
        }
        return bitmap;
    }


    public int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    public Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
        Bitmap returnBm = null;
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        try {
            returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
                    bm.getHeight(), matrix, true);
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }
        if (returnBm == null) {
            returnBm = bm;
        }
        if (bm != returnBm) {
            bm.recycle();
        }
        return returnBm;
    }

    public void set_time() {
        fps_count = 0;
        total_time = 0;
    }


    public void detBitmap(Bitmap bitmap, int iter_num) {
        if (bitmap == null) {
            Toast.makeText(this, "Photo is null", Toast.LENGTH_SHORT).show();
            return;
        }
        CameraX.unbindAll();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                set_time();
                mutableBitmap = detectAndDraw(bitmap);
                showResultOnUI();
                set_time();
                for (int i = 0; i < iter_num; i++) {
                    mutableBitmap = detectAndDraw(bitmap);
                    showResultOnUI();
                }
            }
        }, "photo detect");
        thread.start();
    }

    protected void showResultOnUI() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                detectCamera.set(false);
                resultImageView.setImageBitmap(mutableBitmap);
                width = mutableBitmap.getWidth();
                height = mutableBitmap.getHeight();
                fps_count++;
                total_time += per_time;
                String modelName = getDeviceInfo();
                tvLogInfo.setText(String.format(Locale.CHINESE,
                        "%s\n" +
                                "size    : %dx%d \n" +
                                "det-time: %.3fms\n" +
                                "avg-time: %.3fms\n"+
                                "alert-time: %.3fms\n",
                        modelName, height, width, per_time * 1.0f, total_time * 1.0f / fps_count,3.0));
            }
        });
    }


    protected byte[] bitampToByteArray(Bitmap bitmap) {
        int bytes = bitmap.getByteCount();
        ByteBuffer buf = ByteBuffer.allocate(bytes);
        bitmap.copyPixelsToBuffer(buf);
        return buf.array();
    }

    protected Bitmap detectAndDraw(Bitmap bitmap) {
        bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        FrameInfo[] result = null;
        long startDet = System.currentTimeMillis();
        result = Detector.detect(bitmap, score_threshold, iou_threshold);
        long endDet = System.currentTimeMillis();
        per_time = endDet - startDet;

        if (result == null) {
            detectCamera.set(false);
            mutableBitmap = bitmap;
            consecutiveDetections = 0; // 重置计数器
            return bitmap;
        }

        System.out.println("Detection Results:");
        boolean foundLabelOne = false;
        for (FrameInfo info : result) {
            System.out.println(info.toString());
            if (info.getLabel() == 1) {
                foundLabelOne = true;
                consecutiveDetections++; // 增加计数器
                break; // 假设每帧只关心是否至少有一个检测为label 1
            }
        }

        if (!foundLabelOne) {
            consecutiveDetections = 0; // 如果没有发现label为1，则重置计数器
        }

        if (consecutiveDetections >= 35) {
            runOnUiThread(() -> {
                // 播放提示音
                if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
                    mediaPlayer.start(); // 开始播放
                }

                // 获取Vibrator实例并震动
                Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                if (vibrator != null && vibrator.hasVibrator()) {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)); // 500ms的震动
                    }
                }

                // 如果已有弹窗显示，则关闭它
                if (currentAlertDialog != null && currentAlertDialog.isShowing()) {
                    currentAlertDialog.dismiss();
                }

                // 创建并显示新的AlertDialog
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this)
                        .setTitle("Detection Alert")
                        .setMessage("You are so sleepy, wake up!")
                        .setPositiveButton("Close", (dialog, which) -> {
                            dialog.dismiss(); // 关闭对话框
                        })
                        .setCancelable(false); // 设置对话框不可通过点击外部区域关闭

                currentAlertDialog = builder.create(); // 将新的弹窗实例保存到变量中
                currentAlertDialog.show(); // 显示弹窗

                // 重置计数器，避免重复显示
                consecutiveDetections = 0;
            });
        }

        mutableBitmap = DrawImage.drawResult(bitmap, result, Skeleton.get_skeleton(MODEL_ID));
        return mutableBitmap;
    }


    protected Bitmap detectAndDraw2(Bitmap bitmap) {
        bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
        FrameInfo[] result = null;
        long startDet = System.currentTimeMillis();
        //maskBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        result = Detector.detect(bitmap, score_threshold, iou_threshold);
        long endDet = System.currentTimeMillis();
        per_time = endDet - startDet;
        if (result == null) {
            detectCamera.set(false);
            mutableBitmap = bitmap;
            return bitmap;
        }
        boolean foundLabelOne = false;
        if (result != null) {
            System.out.println("Detection Results:");
            for (FrameInfo info : result) {
                if(info.getLabel()==1){
                    foundLabelOne = true;
                    consecutiveDetections++; // 增加计数器
                    break; // 假设每帧只关心是否至少有一个检测为label 1
                }
                System.out.println(info.toString());
            }
        } else {
            System.out.println("No detections found.");
        }


        mutableBitmap = DrawImage.drawResult(bitmap, result, Skeleton.get_skeleton(MODEL_ID));
        //mutableBitmap = bitmap;
        return mutableBitmap;
    }

    protected String getDeviceInfo() {
        String devidce = "Device: ";
        return USE_GPU ? devidce + "GPU" : devidce + "CPU,Thread: " + String.valueOf(NUM_THREAD);
    }

    private Bitmap imageToBitmap(ImageProxy image) {
        byte[] nv21 = imagetToNV21(image);
        YuvImage yuvImage = new YuvImage(nv21, ImageFormat.NV21, image.getWidth(), image.getHeight(), null);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()), 100, out);
        byte[] imageBytes = out.toByteArray();
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    }

    private byte[] imagetToNV21(ImageProxy image) {
        ImageProxy.PlaneProxy[] planes = image.getPlanes();
        ImageProxy.PlaneProxy y = planes[0];
        ImageProxy.PlaneProxy u = planes[1];
        ImageProxy.PlaneProxy v = planes[2];
        ByteBuffer yBuffer = y.getBuffer();
        ByteBuffer uBuffer = u.getBuffer();
        ByteBuffer vBuffer = v.getBuffer();
        int ySize = yBuffer.remaining();
        int uSize = uBuffer.remaining();
        int vSize = vBuffer.remaining();
        byte[] nv21 = new byte[ySize + uSize + vSize];
        // U and V are swapped
        yBuffer.get(nv21, 0, ySize);
        vBuffer.get(nv21, ySize, vSize);
        uBuffer.get(nv21, ySize + vSize, uSize);

        return nv21;
    }


}