package com.vmloft.develop.library.tools.picker;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v4.app.Fragment;
import android.support.v4.content.FileProvider;

import com.vmloft.develop.library.tools.base.VMConstant;
import com.vmloft.develop.library.tools.picker.bean.VMFolderBean;
import com.vmloft.develop.library.tools.picker.bean.VMPictureBean;
import com.vmloft.develop.library.tools.picker.ui.VMPickGridActivity;
import com.vmloft.develop.library.tools.utils.VMDimen;
import com.vmloft.develop.library.tools.utils.VMStr;
import com.vmloft.develop.library.tools.widget.VMCropView;

import com.vmloft.develop.library.tools.utils.VMFile;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * Create by lzan13 on 2019/05/16
 *
 * 图片选择的入口类,采用单例和弱引用解决Intent传值限制导致的异常
 */
public class VMPicker {
    // 图片选择模式 是否多选 默认为 true
    private boolean mMultiMode = true;
    // 图片加载器接口,需要外部实现,减少三方库依赖
    private ILoaderListener mLoaderListener;
    // 是否开启裁剪,单选模式有效
    private boolean mCrop = true;
    // 裁剪焦点框的宽度
    private int mCropFocusWidth = 256;
    // 裁剪焦点框的高度
    private int mCropFocusHeight = 256;
    // 裁剪图片保存宽度
    private int mCropOutWidth = 720;
    // 裁剪图片保存高度
    private int mCropOutHeight = 720;
    // 裁剪框的形状
    private VMCropView.Style mCropStyle = VMCropView.Style.RECTANGLE;
    // 裁剪缓存文件夹路径
    private String mCropCacheFolder;
    // 裁剪后的图片是否保存为矩形,默认为 false,否则跟随裁剪框的形状
    private boolean mSaveRectangle = false;
    // 最大选择图片数量 默认 9 张
    private int mSelectLimit = 9;
    // 显示相机
    private boolean mShowCamera = true;
    // 选中的图片集合
    private List<VMPictureBean> mSelectedPictures = new ArrayList<>();
    // 定义调用拍照保存文件
    private File mTakePicture;
    // 所有的图片文件夹
    private List<VMFolderBean> mFolderBeans;
    // 当前选中的文件夹位置 0 表示所有图片
    private int mCurrentFolderPosition = 0;
    // 图片选中的监听回调
    private List<OnSelectedPictureListener> mSelectedPictureListeners;

    private VMPicker() {
        mCropFocusWidth = VMDimen.dp2px(256);
        mCropFocusHeight = VMDimen.dp2px(256);
    }

    /**
     * 内部类实现单利模式
     */
    private static class InnerHolder {
        public static VMPicker INSTANCE = new VMPicker();
    }

    /**
     * 获取单例类实例
     */
    public static VMPicker getInstance() {
        return InnerHolder.INSTANCE;
    }

