#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;

namespace OpenCVForUnity.Editor
{
    public class OpenCVForUnityMenuItem : MonoBehaviour
    {
        // Constants
        private static readonly string SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE = "OPENCV_DONT_USE_UNSAFE_CODE";

        // Private Fields
        private static int _pluginFileIndex = 0;
        private static int _pluginFileCount = 0;

        // Public Methods
        public static void SetPluginImportSettings()
        {
            try
            {
                string[] guids = UnityEditor.AssetDatabase.FindAssets("OpenCVForUnityMenuItem");
                if (guids.Length == 0)
                {
                    Debug.LogWarning("SetPluginImportSettings Failed : OpenCVForUnityMenuItem.cs is missing.");
                    return;
                }
                string opencvForUnityFolderPath = AssetDatabase.GUIDToAssetPath(guids[0]).Substring(0, AssetDatabase.GUIDToAssetPath(guids[0]).LastIndexOf("/Editor/OpenCVForUnityMenuItem.cs"));

                string pluginsFolderPath = opencvForUnityFolderPath + "/Plugins";
                //Debug.Log("pluginsFolderPath " + pluginsFolderPath);

                string extraFolderPath = opencvForUnityFolderPath + "/Extra";
                //Debug.Log("extraFolderPath " + extraFolderPath);

                _pluginFileIndex = 0;
                _pluginFileCount = GetPluginFileCount(pluginsFolderPath) + GetPluginFileCount(extraFolderPath);

                //Android
                SetAndroidPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //iOS
                SetIOSPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //VisionOS
                SetVisionOSPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //OSX
                SetOSXPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //Windows
                SetWindowsPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //Linux
                SetLinuxPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //UWP
                SetUWPPluginImportSettings(pluginsFolderPath, extraFolderPath, true);

                //WebGL
                SetWebGLPluginImportSettings(pluginsFolderPath, extraFolderPath, true);
            }
            catch (Exception e)
            {
                Debug.Log("SetPluginImportSettings() " + e);
            }
            finally
            {
                EditorUtility.ClearProgressBar();
            }

            //Debug.Log("pluginFilesIndex " + _pluginFileIndex);
            //Debug.Log("pluginFilesCount " + _pluginFileCount);
        }

        public static void SetAndroidPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/exclude_contrib/Android/libs/armeabi-v7a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/exclude_contrib/Android/libs/arm64-v8a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/exclude_contrib/Android/libs/x86_64"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/libs/armeabi-v7a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/libs/arm64-v8a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/libs/x86_64"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/exclude_contrib/libs/armeabi-v7a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/exclude_contrib/libs/arm64-v8a"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(extraFolderPath + "/dll_version/Android/exclude_contrib/libs/x86_64"), null, null, displayProgressBar);

            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/Android/libs/armeabi-v7a"), null,
    new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.Android,new Dictionary<string, string> () { {
                                            "CPU",
                                            "ARMv7"
                                        }
                                    }
                                }
    }, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/Android/libs/arm64-v8a"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.Android,new Dictionary<string, string> () { {
                                            "CPU",
                                            "ARM64"
                                        }
                                    }
                                }
                }, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/Android/libs/x86_64"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.Android,new Dictionary<string, string> () { {
                                            "CPU",
                                            "x86_64"
                                        }
                                    }
                                }
                }, displayProgressBar);
        }

        public static void SetIOSPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false, bool incrementalBuild = false)
        {
            SetPlugins(new string[] { extraFolderPath + "/exclude_contrib/iOS/device/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(new string[] { extraFolderPath + "/exclude_contrib/iOS/device/libopencvforunity.a" }, null, null, displayProgressBar);
            SetPlugins(new string[] { extraFolderPath + "/exclude_contrib/iOS/simulator/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(new string[] { extraFolderPath + "/exclude_contrib/iOS/simulator/libopencvforunity.a" }, null, null, displayProgressBar);

            SetPlugins(new string[] { pluginsFolderPath + "/iOS/device/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/iOS/device/libopencvforunity.a" }, null, null, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/iOS/simulator/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/iOS/simulator/libopencvforunity.a" }, null, null, displayProgressBar);

            string sdkVersion = "device";
            if (PlayerSettings.iOS.sdkVersion == iOSSdkVersion.DeviceSDK)
            {
                sdkVersion = "device";
            }
            else
            {
                sdkVersion = "simulator";
            }

            SetPlugins(new string[] { pluginsFolderPath + "/iOS/" + sdkVersion + "/opencv2.framework" }, null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                    BuildTarget.iOS,
                                    incrementalBuild? null : new Dictionary<string, string> () {
                                        { "AddToEmbeddedBinaries", "true" }
                                    }
                                }
}, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/iOS/" + sdkVersion + "/libopencvforunity.a" }, null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                    BuildTarget.iOS,
                                    null
                                }
                }, displayProgressBar);
        }

        public static void SetVisionOSPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false, bool incrementalBuild = false)
        {
            SetPlugins(new string[] { pluginsFolderPath + "/VisionOS/device/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/VisionOS/device"), null, null, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/VisionOS/simulator/opencv2.framework" }, null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/VisionOS/simulator"), null, null, displayProgressBar);

