/// <summary>
        /// Gets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
        /// The exact property name will be searched for first and if no matching property is found then
        /// the <see cref="StringComparison"/> will be used to match a property.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="comparison">One of the enumeration values that specifies how the strings will be compared.</param>
        /// <returns>The <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.</returns>
        public JToken GetValue(string propertyName, StringComparison comparison)
        {
            if (propertyName == null)
            {
                return(null);
            }

            // attempt to get value via dictionary first for performance
            BacktraceJProperty property = Property(propertyName);

            if (property != null)
            {
                return(property.Value);
            }

            // test above already uses this comparison so no need to repeat
            if (comparison != StringComparison.Ordinal)
            {
                foreach (BacktraceJProperty p in _properties)
                {
                    if (string.Equals(p.Name, propertyName, comparison))
                    {
                        return(p.Value);
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Loads an <see cref="BacktraceJProperty"/> from a <see cref="JsonReader"/>.
        /// </summary>
        /// <param name="reader">A <see cref="JsonReader"/> that will be read for the content of the <see cref="BacktraceJProperty"/>.</param>
        /// <param name="settings">The <see cref="JsonLoadSettings"/> used to load the JSON.
        /// If this is null, default load settings will be used.</param>
        /// <returns>A <see cref="BacktraceJProperty"/> that contains the JSON that was read from the specified <see cref="JsonReader"/>.</returns>
        public new static BacktraceJProperty Load(JsonReader reader, JsonLoadSettings settings)
        {
            if (reader.TokenType == JsonToken.None)
            {
                if (!reader.Read())
                {
                    throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader.");
                }
            }

            reader.MoveToContent();

            if (reader.TokenType != JsonToken.PropertyName)
            {
                throw JsonReaderException.Create(reader, "Error reading JProperty from JsonReader. Current JsonReader item is not a property: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType));
            }

            BacktraceJProperty p = new BacktraceJProperty((string)reader.Value);

            p.SetLineInfo(reader as IJsonLineInfo, settings);

            p.ReadTokenFrom(reader, settings);

            return(p);
        }
        /// <summary>
        /// Gets or sets the <see cref="Newtonsoft.Json.Linq.JToken"/> with the specified property name.
        /// </summary>
        /// <value></value>
        public JToken this[string propertyName]
        {
            get
            {
                ValidationUtils.ArgumentNotNull(propertyName, "propertyName");

                BacktraceJProperty property = Property(propertyName);

                return((property != null) ? property.Value : null);
            }
            set
            {
                BacktraceJProperty property = Property(propertyName);
                if (property != null)
                {
                    property.Value = value;
                }
                else
                {
#if !(NET20 || PORTABLE40 || PORTABLE)
                    OnPropertyChanging(propertyName);
#endif
                    Add(new BacktraceJProperty(propertyName, value));
                    OnPropertyChanged(propertyName);
                }
            }
        }
        internal override void ValidateToken(JToken o, JToken existing)
        {
            ValidationUtils.ArgumentNotNull(o, "o");

            if (o.Type != JTokenType.Property)
            {
                throw new ArgumentException("Can not add {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, o.GetType(), GetType()));
            }

            BacktraceJProperty newProperty = (BacktraceJProperty)o;

            if (existing != null)
            {
                BacktraceJProperty existingProperty = (BacktraceJProperty)existing;

                if (newProperty.Name == existingProperty.Name)
                {
                    return;
                }
            }

            if (_properties.TryGetValue(newProperty.Name, out existing))
            {
                throw new ArgumentException("Can not add property {0} to {1}. Property with the same name already exists on object.".FormatWith(CultureInfo.InvariantCulture, newProperty.Name, GetType()));
            }
        }
        public bool Compare(JPropertyKeyedCollection other)
        {
            if (this == other)
            {
                return(true);
            }

            // dictionaries in JavaScript aren't ordered
            // ignore order when comparing properties
            Dictionary <string, JToken> d1 = _dictionary;
            Dictionary <string, JToken> d2 = other._dictionary;

            if (d1 == null && d2 == null)
            {
                return(true);
            }

            if (d1 == null)
            {
                return(d2.Count == 0);
            }

            if (d2 == null)
            {
                return(d1.Count == 0);
            }

            if (d1.Count != d2.Count)
            {
                return(false);
            }

            foreach (KeyValuePair <string, JToken> keyAndProperty in d1)
            {
                JToken secondValue;
                if (!d2.TryGetValue(keyAndProperty.Key, out secondValue))
                {
                    return(false);
                }

                BacktraceJProperty p1 = (BacktraceJProperty)keyAndProperty.Value;
                BacktraceJProperty p2 = (BacktraceJProperty)secondValue;

                if (p1.Value == null)
                {
                    return(p2.Value == null);
                }

                if (!p1.Value.DeepEquals(p2.Value))
                {
                    return(false);
                }
            }

            return(true);
        }
        bool ICollection <KeyValuePair <string, JToken> > .Contains(KeyValuePair <string, JToken> item)
        {
            BacktraceJProperty property = Property(item.Key);

            if (property == null)
            {
                return(false);
            }

            return(property.Value == item.Value);
        }
        /// <summary>
        /// Removes the property with the specified name.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns>true if item was successfully removed; otherwise, false.</returns>
        public bool Remove(string propertyName)
        {
            BacktraceJProperty property = Property(propertyName);

            if (property == null)
            {
                return(false);
            }

            property.Remove();
            return(true);
        }
        /// <summary>
        /// Tries the get value.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        /// <returns>true if a value was successfully retrieved; otherwise, false.</returns>
        public bool TryGetValue(string propertyName, out JToken value)
        {
            BacktraceJProperty property = Property(propertyName);

            if (property == null)
            {
                value = null;
                return(false);
            }

            value = property.Value;
            return(true);
        }
        internal override void MergeItem(object content, JsonMergeSettings settings)
        {
            BacktraceJProperty p = content as BacktraceJProperty;

            if (p == null)
            {
                return;
            }

            if (p.Value != null && p.Value.Type != JTokenType.Null)
            {
                Value = p.Value;
            }
        }
        internal void InternalPropertyChanged(BacktraceJProperty childProperty)
        {
            OnPropertyChanged(childProperty.Name);
#if !(DOTNET || PORTABLE40 || PORTABLE || NET_STANDARD_2_0)
            if (_listChanged != null)
            {
                OnListChanged(new ListChangedEventArgs(ListChangedType.ItemChanged, IndexOfItem(childProperty)));
            }
#endif
#if !UNITY_WINRT || UNITY_EDITOR || (UNITY_WP8 && !UNITY_WP_8_1)
            if (_collectionChanged != null)
            {
                OnCollectionChanged(new System.ComponentModel.NotifyCollectionChangedEventArgs(System.ComponentModel.NotifyCollectionChangedAction.Replace, childProperty, childProperty, IndexOfItem(childProperty)));
            }
#endif
        }
        internal override void MergeItem(object content, JsonMergeSettings settings)
        {
            BacktraceJObject o = content as BacktraceJObject;

            if (o == null)
            {
                return;
            }

            foreach (KeyValuePair <string, JToken> contentItem in o)
            {
                BacktraceJProperty existingProperty = Property(contentItem.Key);

                if (existingProperty == null)
                {
                    Add(contentItem.Key, contentItem.Value);
                }
                else if (contentItem.Value != null)
                {
                    BacktraceJContainer existingContainer = existingProperty.Value as BacktraceJContainer;
                    if (existingContainer == null)
                    {
                        if (contentItem.Value.Type != JTokenType.Null || (settings != null && settings.MergeNullValueHandling == MergeNullValueHandling.Merge))
                        {
                            existingProperty.Value = contentItem.Value;
                        }
                    }
                    else if (existingContainer.Type != contentItem.Value.Type)
                    {
                        existingProperty.Value = contentItem.Value;
                    }
                    else
                    {
                        existingContainer.Merge(contentItem.Value, settings);
                    }
                }
            }
        }
        internal override bool DeepEquals(JToken node)
        {
            BacktraceJProperty t = node as BacktraceJProperty;

            return(t != null && _name == t.Name && ContentsEqual(t));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="BacktraceJProperty"/> class from another <see cref="BacktraceJProperty"/> object.
 /// </summary>
 /// <param name="other">A <see cref="BacktraceJProperty"/> object to copy from.</param>
 public BacktraceJProperty(BacktraceJProperty other)
     : base(other)
 {
     _name = other.Name;
 }
        internal void ReadContentFrom(JsonReader r, JsonLoadSettings settings)
        {
            ValidationUtils.ArgumentNotNull(r, "r");
            IJsonLineInfo lineInfo = r as IJsonLineInfo;

            BacktraceJContainer parent = this;

            do
            {
                if (parent is BacktraceJProperty && (parent as BacktraceJProperty).Value != null)
                {
                    if (parent == this)
                    {
                        return;
                    }

                    parent = parent.Parent;
                }

                switch (r.TokenType)
                {
                case JsonToken.None:
                    // new reader. move to actual content
                    break;

                case JsonToken.StartArray:
                    JArray a = new JArray();
                    a.SetLineInfo(lineInfo, settings);
                    parent.Add(a);
                    parent = a;
                    break;

                case JsonToken.EndArray:
                    if (parent == this)
                    {
                        return;
                    }

                    parent = parent.Parent;
                    break;

                case JsonToken.StartObject:
                    BacktraceJObject o = new BacktraceJObject();
                    o.SetLineInfo(lineInfo, settings);
                    parent.Add(o);
                    parent = o;
                    break;

                case JsonToken.EndObject:
                    if (parent == this)
                    {
                        return;
                    }

                    parent = parent.Parent;
                    break;

                case JsonToken.StartConstructor:
                    JConstructor constructor = new JConstructor(r.Value.ToString());
                    constructor.SetLineInfo(lineInfo, settings);
                    parent.Add(constructor);
                    parent = constructor;
                    break;

                case JsonToken.EndConstructor:
                    if (parent == this)
                    {
                        return;
                    }

                    parent = parent.Parent;
                    break;

                case JsonToken.String:
                case JsonToken.Integer:
                case JsonToken.Float:
                case JsonToken.Date:
                case JsonToken.Boolean:
                case JsonToken.Bytes:
                    JValue v = new JValue(r.Value);
                    v.SetLineInfo(lineInfo, settings);
                    parent.Add(v);
                    break;

                case JsonToken.Comment:
                    if (settings != null && settings.CommentHandling == CommentHandling.Load)
                    {
                        v = JValue.CreateComment(r.Value.ToString());
                        v.SetLineInfo(lineInfo, settings);
                        parent.Add(v);
                    }
                    break;

                case JsonToken.Null:
                    v = JValue.CreateNull();
                    v.SetLineInfo(lineInfo, settings);
                    parent.Add(v);
                    break;

                case JsonToken.Undefined:
                    v = JValue.CreateUndefined();
                    v.SetLineInfo(lineInfo, settings);
                    parent.Add(v);
                    break;

                case JsonToken.PropertyName:
                    string             propertyName = r.Value.ToString();
                    BacktraceJProperty property     = new BacktraceJProperty(propertyName);
                    property.SetLineInfo(lineInfo, settings);
                    BacktraceJObject parentObject = (BacktraceJObject)parent;
                    // handle multiple properties with the same name in JSON
                    BacktraceJProperty existingPropertyWithName = parentObject.Property(propertyName);
                    if (existingPropertyWithName == null)
                    {
                        parent.Add(property);
                    }
                    else
                    {
                        existingPropertyWithName.Replace(property);
                    }
                    parent = property;
                    break;

                default:
                    throw new InvalidOperationException("The JsonReader should not be on a token of type {0}.".FormatWith(CultureInfo.InvariantCulture, r.TokenType));
                }
            } while (r.Read());
        }
        internal void InternalPropertyChanging(BacktraceJProperty childProperty)
        {
#if !(NET20 || PORTABLE40 || PORTABLE)
            OnPropertyChanging(childProperty.Name);
#endif
        }