using System;

/// <summary>装箱类。</summary>
public class Class<T> : IComparable, IComparable<T>, IComparable<Class<T>>
{

    private bool _hashcode = false;
    private bool _equals = false;

    /// <summary>装箱对象。</summary>
    public virtual T Value { get; set; }

    /// <summary></summary>
    public virtual bool IsNull
    {
        get { return Value == null; }
    }

    /// <summary></summary>
    public virtual bool HasValue
    {
        get { return Value != null; }
    }

    /// <summary>创建默认值。</summary>
    public Class(T value = default, bool tryEquals = true, bool tryHashCode = true)
    {
        Value = value;
        _hashcode = tryHashCode;
        _equals = tryEquals;
    }

    /// <summary></summary>
    public override int GetHashCode()
    {
        if (_hashcode && Value != null)
        {
            return Value.GetHashCode();
        }
        return base.GetHashCode();
    }

    /// <summary></summary>
    public override bool Equals(object obj)
    {
        if (_equals)
        {
            var right = obj as Class<T>;
            if (right == null) return false;

            if (Value == null && right.Value == null) return true;
            if (Value == null && right.Value != null) return false;
            if (Value != null && right.Value == null) return false;
            return Value.Equals(right.Value);
        }
        return base.Equals(obj);
    }

    /// <summary></summary>
    public override string ToString()
    {
        if (Value == null) return "";
        return Value.ToString();
    }

    /// <summary></summary>
    /// <exception cref="MissingMemberException"></exception>
    /// <exception cref="NotSupportedException"></exception>
    public virtual int CompareTo(object obj)
    {
        if (obj != null && obj is T) return CompareTo((T)obj);
        if (obj != null && obj is Class<T>) return CompareTo(obj as Class<T>);

        if (Value == null) throw new MissingMemberException(typeof(T).FullName, nameof(Value));
        if (!(Value is IComparable)) throw new NotSupportedException();
        return ((IComparable)Value).CompareTo(obj);
    }

    /// <summary></summary>
    /// <exception cref="MissingMemberException"></exception>
    /// <exception cref="NotSupportedException"></exception>
    public virtual int CompareTo(T other)
    {
        if (Value == null) throw new MissingMemberException(typeof(T).FullName, nameof(Value));
        if (!(Value is IComparable)) throw new NotSupportedException();
        return ((IComparable<T>)Value).CompareTo(other);
    }

    /// <summary></summary>
    /// <exception cref="MissingMemberException"></exception>
    /// <exception cref="NotSupportedException"></exception>
    public virtual int CompareTo(Class<T> other)
    {
        if (Value == null) throw new MissingMemberException(typeof(T).FullName, nameof(Value));
        if (other == null || !other.HasValue) return 1;

        if (Value is IComparable) return ((IComparable)Value).CompareTo(other.Value);
        if (Value is IComparable<T>) return ((IComparable<T>)Value).CompareTo(other.Value);

        throw new NotSupportedException();
    }

}