// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

namespace System.Data.Entity.Core.Query.InternalTrees
{
    using System.Data.Entity.Core.Metadata.Edm;
    using System.Diagnostics;

    /// <summary>
    ///     A "Rel" property is best thought of as a collocated reference (aka foreign key).
    ///     Any entity may have zero or more rel-properties carried along with it (purely
    ///     as a means to optimize for common relationship traversal scenarios)
    ///     Although the definition is lax here, we only deal with RelProperties that
    ///     are one-ended (ie) the target multiplicity is at most One.
    ///     Consider for example, an Order entity with a (N:1) Order-Customer relationship. The Customer ref
    ///     will be treated as a rel property for the Order entity.
    ///     Similarly, the OrderLine entity may have an Order ref rel property (assuming that there was
    ///     a N:1 relationship between OrderLine and Order)
    /// </summary>
    internal sealed class RelProperty
    {
        #region private state

        private readonly RelationshipType m_relationshipType;
        private readonly RelationshipEndMember m_fromEnd;
        private readonly RelationshipEndMember m_toEnd;

        #endregion

        #region constructors

        internal RelProperty(RelationshipType relationshipType, RelationshipEndMember fromEnd, RelationshipEndMember toEnd)
        {
            m_relationshipType = relationshipType;
            m_fromEnd = fromEnd;
            m_toEnd = toEnd;
        }

        #endregion

        #region public APIs

        /// <summary>
        ///     The relationship
        /// </summary>
        public RelationshipType Relationship
        {
            get { return m_relationshipType; }
        }

        /// <summary>
        ///     The source end of the relationship
        /// </summary>
        public RelationshipEndMember FromEnd
        {
            get { return m_fromEnd; }
        }

        /// <summary>
        ///     the target end of the relationship
        /// </summary>
        public RelationshipEndMember ToEnd
        {
            get { return m_toEnd; }
        }

        /// <summary>
        ///     Our definition of equality
        /// </summary>
        /// <param name="obj"> </param>
        /// <returns> </returns>
        public override bool Equals(object obj)
        {
            var other = obj as RelProperty;
            return (other != null &&
                    Relationship.EdmEquals(other.Relationship) &&
                    FromEnd.EdmEquals(other.FromEnd) &&
                    ToEnd.EdmEquals(other.ToEnd));
        }

        /// <summary>
        ///     our hash code
        /// </summary>
        /// <returns> </returns>
        public override int GetHashCode()
        {
            return ToEnd.Identity.GetHashCode();
        }

        /// <summary>
        ///     String form
        /// </summary>
        /// <returns> </returns>
        [DebuggerNonUserCode]
        public override string ToString()
        {
            return m_relationshipType + ":" +
                   m_fromEnd + ":" +
                   m_toEnd;
        }

        #endregion
    }
}
