using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;

namespace Ethanol.MalwareSonar.Fuzzy
{
    /// <summary>
    /// Represents a fuzzy set which is a mathematical set that defines
    /// the membership of elements in a continuum of values between 0 and 1.
    /// </summary>
    public class FuzzySet<T> where T : notnull
    {

        // The membership function used to determine the degree of membership 
        // of a given element in this fuzzy set.
        private IMembershipFunction<T> _membershipFunction;
        private readonly ImmutableHashSet<T> _members;

        public IImmutableSet<T> Members => _members;
        
        /// <summary>
        /// Initializes a new instance of the <see cref="FuzzySet"/> class.
        /// </summary>
        /// <param name="name">The name of the fuzzy set.</param>
        /// <param name="membershipFunction">The membership function to use for this set.</param>
        public FuzzySet(IMembershipFunction<T> membershipFunction, IEnumerable<T> members)
        {
            this._membershipFunction = membershipFunction;
            this._members = new HashSet<T>(members).ToImmutableHashSet();
        }

        /// <summary>
        /// Retrieves the membership value of a given element in the fuzzy set.
        /// </summary>
        /// <param name="x">The element for which to retrieve the membership value.</param>
        /// <returns>The membership value, between 0 and 1.</returns>
        public double GetMembership(T x)
        {
            return _membershipFunction.GetMembership(x);
        }


        public static FuzzySet<T> FromEnumerable(IEnumerable<T> members)
        {
            return new FuzzySet<T>(new ValueBasedMembership<T>(members.ToDictionary<T,T,double>(x => x, x=> 1)), members);
        }

        public IDictionary<T, double> GetMembershipValues()
        {
            return _members.ToDictionary(x => x, x => _membershipFunction.GetMembership(x));
        }

        public static FuzzySet<T> Empty => new FuzzySet<T>(new ValueBasedMembership<T>(new Dictionary<T, double>()), Enumerable.Empty<T>());
    }
}
