//============= Copyright (c) Ludic GmbH, All rights reserved. ==============
//
// Purpose: Generate Procompiler settings in Unity
//
//=============================================================================

using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEditorInternal;

public delegate bool AvailableCallbackDelegate(string str);

public class CompilerSetting {
    public string longName;
    public string precompilerName;

    public AvailableCallbackDelegate availableCallback;
    public string availableCallbackParameter;

    public void UpdateAvailable () {
        isAvailableCache = isAvailableCurrently;
    }

    public bool isAvailableCache;
    public bool isAvailableCurrently {
        get {
            return availableCallback(availableCallbackParameter);
        }
    }

    public CompilerSetting (string _longName, string _precompilerName, AvailableCallbackDelegate _availableCallback, string _availableCallbackParameter) {
        longName = _longName;
        precompilerName = _precompilerName;
        availableCallback = _availableCallback;
        availableCallbackParameter = _availableCallbackParameter;
        // update value
        isAvailableCache = isAvailableCurrently;
    }
}


public class PreCompilerDefinitions : EditorWindow {

    public List<CompilerSetting> compilerSettings = new List<CompilerSetting>() {
        new CompilerSetting("Leap Lib Available", "LEAPMOTION_AVAILABLE", NamespaceExists, "Leap"),
        new CompilerSetting("SteamVR Lib Available", "STEAMVR_AVAILABLE", ClassExists, "SteamVR_Controller"),
        new CompilerSetting("OculusVR Available", "OCULUSVR_AVAILABLE", ClassExists, "OVRInput"),
        new CompilerSetting("FMod Lib Available", "FMOD_AVAILABLE", NamespaceExists, "FMODUnity"),
        new CompilerSetting("Megafiers Lib Available", "MEGAFIERS_AVAILABLE", ClassExists, "MegaCacheUtils"),
        new CompilerSetting("Depthkit Available", "DEPTHKIT_AVAILABLE", NamespaceExists, "Depthkit"),
        new CompilerSetting("TextMeshPro Available", "TMPRO_AVAILABLE", NamespaceExists, "TMPro"),
        new CompilerSetting("Curvy Available", "CURVY_AVAILABLE", NamespaceExists, "FluffyUnderware.Curvy"),
    };

    [MenuItem ("Window/MyBT/Precompiler Definitions", false, 100)]
    public static void ShowWindow () {
        EditorWindow.GetWindow (typeof (PreCompilerDefinitions));
    }

    public void Awake() {
        ReadValuesFromSystem();
    }

    public void ReadValuesFromSystem () {
        foreach (CompilerSetting compilerSetting in compilerSettings) {
            compilerSetting.UpdateAvailable();
        }
    }

    public void OnGUI () {
        if (GUILayout.Button("Read Values from System")) {
            ReadValuesFromSystem();
        }

        GUILayout.Label("Libraries Found");
        GUI.enabled = false;
        foreach (CompilerSetting compilerSetting in compilerSettings) {
            EditorGUILayout.Toggle(compilerSetting.longName, compilerSetting.isAvailableCache);
        }
        GUI.enabled = true;

        GUILayout.Label("Current Unity Scripting Define Symbols");
        GUI.enabled = false;
        GUILayout.TextField(PlayerSettings.GetScriptingDefineSymbolsForGroup (EditorUserBuildSettings.selectedBuildTargetGroup));
        GUI.enabled = true;

        if (GUILayout.Button ("Update Precompile Symbols")) {
            UpdatePrecompileSymbols ();
        }

        GUILayout.BeginHorizontal();
        GUILayout.Label($"Active BuildTargetGroup");
        GUI.enabled = false;
        GUILayout.Label($"{EditorUserBuildSettings.selectedBuildTargetGroup}");
        GUI.enabled = true;
        GUILayout.EndHorizontal();
    }

    private void UpdatePrecompileSymbols () {
        foreach (CompilerSetting compilerSetting in compilerSettings) {
            compilerSetting.UpdateAvailable();
            DefinePrecompileSymbol(compilerSetting.precompilerName, compilerSetting.isAvailableCache);
        }
    }

    // method3
    private static bool ClassExists (string className) {
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies ()) {
            foreach (Type type in assembly.GetTypes ()) {
                if (type.Name == className)
                    return true;
            }
        }
        return false;
        // Type t = System.Reflection.Assembly.GetExecutingAssembly ().GetType (className, false);
        // return (t != null);
    }

    private static bool NamespaceExists (string desiredNamespace) {
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies ()) {
            foreach (Type type in assembly.GetTypes ()) {
                if (type.Namespace == desiredNamespace)
                    return true;
            }
        }
        return false;
    }

    private void DefinePrecompileSymbol (string newSymbol, bool newState) {
        //bool currentActive = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup).Contains(newSymbol);
        List<String> allCurrentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup (EditorUserBuildSettings.selectedBuildTargetGroup).Split (';').ToList ();
        if (allCurrentSymbols.Contains (newSymbol) != newState) {
            if (newState) {
                allCurrentSymbols.Add (newSymbol);
                // add the symbol
                string newSymbols = string.Join (";", allCurrentSymbols.ToArray ());
                Debug.LogWarning ("PreCompilerDefinitions.DefineCompileSymbol: adding " + newSymbol + " to compile preprocessors -> " + newSymbols);
                PlayerSettings.SetScriptingDefineSymbolsForGroup (EditorUserBuildSettings.selectedBuildTargetGroup, newSymbols);
            } else {
                allCurrentSymbols.Remove (newSymbol);
                // remove the symbol
                string newSymbols = string.Join (";", allCurrentSymbols.ToArray ());
                Debug.LogWarning ("PreCompilerDefinitions.DefineCompileSymbol: removing " + newSymbol + " from compile preprocessors -> " + newSymbols);
                PlayerSettings.SetScriptingDefineSymbolsForGroup (EditorUserBuildSettings.selectedBuildTargetGroup, newSymbols);
            }
        }
    }
}