﻿using NullGuard;
using System;

namespace FunctionalSharp.OptionTypes
{
    /// <summary>
    /// A representation for an IOption without a value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    [Serializable]
    public class None<T> : IOption<T>
    {
        /// <summary>
        /// Creates a new None of T. The type T must be nullable, if not an exception will be thrown
        /// </summary>
        public None()
        {

        }

        /// <summary>
        /// Does nothing since None doesnt hold a value.
        /// </summary>
        /// <param name="withValue"></param>
        public void IfNotNullDo(Action<T> withValue)
        {

        }

        /// <summary>
        /// Executes the action <paramref name="withoutValue"/>.
        /// </summary>
        /// <param name="withValue"></param>
        /// <param name="withoutValue"></param>
        public void Match(Action<T> withValue, Action withoutValue)
        {
            withoutValue();
        }

        /// <summary>
        /// returns the value in the parameter withoutValue.
        /// </summary>
        /// <typeparam name="TResult">The result type.</typeparam>
        /// <param name="withValue">Not executed.</param>
        /// <param name="withoutValue">The value returned.</param>
        /// <returns></returns>
        public TResult Match<TResult>(Func<T, TResult> withValue, TResult withoutValue)
        {
            return withoutValue;
        }

        /// <summary>
        /// returns the value generated by running <paramref name="withoutValue"/>.
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="withValue"></param>
        /// <param name="withoutValue"></param>
        /// <returns></returns>
        public TResult Match<TResult>(Func<T, TResult> withValue, Func<TResult> withoutValue)
        {
            return withoutValue();
        }

        /// <summary>
        /// Returns null.
        /// </summary>
        /// <returns></returns>
        [return: AllowNull]
        public T ToNullable()
        {
            return default(T);
        }

        /// <summary>
        /// returns a string "null value for" with the name of the type.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "null value for " + typeof(T).Name;
        }
    }
}
