using UnityEngine;
using UnityEditor;
using System.Linq;

namespace Klak.Spout.Editor {

static class MaterialPropertySelector
{
    #region Public method

    // Material property dropdown list
    public static void DropdownList
      (SerializedProperty rendererProperty,
       SerializedProperty materialProperty)
    {
        var shader = GetShaderFromRenderer(rendererProperty);

        // Abandon the current value if there is no shader assignment.
        if (shader == null)
        {
            materialProperty.stringValue = "";
            return;
        }

        var names = CachePropertyNames(shader);

        // Abandon the current value if there is no option.
        if (names.Length == 0)
        {
            materialProperty.stringValue = "";
            return;
        }

        // Dropdown GUI
        var index = System.Array.IndexOf(names, materialProperty.stringValue);
        var newIndex = EditorGUILayout.Popup("Property", index, names);
        if (index != newIndex) materialProperty.stringValue = names[newIndex];
    }

    #endregion

    #region Utility function

    // Shader retrieval function
    static Shader GetShaderFromRenderer(SerializedProperty property)
    {
        var renderer = property.objectReferenceValue as Renderer;
        if (renderer == null) return null;

        var material = renderer.sharedMaterial;
        if (material == null) return null;

        return material.shader;
    }

    #endregion

    #region Property name cache

    static Shader _cachedShader;
    static string[] _cachedPropertyNames;

    static bool IsPropertyTexture(Shader shader, int index)
      => ShaderUtil.GetPropertyType(shader, index) ==
         ShaderUtil.ShaderPropertyType.TexEnv;

    static string[] CachePropertyNames(Shader shader)
    {
        if (shader == _cachedShader) return _cachedPropertyNames;

        var names =
          Enumerable.Range(0, ShaderUtil.GetPropertyCount(shader))
          .Where(i => IsPropertyTexture(shader, i))
          .Select(i => ShaderUtil.GetPropertyName(shader, i));

        _cachedShader = shader;
        _cachedPropertyNames = names.ToArray();

        return _cachedPropertyNames;
    }

    #endregion
}

} // namespace Klak.Spout.Editor