#if (UNITY_2022_3_OR_NEWER && !(UNITY_2023_1_OR_NEWER) && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17)) || UNITY_6000_0_OR_NEWER
            string sdkVersion = "device";
            if (PlayerSettings.VisionOS.sdkVersion == VisionOSSdkVersion.Device)
            {
                sdkVersion = "device";
            }
            else
            {
                sdkVersion = "simulator";
            }

            SetPlugins(new string[] { pluginsFolderPath + "/VisionOS/" + sdkVersion + "/opencv2.framework" }, null,
new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                    BuildTarget.VisionOS,
                                    incrementalBuild? null : new Dictionary<string, string> () {
                                        { "AddToEmbeddedBinaries", "true" }
                                    }
                                }
}, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/VisionOS/" + sdkVersion), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                    BuildTarget.VisionOS,
                                    null
                                }
                }, displayProgressBar);
#endif
        }

        public static void SetOSXPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(new string[] { pluginsFolderPath + "/macOS/opencvforunity.bundle" }, new Dictionary<string, string>() { {
                                "CPU",
                                "AnyCPU"
                            }, {
                                "OS",
                                "OSX"
                            }
                        },
    new Dictionary<BuildTarget, Dictionary<string, string>>() {
                                {
                                    BuildTarget.StandaloneOSX,new Dictionary<string, string> () { {
                                            "CPU",
                                            "AnyCPU"
                                        }
                                    }
                                }
    }, displayProgressBar);
        }

        public static void SetWindowsPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(new string[] { extraFolderPath + "/dll_version/Windows/x86/opencvforunity.dll" }, null, null, displayProgressBar);
            SetPlugins(new string[] { extraFolderPath + "/dll_version/Windows/x86_64/opencvforunity.dll" }, null, null, displayProgressBar);
            SetPlugins(new string[] { extraFolderPath + "/dll_version/Windows/ARM64/opencvforunity.dll" }, null, null, displayProgressBar);

            SetPlugins(new string[] { pluginsFolderPath + "/Windows/x86/opencvforunity.dll" }, new Dictionary<string, string>() { {
                                "CPU",
                                "x86"
                            }, {
                                "OS",
                                "Windows"
                            }
                        },
    new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.StandaloneWindows,new Dictionary<string, string> () { {
                                            "CPU",
                                            "x86"
                                        }
                                    }
                                }
    }, displayProgressBar);
            SetPlugins(new string[] { pluginsFolderPath + "/Windows/x86_64/opencvforunity.dll" }, new Dictionary<string, string>() { {
                                "CPU",
                                "x86_64"
                            }, {
                                "OS",
                                "Windows"
                            }
                        },
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.StandaloneWindows64,new Dictionary<string, string> () { {
                                            "CPU",
                                            "x86_64"
                                        }
                                    }
                                }
                }, displayProgressBar);