    /**
     * 拍照的方法
     */
    public void takePicture(Activity activity, int requestCode) {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        takePictureIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        if (takePictureIntent.resolveActivity(activity.getPackageManager()) != null) {
            if (VMFile.hasSdcard()) {
                mTakePicture = new File(Environment.getExternalStorageDirectory(), "/DCIM/camera/");
            } else {
                mTakePicture = Environment.getDataDirectory();
            }
            mTakePicture = VMFile.createFile(mTakePicture.getAbsolutePath(), "IMG_", ".jpg");
            if (mTakePicture != null) {
                // 默认情况下,即不需要指定intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
                // 照相机有自己默认的存储路径,拍摄的照片将返回一个缩略图。如果想访问原始图片,
                // 可以通过dat extra能够得到原始图片位置。即,如果指定了目标uri,data就没有数据,
                // 如果没有指定uri,则data就返回有数据!

                Uri uri;
                if (VERSION.SDK_INT <= VERSION_CODES.M) {
                    uri = Uri.fromFile(mTakePicture);
                } else {

                    /**
                     * 7.0 调用系统相机拍照不再允许使用Uri方式,应该替换为 FileProvider
                     * 并且这样可以解决 MIUI 系统上拍照返回 size 为 0 的情况
                     */
                    uri = FileProvider.getUriForFile(activity, VMPickerProvider.getAuthority(activity), mTakePicture);
                    //加入uri权限 要不三星手机不能拍照
                    List<ResolveInfo> resInfoList = activity.getPackageManager()
                        .queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
                    for (ResolveInfo resolveInfo : resInfoList) {
                        String packageName = resolveInfo.activityInfo.packageName;
                        activity.grantUriPermission(packageName, uri,
                            Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    }
                }
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            }
        }
        activity.startActivityForResult(takePictureIntent, requestCode);
    }

    /**
     * 通知系统相册有变化
     */
    public static void notifyGalleryChange(Context context, File file) {
        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri contentUri = Uri.fromFile(file);
        mediaScanIntent.setData(contentUri);
        context.sendBroadcast(mediaScanIntent);
    }

    /**
     * 添加选中图片,选中的图片时全局保存的,方便统一管理
     *
     * @param position 图片位置
     * @param bean     图片实体对象
     * @param isAdd    是否是添加
     */
    public void addSelectedPicture(int position, VMPictureBean bean, boolean isAdd) {
        if (isAdd) {
            mSelectedPictures.add(bean);
        } else {
            mSelectedPictures.remove(bean);
        }
        notifySelectedPictureChanged(position, bean, isAdd);
    }

    /**
     * 通知选中图片有更新
     *
     * @param position 图片位置
     * @param bean     图片实体对象
     * @param isAdd    是否是添加
     */
    private void notifySelectedPictureChanged(int position, VMPictureBean bean, boolean isAdd) {
        if (mSelectedPictureListeners == null) {
            return;
        }
        // 循环通知选中的图片有更新
        for (OnSelectedPictureListener listener : mSelectedPictureListeners) {
            listener.onPictureSelected(position, bean, isAdd);
        }
    }

    /**
     * --------------------------- 链式调用设置属性方法 ---------------------------
     */
    /**
     * 设置是否为多图抹式,默认为 true
     *
     * @param multiMode 是否多图模式
     */
    public VMPicker setMultiMode(boolean multiMode) {
        mMultiMode = multiMode;
        return this;
    }

    /**
     * 设置图片加载接口实现
     *
     * @param pictureLoader 外部实现的图片加载类
     */
    public VMPicker setPictureLoader(ILoaderListener pictureLoader) {
        this.mLoaderListener = pictureLoader;
        return this;
    }

    /**
     * 是否开启剪切 默认为 true,不过这个和单选模式相关联,多选无法使用
     *
     * @param crop 是否剪切
     */
    public VMPicker setCrop(boolean crop) {
        mCrop = crop;
        return this;
    }

    /**
     * 设置裁剪焦点框宽度
     *
     * @param width 裁剪框宽度
     */
    public VMPicker setCropFocusWidth(int width) {
        mCropFocusWidth = width;
        return this;
    }

    /**
     * 设置裁剪焦点框高度
     *
     * @param height 裁剪框高度
     */
    public VMPicker setCropFocusHeight(int height) {
        mCropFocusHeight = height;
        return this;
    }

    /**
     * 设置裁剪图片输出宽度
     *
     * @param width 裁剪输出宽度
     */
    public VMPicker setCropOutWidth(int width) {
        mCropOutWidth = width;
        return this;
    }

    /**
     * 设置裁剪图片输出宽高度
     *
     * @param height 裁剪输出高度
     */
    public VMPicker setCropOutHeight(int height) {
        mCropOutHeight = height;
        return this;
    }

    /**
     * 设置裁剪框样式 {@link VMCropView.Style}
     *
     * @param style 裁剪框样式
     */
    public VMPicker setCropStyle(VMCropView.Style style) {
        mCropStyle = style;
        return this;
    }

    /**
     * 设置裁剪图片缓存文件夹路径
     *
     * @param folder 文件夹地址
     */
    public void setCropCacheFolder(String folder) {
        mCropCacheFolder = folder;
    }

    /**
     * 设施是否保存为剪切区域的矩形数据,默认为 false
     *
     * @param saveRectangle 保存为矩形
     */
    public VMPicker setSaveRectangle(boolean saveRectangle) {
        mSaveRectangle = saveRectangle;
        return this;
    }

    /**
     * 设置选择限制 默认 9 个
     *
     * @param limit 最多选择多少个
     */
    public VMPicker setSelectLimit(int limit) {
        mSelectLimit = limit;
        return this;
    }

    /**
     * 设置是否显示相机选项 默认为 true
     *
     * @param showCamera 是否显示相机
     */
    public VMPicker setShowCamera(boolean showCamera) {
        mShowCamera = showCamera;
        return this;
    }

    /**
     * 设置选中的图像集合,这个主要是在已经选中了的情况下又打开选择器,外部传入
     *
     * @param pictures 已经选中的图片集合
     */
    public VMPicker setSelectedPictures(List<VMPictureBean> pictures) {
        if (pictures == null) {
            return this;
        }
        mSelectedPictures = pictures;
        return this;
    }

    /**
     * 启动选择器
     */
    public void startPicker(Activity activity) {
        Intent intent = new Intent(activity, VMPickGridActivity.class);
        intent.putParcelableArrayListExtra(VMConstant.VM_KEY_PICK_PICTURES, (ArrayList<? extends Parcelable>) mSelectedPictures);
        activity.startActivityForResult(intent, VMConstant.VM_PICK_REQUEST_CODE);
    }

    /**
     * 启动选择器,通过 Fragment 打开
     */
    public void startPicker(Fragment fragment) {
        Intent intent = new Intent(fragment.getContext(), VMPickGridActivity.class);
        intent.putParcelableArrayListExtra(VMConstant.VM_KEY_PICK_PICTURES, (ArrayList<? extends Parcelable>) mSelectedPictures);
        fragment.startActivityForResult(intent, VMConstant.VM_PICK_REQUEST_CODE);
    }

    /**
     * 设置文件夹集合
     *
     * @param folders 文件夹集合
     */
    public void setFolderBeans(List<VMFolderBean> folders) {
        mFolderBeans = folders;
    }

    /**
     * 设置当前选中的文件夹在文件夹列表中的位置
     *
     * @param position 当前选中的在列表中的位置
     */
    public void setCurrentFolderPosition(int position) {
        mCurrentFolderPosition = position;
    }

    /**
     * --------------------------- 获取一些属性 ---------------------------
     */
    /**
     * 判断是不是多选模式
     */
    public boolean isMultiMode() {
        return mMultiMode;
    }

    /**
     * 获取图片加载实例
     */
    public ILoaderListener getPictureLoader() {
        return mLoaderListener;
    }

    /**
     * 判断是否开启剪切
     */
    public boolean isCrop() {
        return mCrop;
    }

    /**
     * 获取裁剪输出宽度
     */
    public int getCropOutWidth() {
        return mCropOutWidth;
    }

    /**
     * 获取裁剪输出高度
     */
    public int getCropOutHeight() {
        return mCropOutHeight;
    }

    /**
     * 获取裁剪框宽度
     */
    public int getCropFocusWidth() {
        return mCropFocusWidth;
    }

    /**
     * 获取裁剪框高度
     */
    public int getCropFocusHeight() {
        return mCropFocusHeight;
    }

    /**
     * 获取裁剪框样式
     */
    public VMCropView.Style getCropStyle() {
        return mCropStyle;
    }

    /**
     * 获取缓存文件夹
     */
    public String getCropCacheFolder() {
        if (VMStr.isEmpty(mCropCacheFolder)) {
            mCropCacheFolder = VMFile.getCacheFromSDCard();
        }
        return mCropCacheFolder;
    }

    /**
     * 判断是否保存为矩形
     */
    public boolean isSaveRectangle() {
        return mSaveRectangle;
    }

    /**
     * 获取选择限制
     *
     * @return 最多选择多少个
     */
    public int getSelectLimit() {
        return mSelectLimit;
    }

    /**
     * 判断是否显示相机
     */
    public boolean isShowCamera() {
        return mShowCamera;
    }

    /**
     * 获取已选择的图片集合
     */
    public List<VMPictureBean> getSelectedPictures() {
        return mSelectedPictures;
    }

    /**
     * 判断已选择图片是否包含指定对象
     *
     * @param bean 要判断是否包含的对象
     */
    public boolean isSelectPicture(VMPictureBean bean) {
        return mSelectedPictures.contains(bean);
    }

    /**
     * 获取要选择的数据对象个数
     */
    public int getSelectPictureCount() {
        if (mSelectedPictures == null) {
            return 0;
        }
        return mSelectedPictures.size();
    }

    /**
     * 获取拍照保存的文件
     */
    public File getTakeImageFile() {
        return mTakePicture;
    }

    /**
     * 获取文件夹列表集合
     */
    public List<VMFolderBean> getFolderBeans() {
        return mFolderBeans;
    }

    /**
     * 获取当前选中的文件夹位置
     */
    public int getCurrentFolderPosition() {
        return mCurrentFolderPosition;
    }

    /**
     * 获取当前文件夹下图片集合
     */
    public ArrayList<VMPictureBean> getCurrentFolderPictures() {
        return mFolderBeans.get(mCurrentFolderPosition).pictures;
    }

    /**
     * 获取选择结果数据
     */
    public List<VMPictureBean> getResultData() {
        List<VMPictureBean> result = new ArrayList<>();
        result.addAll(mSelectedPictures);
        reset();
        return result;
    }

    /**
     * 清空当前选择的图片
     */
    public void clearSelectedPictures() {
        if (mSelectedPictures != null) {
            mSelectedPictures.clear();
        }
    }

    /**
     * 重置选择器
     */
    public void reset() {
        if (mSelectedPictureListeners != null) {
            mSelectedPictureListeners.clear();
            mSelectedPictureListeners = null;
        }
        if (mFolderBeans != null) {
            mFolderBeans.clear();
            mFolderBeans = null;
        }
        if (mSelectedPictures != null) {
            mSelectedPictures.clear();
        }
        mCurrentFolderPosition = 0;
    }

    /**
     * 用于手机内存不足,进程被系统回收,重启时的状态恢复
     */
    public void restoreInstanceState(Bundle savedInstanceState) {
        mMultiMode = savedInstanceState.getBoolean("multiMode");
        mSelectLimit = savedInstanceState.getInt("selectLimit");
        mCrop = savedInstanceState.getBoolean("crop");
        mShowCamera = savedInstanceState.getBoolean("showCamera");
        mSaveRectangle = savedInstanceState.getBoolean("isSaveRectangle");
        mCropOutWidth = savedInstanceState.getInt("outPutX");
        mCropOutHeight = savedInstanceState.getInt("outPutY");
        mCropFocusWidth = savedInstanceState.getInt("focusWidth");
        mCropFocusHeight = savedInstanceState.getInt("focusHeight");
        mCropStyle = (VMCropView.Style) savedInstanceState.getSerializable("style");
        mCropCacheFolder = savedInstanceState.getString("cropCacheFolder");
        mLoaderListener = (ILoaderListener) savedInstanceState.getSerializable("mLoaderListener");
        mTakePicture = (File) savedInstanceState.getSerializable("takeImageFile");
    }

    /**
     * 用于手机内存不足,进程被系统回收时的状态保存
     */
    public void saveInstanceState(Bundle outState) {
        outState.putBoolean("multiMode", mMultiMode);
        outState.putBoolean("crop", mCrop);
        outState.putInt("selectLimit", mSelectLimit);
        outState.putBoolean("showCamera", mShowCamera);
        outState.putBoolean("isSaveRectangle", mSaveRectangle);
        outState.putInt("outPutX", mCropOutWidth);
        outState.putInt("outPutY", mCropOutHeight);
        outState.putInt("focusWidth", mCropFocusWidth);
        outState.putInt("focusHeight", mCropFocusHeight);
        outState.putSerializable("style", mCropStyle);
        outState.putString("cropCacheFolder", mCropCacheFolder);
        outState.putSerializable("mLoaderListener", mLoaderListener);
        outState.putSerializable("takeImageFile", mTakePicture);
    }

    /**
     * ---------------------------------------------------------------
     *
     * 图片选中的监听
     */
    public interface OnSelectedPictureListener {
        void onPictureSelected(int position, VMPictureBean item, boolean isAdd);
    }

    /**
     * 添加图片选中监听回调
     */
    public void addOnSelectedPictureListener(OnSelectedPictureListener listener) {
        if (mSelectedPictureListeners == null) {
            mSelectedPictureListeners = new ArrayList<>();
        }
        mSelectedPictureListeners.add(listener);
    }

    /**
     * 移除图片选中监听回调
     */
    public void removeOnSelectedPictureListener(OnSelectedPictureListener listener) {
        if (mSelectedPictureListeners == null) {
            return;
        }
        mSelectedPictureListeners.remove(listener);
    }
}