// For dynamic activity property, we needs to collect the source location of
        // its default value when the value is inlined.
        private KeyValuePair <string, SourceLocation> TransformDynamicActivityProperty(
            XamlReader reader,
            XamlObjectWriter objectWriter,
            SourceTextScanner sourceTextScanner)
        {
            // (Number of SM -Number of EM) since SM DAP.Name is read.
            // SO DAP                   ---nameReadingLevel=0
            //   SM NAME                ---nameReadingLevel=1
            //     SO String            ---nameReadingLevel=1
            //       SM Initialize      ---nameReadingLevel=2
            //         VA StringValue   ---nameReadingLevel=2
            //       EM                 ---nameReadingLevel=1
            //     SO                   ---nameReadingLevel=1
            //   EM                     ---nameReadingLevel=0
            // EO                       ---nameReadingLevel=0
            int nameReadingLevel = 0;

            IXamlLineInfo  lineInfo             = (IXamlLineInfo)reader;
            SourceLocation defaultValueLocation = null;
            string         propertyName         = null;

            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                case XamlNodeType.StartMember:
                    if (nameReadingLevel > 0 ||
                        reader.Member == this.dynamicActivityPropertyNameMember)
                    {
                        ++nameReadingLevel;
                    }
                    else if (reader.Member == this.dynamicActivityPropertyValueMember)
                    {
                        LineColumnPair startPoint = new LineColumnPair(lineInfo.LineNumber, lineInfo.LinePosition);
                        defaultValueLocation = GetInlineAttributeValueLocation(startPoint, sourceTextScanner);
                    }

                    break;

                case XamlNodeType.EndMember:
                    if (nameReadingLevel > 0)
                    {
                        --nameReadingLevel;
                    }

                    break;

                case XamlNodeType.Value:
                    if (nameReadingLevel > 0)
                    {
                        propertyName = reader.Value as string;
                    }

                    break;
                }

                objectWriter.WriteNode(reader);
            }

            if (propertyName != null && defaultValueLocation != null)
            {
                return(new KeyValuePair <string, SourceLocation>(propertyName, defaultValueLocation));
            }

            return(new KeyValuePair <string, SourceLocation>());
        }
        private object TransformAndGetPropertySourceLocation(XamlReader reader, SourceTextScanner sourceTextScanner, SourceLocationFoundCallback sourceLocationFoundCallback)
        {
            // <property name, value's start location>
            Dictionary <string, SourceLocation> propertyValueLocationMapping = new Dictionary <string, SourceLocation>();

            object deserializedObject = null;
            object earlyResult        = null;

            UsingXamlWriter(
                new XamlObjectWriter(reader.SchemaContext),
                delegate(XamlObjectWriter objectWriter)
            {
                if (this.XamlSchemaContext.HasLocalAssembly)
                {
                    this.CopyNamespacesAndAddLocalAssembly(reader, objectWriter);
                }

                if (!(reader is IXamlLineInfo))
                {
                    XamlServices.Transform(reader, objectWriter);
                    earlyResult = objectWriter.Result;
                    return;
                }

                XamlType dynamicActivityPropertyType = this.XamlSchemaContext.GetXamlType(typeof(DynamicActivityProperty));
                while (reader.Read())
                {
                    // read SubTree will moves the reader pointed to
                    // element after its EO. So, we need to use a while
                    while (!reader.IsEof && reader.NodeType == XamlNodeType.StartObject &&
                           dynamicActivityPropertyType == reader.Type)
                    {
                        KeyValuePair <string, SourceLocation> nameSourceLocation = this.TransformDynamicActivityProperty(reader.ReadSubtree(), objectWriter, sourceTextScanner);
                        if (nameSourceLocation.Key != null && nameSourceLocation.Value != null && !propertyValueLocationMapping.ContainsKey(nameSourceLocation.Key))
                        {
                            propertyValueLocationMapping.Add(nameSourceLocation.Key, nameSourceLocation.Value);
                        }
                    }

                    if (!reader.IsEof)
                    {
                        objectWriter.WriteNode(reader);
                    }
                }

                deserializedObject = objectWriter.Result;
            });

            if (earlyResult != null)
            {
                return(earlyResult);
            }

            ActivityBuilder activityBuilder = deserializedObject as ActivityBuilder;

            if (activityBuilder == null)
            {
                return(deserializedObject);
            }

            foreach (KeyValuePair <string, SourceLocation> propertyValueLocation in propertyValueLocationMapping)
            {
                string         propertyName     = propertyValueLocation.Key;
                SourceLocation propertyLocation = propertyValueLocation.Value;
                if (!activityBuilder.Properties.Contains(propertyName))
                {
                    SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property:{0}", propertyName));
                    continue;
                }

                DynamicActivityProperty property = activityBuilder.Properties[propertyName];

                if (property == null || property.Value == null)
                {
                    SharedFx.Assert(string.Format(CultureInfo.CurrentCulture, "no such property value:{0}", propertyName));
                    continue;
                }

                object expression = (property.Value is Argument) ? ((Argument)property.Value).Expression : null;
                if (expression != null)
                {
                    sourceLocationFoundCallback(expression, propertyLocation);
                }
                else
                {
                    sourceLocationFoundCallback(property.Value, propertyLocation);
                }
            }

            return(deserializedObject);
        }
        // there are two kind of attribute:
        // 1) in lined : argument="some value"
        // 2) <argument>
        //       <Expression ....../>
        //    </argument>
        // here, for (1) return the source location of "some value".
        // for (2) return null
        private static SourceLocation GetInlineAttributeValueLocation(LineColumnPair startPoint, SourceTextScanner sourceTextScanner)
        {
            const char SingleQuote             = '\'';
            const char DoubleQuote             = '"';
            const char StartAngleBracket       = '<';
            Tuple <LineColumnPair, char> start = sourceTextScanner.SearchCharAfter(startPoint, SingleQuote, DoubleQuote, StartAngleBracket);

            if (start == null)
            {
                return(null);
            }

            if (start.Item2 == StartAngleBracket)
            {
                return(null);
            }

            Tuple <LineColumnPair, char> end = sourceTextScanner.SearchCharAfter(start.Item1, start.Item2);

            if (end == null)
            {
                SharedFx.Assert("end of SourceLocation is not found");
                return(null);
            }

            return(new SourceLocation(null, start.Item1.LineNumber, start.Item1.ColumnNumber, end.Item1.LineNumber, end.Item1.ColumnNumber));
        }