#if UNITY_2023_1_OR_NEWER
            SetPlugins(new string[] { pluginsFolderPath + "/Windows/ARM64/opencvforunity.dll" }, new Dictionary<string, string>() { {
                                "CPU",
                                "ARM64"
                            }, {
                                "OS",
                                "Windows"
                            }
                        },
    new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.StandaloneWindows64,new Dictionary<string, string> () { {
                                            "CPU",
                                            "ARM64"
                                        }
                                    }
                                }
    }, displayProgressBar);
#else
            SetPlugins(new string[] { pluginsFolderPath + "/Windows/ARM64/opencvforunity.dll" }, null, null, displayProgressBar);
#endif
        }

        public static void SetLinuxPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/Linux/x86_64"), new Dictionary<string, string>() { {
                                "CPU",
                                "x86_64"
                            }, {
                                "OS",
                                "Linux"
                            }
                        },
    new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.StandaloneLinux64,new Dictionary<string, string> () { {
                                            "CPU",
                                            "x86_64"
                                        }
                                    }
                                },
    }, displayProgressBar);
        }

        public static void SetUWPPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WSA/UWP/ARM"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.WSAPlayer,new Dictionary<string, string> () { {
                                            "SDK",
                                            "UWP"
                                        }, {
                                            "CPU",
                                            "ARM"
                                        }
                                    }
                                }
                }, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WSA/UWP/ARM64"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.WSAPlayer,new Dictionary<string, string> () { {
                                            "SDK",
                                            "UWP"
                                        }, {
                                            "CPU",
                                            "ARM64"
                                        }
                                    }
                                }
                }, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WSA/UWP/x64"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.WSAPlayer,new Dictionary<string, string> () { {
                                            "SDK",
                                            "UWP"
                                        }, {
                                            "CPU",
                                            "x64"
                                        }
                                    }
                                }
                }, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WSA/UWP/x86"), null,
                new Dictionary<BuildTarget, Dictionary<string, string>>() { {BuildTarget.WSAPlayer,new Dictionary<string, string> () { {
                                            "SDK",
                                            "UWP"
                                        }, {
                                            "CPU",
                                            "x86"
                                        }
                                    }
                                }
                }, displayProgressBar);
        }

        public static void SetWebGLPluginImportSettings(string pluginsFolderPath, string extraFolderPath, bool displayProgressBar = false)
        {
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WebGL/2021.2"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WebGL/2022.2"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WebGL/2023.2/wasm2023"), null, null, displayProgressBar);
            SetPlugins(GetPluginFilePaths(pluginsFolderPath + "/WebGL/2023.2/wasmMVP"), null, null, displayProgressBar);

            string version = "2021.2";
#if UNITY_2023_2_OR_NEWER
            version = "2023.2";
#elif UNITY_2022_2_OR_NEWER
            version = "2022.2";
#elif UNITY_2021_2_OR_NEWER
            version = "2021.2";
#endif

            bool simd = ValidateUseWebGLSIMDSupport();
            bool threads = ValidateUseWebGLThreadsSupport();

            string target = "";
#if UNITY_2023_3_OR_NEWER
            // Untiy2023.3 or later automatically sets PlayerSettings.WebGL.wasm2023 to true when PlayerSettings.WebGL.threadsSupport is true.
            if (threads)
                UseWebGLWasm2023Support(true);

            // simd is true when PlayerSettings.WebGL.wasm2023 is true.
            if (ValidateUseWasm2023Support())
                simd = true;

            target = PlayerSettings.WebGL.wasm2023 ? "wasm2023" : "wasmMVP";
#elif UNITY_2023_2_OR_NEWER
            target = "wasmMVP";
#endif

            if (threads && simd)
            {
                SetPlugins(new string[] { pluginsFolderPath + "/WebGL/" + version + "/" + target + "/opencvforunity_simd_threads.bc" }, null, new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                            BuildTarget.WebGL,
                                            null
                                        }
                                    }, displayProgressBar);
            }
            else if (threads)
            {
                SetPlugins(new string[] { pluginsFolderPath + "/WebGL/" + version + "/" + target + "/opencvforunity_threads.bc" }, null, new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                            BuildTarget.WebGL,
                                            null
                                        }
                                    }, displayProgressBar);
            }
            else if (simd)
            {
                SetPlugins(new string[] { pluginsFolderPath + "/WebGL/" + version + "/" + target + "/opencvforunity_simd.bc" }, null, new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                            BuildTarget.WebGL,
                                            null
                                        }
                                    }, displayProgressBar);
            }
            else
            {
                SetPlugins(new string[] { pluginsFolderPath + "/WebGL/" + version + "/" + target + "/opencvforunity.bc" }, null, new Dictionary<BuildTarget, Dictionary<string, string>>() { {
                                            BuildTarget.WebGL,
                                            null
                                        }
                                    }, displayProgressBar);
            }

            if (PlayerSettings.WebGL.exceptionSupport == WebGLExceptionSupport.None)
                PlayerSettings.WebGL.exceptionSupport = WebGLExceptionSupport.ExplicitlyThrownExceptionsOnly;
        }

        public static bool ValidateUseUnsafeCode()
        {
            return !EditorUserBuildSettings.activeScriptCompilationDefines.Contains(SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
        }

        public static void UseUnsafeCode(bool enable)
        {
            if (!enable)
            {
                if (EditorUtility.DisplayDialog("Disable Unsafe Code",
                "Do you want to disable Unsafe Code in OpenCV for Unity?", "Yes", "Cancel"))
                {
                    Symbol.Add(NamedBuildTarget.Standalone, Symbol.GetCurrentSymbols(NamedBuildTarget.Standalone), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Add(NamedBuildTarget.Android, Symbol.GetCurrentSymbols(NamedBuildTarget.Android), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Add(NamedBuildTarget.iOS, Symbol.GetCurrentSymbols(NamedBuildTarget.iOS), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
#if (UNITY_2022_3_OR_NEWER && !(UNITY_2023_1_OR_NEWER) && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17)) || UNITY_6000_0_OR_NEWER
                    Symbol.Add(NamedBuildTarget.VisionOS, Symbol.GetCurrentSymbols(NamedBuildTarget.VisionOS), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
#endif
                    Symbol.Add(NamedBuildTarget.WebGL, Symbol.GetCurrentSymbols(NamedBuildTarget.WebGL), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Add(NamedBuildTarget.WindowsStoreApps, Symbol.GetCurrentSymbols(NamedBuildTarget.WindowsStoreApps), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);

                    Debug.Log("\"" + SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE + "\" has been added to Scripting Define Symbols.");
                    EditorUtility.DisplayDialog("success!!",
                        "\"" + SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE + "\" has been added to Scripting Define Symbols.", "OK");
                }
            }
            else
            {
                if (EditorUtility.DisplayDialog("Enable Unsafe Code",
                "Do you want to enable Unsafe Code in OpenCV for Unity?", "Yes", "Cancel"))
                {
                    Symbol.Remove(NamedBuildTarget.Standalone, Symbol.GetCurrentSymbols(NamedBuildTarget.Standalone), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Remove(NamedBuildTarget.Android, Symbol.GetCurrentSymbols(NamedBuildTarget.Android), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Remove(NamedBuildTarget.iOS, Symbol.GetCurrentSymbols(NamedBuildTarget.iOS), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
#if (UNITY_2022_3_OR_NEWER && !(UNITY_2023_1_OR_NEWER) && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17)) || UNITY_6000_0_OR_NEWER
                    Symbol.Remove(NamedBuildTarget.VisionOS, Symbol.GetCurrentSymbols(NamedBuildTarget.VisionOS), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
#endif
                    Symbol.Remove(NamedBuildTarget.WebGL, Symbol.GetCurrentSymbols(NamedBuildTarget.WebGL), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Symbol.Remove(NamedBuildTarget.WindowsStoreApps, Symbol.GetCurrentSymbols(NamedBuildTarget.WindowsStoreApps), SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE);
                    Debug.Log("\"" + SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE + "\" has been removed from Scripting Define Symbols.");
                    EditorUtility.DisplayDialog("success!!",
                "\"" + SYMBOL_OPENCV_DONT_USE_UNSAFE_CODE + "\" has been removed from Scripting Define Symbols.", "OK");
                }
            }
        }

        public static bool ValidateUseWebGLThreadsSupport()
        {
            return PlayerSettings.WebGL.threadsSupport;
        }

        public static void UseWebGLThreadsSupport(bool enable)
        {
            PlayerSettings.WebGL.threadsSupport = enable;
        }

        public static bool ValidateUseWebGLSIMDSupport()
        {
            return PlayerSettings.WebGL.emscriptenArgs.Contains("-msimd128");
        }

        public static void UseWebGLSIMDSupport(bool enable)
        {
            if (enable)
            {
                PlayerSettings.WebGL.emscriptenArgs += "-msimd128";
            }
            else
            {
                PlayerSettings.WebGL.emscriptenArgs = PlayerSettings.WebGL.emscriptenArgs.Replace("-msimd128", "");
            }
        }

        public static bool ValidateUseWasm2023Support()
        {
#if UNITY_2023_3_OR_NEWER
            if (PlayerSettings.WebGL.wasm2023 || PlayerSettings.WebGL.threadsSupport)
            {
                return true;
            }
#endif
            return false;
        }

        public static void UseWebGLWasm2023Support(bool enable)
        {
#if UNITY_2023_3_OR_NEWER
            PlayerSettings.WebGL.wasm2023 = enable;
#endif
            return;
        }

        //[MenuItem("Tools/OpenCV for Unity/Import Extra Package", false, 24)]
        public static void ImportExtraPackage()
        {
            AssetDatabase.ImportPackage("Assets/OpenCVForUnity/Extra.unitypackage", true);
        }

        [MenuItem("Tools/OpenCV for Unity/Open OpenCV for Unity API Reference", false, 35)]
        public static void OpenOpenCVForUnityAPIReference()
        {
            Application.OpenURL("https://enoxsoftware.github.io/OpenCVForUnity/doc/html/annotated.html");
        }

        [MenuItem("Tools/OpenCV for Unity/Open OpenCV C++ API Reference", false, 36)]
        public static void OpenOpenCVAPIReference()
        {
            Application.OpenURL("http://docs.opencv.org/4.13.0/index.html");
        }

        // Private Methods
        private static int GetPluginFileCount(string folderPath)
        {
            int pluginFileCount = 0;

            Regex reg = new Regex(".meta$|.DS_Store$|.zip$|.bundle|.framework");
            try
            {
                pluginFileCount += Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories).Where(f => !reg.IsMatch(f)).Count();
            }
            catch (Exception)
            {
                //Debug.LogWarning("SetPluginImportSettings Faild :" + ex);
                return 0;
            }

            pluginFileCount += Directory.GetDirectories(folderPath, "*.bundle", SearchOption.AllDirectories).Count();
            pluginFileCount += Directory.GetDirectories(folderPath, "*.framework", SearchOption.AllDirectories).Count();

            return pluginFileCount;
        }

        private static string[] GetPluginFilePaths(string folderPath)
        {
            Regex reg = new Regex(".meta$|.DS_Store$|.zip");
            try
            {
                return Directory.GetFiles(folderPath).Where(f => !reg.IsMatch(f)).Select(n => n.Replace("\\", "/")).ToArray();
            }
            catch (Exception)
            {
                //Debug.LogWarning("SetPluginImportSettings Faild :" + ex);
                return null;
            }
        }

        private static void SetPlugins(string[] files, Dictionary<string, string> editorSettings, Dictionary<BuildTarget, Dictionary<string, string>> settings, bool displayProgressBar)
        {
            if (files == null)
                return;

            foreach (string item in files)
            {
                PluginImporter pluginImporter = PluginImporter.GetAtPath(item) as PluginImporter;

                if (pluginImporter != null)
                {
                    //if(displayProgressBar) EditorUtility.DisplayProgressBar("Set Plugin Import Settings", item, 1);
                    if (displayProgressBar)
                    {
                        EditorUtility.DisplayProgressBar("Set Plugin Import Settings", string.Format("{0} / {1} " + item, _pluginFileIndex + 1, _pluginFileCount), (float)_pluginFileIndex / _pluginFileCount);
                        _pluginFileIndex++;
                    }

                    pluginImporter.SetCompatibleWithAnyPlatform(false);
                    pluginImporter.SetCompatibleWithEditor(false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.iOS, false);
#if (UNITY_2022_3_OR_NEWER && !(UNITY_2023_1_OR_NEWER) && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17)) || UNITY_6000_0_OR_NEWER
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.VisionOS, false);
#endif
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneOSX, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.WSAPlayer, false);
                    pluginImporter.SetCompatibleWithPlatform(BuildTarget.WebGL, false);

                    if (editorSettings != null)
                    {
                        pluginImporter.SetCompatibleWithEditor(true);

                        foreach (KeyValuePair<string, string> pair in editorSettings)
                        {
                            if (pluginImporter.GetEditorData(pair.Key) != pair.Value)
                            {
                                pluginImporter.SetEditorData(pair.Key, pair.Value);
                            }
                        }
                    }

                    if (settings != null)
                    {
                        foreach (KeyValuePair<BuildTarget, Dictionary<string, string>> settingPair in settings)
                        {
                            pluginImporter.SetCompatibleWithPlatform(settingPair.Key, true);
                            if (settingPair.Value != null)
                            {
                                foreach (KeyValuePair<string, string> pair in settingPair.Value)
                                {
                                    if (pluginImporter.GetPlatformData(settingPair.Key, pair.Key) != pair.Value)
                                    {
                                        pluginImporter.SetPlatformData(settingPair.Key, pair.Key, pair.Value);
                                    }
                                }
                            }
                        }

                        pluginImporter.isPreloaded = true;
                    }
                    else
                    {
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.Android, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.iOS, false);
#if (UNITY_2022_3_OR_NEWER && !(UNITY_2023_1_OR_NEWER) && !(UNITY_2022_3_0 || UNITY_2022_3_1 || UNITY_2022_3_2 || UNITY_2022_3_3 || UNITY_2022_3_4 || UNITY_2022_3_5 || UNITY_2022_3_6 || UNITY_2022_3_7 || UNITY_2022_3_8 || UNITY_2022_3_9 || UNITY_2022_3_10 || UNITY_2022_3_11 || UNITY_2022_3_12 || UNITY_2022_3_13 || UNITY_2022_3_14 || UNITY_2022_3_15 || UNITY_2022_3_16 || UNITY_2022_3_17)) || UNITY_6000_0_OR_NEWER
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.VisionOS, false);
#endif
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneWindows64, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneOSX, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.StandaloneLinux64, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.WSAPlayer, false);
                        pluginImporter.SetCompatibleWithPlatform(BuildTarget.WebGL, false);

                        pluginImporter.isPreloaded = false;
                    }

                    pluginImporter.SaveAndReimport();

                    if (displayProgressBar) Debug.Log("SetPluginImportSettings Success :" + item);
                }
                else
                {
                    //Debug.LogWarning("SetPluginImportSettings Faild :" + item);
                }
            }
        }

        private static class Symbol
        {
            public static IEnumerable<string> GetCurrentSymbols(NamedBuildTarget nameBuildTarget)
            {
                return PlayerSettings.GetScriptingDefineSymbols(nameBuildTarget).Split(';');
            }

            private static void SaveSymbol(NamedBuildTarget nameBuildTarget, IEnumerable<string> currentSymbols)
            {
                var symbols = String.Join(";", currentSymbols.ToArray());
                PlayerSettings.SetScriptingDefineSymbols(nameBuildTarget, symbols);
            }

            public static void Add(NamedBuildTarget nameBuildTarget, IEnumerable<string> currentSymbols, params string[] symbols)
            {
                currentSymbols = currentSymbols.Except(symbols);
                currentSymbols = currentSymbols.Concat(symbols).Distinct();
                SaveSymbol(nameBuildTarget, currentSymbols);
            }

            public static void Remove(NamedBuildTarget nameBuildTarget, IEnumerable<string> currentSymbols, params string[] symbols)
            {
                currentSymbols = currentSymbols.Except(symbols);
                SaveSymbol(nameBuildTarget, currentSymbols);
            }

            public static void Set(NamedBuildTarget nameBuildTarget, IEnumerable<string> currentSymbols, params string[] symbols)
            {
                SaveSymbol(nameBuildTarget, symbols);
            }
        }
    }
}
#endif
