namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter10.Listing10_06
{
    public sealed class ProductSerialNumber
    {
        public ProductSerialNumber(
            string productSeries, int model, long id)
        {
            ProductSeries = productSeries;
            Model = model;
            Id = id;
        }

        public string ProductSeries { get; }
        public int Model { get; }
        public long Id { get; }


        public override int GetHashCode()
        {
            int hashCode = ProductSeries.GetHashCode();
            hashCode ^= Model;  // Xor
            hashCode ^= Id.GetHashCode();  // Xor
            return hashCode;
        }

        public override bool Equals(object obj)
        {
            if(obj == null)
            {
                return false;
            }
            if(ReferenceEquals(this, obj))
            {
                return true;
            }
            if(this.GetType() != obj.GetType())
            {
                return false;
            }
            return Equals((ProductSerialNumber)obj);
        }

        public bool Equals(ProductSerialNumber obj)
        {
            // KROK 3: Sprawdzanie, czy skróty są identyczne
            // if (this.GetHashCode() != obj.GetHashCode())
            // {
            //    return false;
            // } 

            // KROK 4: Sprawdzanie base.Equals, jeśli base przesłania Equals()
            // System.Diagnostics.Debug.Assert(
            //     base.GetType() != typeof(object));
            // if ( base.Equals(obj) )
            // {
            //    return false;
            // } 

            // KROK 1: Sprawdzanie wartości null
            return ((obj != null)
                // KROK 5: Porównanie na podstawie wartości pól.
                && (ProductSeries == obj.ProductSeries) &&
                (Model == obj.Model) &&
                (Id == obj.Id));
        }

        public static bool operator ==(
            ProductSerialNumber leftHandSide,
            ProductSerialNumber rightHandSide)
        {

            // Sprawdzanie, czy operand leftHandSide jest równy null. 
            // Użycie operatora == spowodowałoby rekurencję.
            if (ReferenceEquals(leftHandSide, null))
            {
                // Zwraca true, jeśli operand rightHandSide też jest równy null.
                // W przeciwnym razie zwracana wartość to false.
                return ReferenceEquals(rightHandSide, null);
            }

            return (leftHandSide.Equals(rightHandSide));
        }

        public static bool operator !=(
            ProductSerialNumber leftHandSide,
            ProductSerialNumber rightHandSide)
        {
            return !(leftHandSide == rightHandSide);
        }
    }

}
