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

namespace Microsoft.Data.Entity.Design.Model.Designer
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Xml.Linq;
    using Microsoft.Data.Entity.Design.Model.Commands;

    internal class ConnectorPoint : EFElement
    {
        internal static readonly string ElementName = "ConnectorPoint";

        internal static readonly string AttributePointX = "PointX";
        internal static readonly string AttributePointY = "PointY";

        private DefaultableValue<double> _pointXAttr;
        private DefaultableValue<double> _pointYAttr;

        internal ConnectorPoint(EFElement parent, XElement element)
            : base(parent, element)
        {
        }

        internal DefaultableValue<double> PointX
        {
            get
            {
                if (_pointXAttr == null)
                {
                    _pointXAttr = new PointXDefaultableValue(this);
                }
                return _pointXAttr;
            }
        }

        internal DefaultableValue<double> PointY
        {
            get
            {
                if (_pointYAttr == null)
                {
                    _pointYAttr = new PointYDefaultableValue(this);
                }
                return _pointYAttr;
            }
        }

        #region overrides

        // we unfortunately get a warning from the compiler when we use the "base" keyword in "iterator" types generated by using the
        // "yield return" keyword.  By adding this method, I was able to get around this.  Unfortunately, I wasn't able to figure out
        // a way to implement this once and have derived classes share the implementation (since the "base" keyword is resolved at 
        // compile-time and not at runtime.
        private IEnumerable<EFObject> BaseChildren
        {
            get { return base.Children; }
        }

        internal override IEnumerable<EFObject> Children
        {
            get
            {
                foreach (var efobj in BaseChildren)
                {
                    yield return efobj;
                }
                yield return PointX;
                yield return PointY;
            }
        }

#if DEBUG
        internal override ICollection<string> MyAttributeNames()
        {
            var s = base.MyAttributeNames();
            s.Add(AttributePointX);
            s.Add(AttributePointY);
            return s;
        }
#endif

        protected override void PreParse()
        {
            Debug.Assert(State != EFElementState.Parsed, "this object should not already be in the parsed state");

            ClearEFObject(_pointXAttr);
            _pointXAttr = null;
            ClearEFObject(_pointYAttr);
            _pointYAttr = null;
            base.PreParse();
        }

        /// <summary>
        ///     We override this so that we can send 'false' to the second argument of the command c'tor so
        ///     that we don't rebind all of the bindings in the artifact everytime we move a shape
        /// </summary>
        /// <returns></returns>
        internal override DeleteEFElementCommand GetDeleteCommand()
        {
            var cmd = new DeleteEFElementCommand(this, false /* = rebindAllBindings */);
            if (cmd == null)
            {
                // shouldn't happen, just to be safe
                throw new InvalidOperationException();
            }
            return cmd;
        }

        #endregion

        internal class PointXDefaultableValue : DefaultableValue<double>
        {
            internal PointXDefaultableValue(EFElement parent)
                : base(parent, AttributePointX)
            {
            }

            internal override string AttributeName
            {
                get { return AttributePointX; }
            }

            public override double DefaultValue
            {
                get { return 0.0; }
            }
        }

        internal class PointYDefaultableValue : DefaultableValue<double>
        {
            internal PointYDefaultableValue(EFElement parent)
                : base(parent, AttributePointY)
            {
            }

            internal override string AttributeName
            {
                get { return AttributePointY; }
            }

            public override double DefaultValue
            {
                get { return 0.0; }
            }
        }
    }
}
