private static ObjectDiffPatchResult Diff(JObject source, JObject target)
        {
            ObjectDiffPatchResult result = new ObjectDiffPatchResult();

            // check for null values
            if (source == null && target == null)
            {
                return(result);
            }
            else if (source == null || target == null)
            {
                result.OldValues = source;
                result.NewValues = target;
                return(result);
            }

            // compare internal fields
            JArray removedNew = new JArray();
            JArray removedOld = new JArray();
            JToken token;

            // start by iterating in source fields
            foreach (var i in source)
            {
                // check if field exists
                if (!target.TryGetValue(i.Key, out token))
                {
                    AddOldValuesToken(result, i.Value, i.Key);
                    removedNew.Add(i.Key);
                }
                // compare field values
                else
                {
                    DiffField(i.Key, i.Value, token, result);
                }
            }
            // then iterate in target fields that are not present in source
            foreach (var i in target)
            {
                // ignore alredy compared values
                if (source.TryGetValue(i.Key, out token))
                {
                    continue;
                }
                // add missing tokens
                removedOld.Add(i.Key);
                AddNewValuesToken(result, i.Value, i.Key);
            }

            if (removedOld.Count > 0)
            {
                AddOldValuesToken(result, removedOld, PREFIX_REMOVED_FIELDS);
            }
            if (removedNew.Count > 0)
            {
                AddNewValuesToken(result, removedNew, PREFIX_REMOVED_FIELDS);
            }

            return(result);
        }
 private static void AddOldValuesToken(ObjectDiffPatchResult item, JToken oldToken, string fieldName)
 {
     if (item.OldValues == null)
     {
         item.OldValues = new Newtonsoft.Json.Linq.JObject();
     }
     item.OldValues[fieldName] = oldToken;
 }
 private static void AddToken(ObjectDiffPatchResult item, string fieldName, ObjectDiffPatchResult diff)
 {
     AddToken(item, fieldName, diff.OldValues, diff.NewValues);
 }
        private static void AddToken(ObjectDiffPatchResult item, string fieldName, JToken oldToken, JToken newToken)
        {
            AddOldValuesToken(item, oldToken, fieldName);

            AddNewValuesToken(item, newToken, fieldName);
        }
        private static ObjectDiffPatchResult DiffField(string fieldName, JToken source, JToken target, ObjectDiffPatchResult result = null)
        {
            if (result == null)
            {
                result = new ObjectDiffPatchResult();
            }
            if (source == null)
            {
                if (target != null)
                {
                    AddToken(result, fieldName, source, target);
                }
            }
            else if (target == null)
            {
                AddToken(result, fieldName, source, target);
            }
            else if (source.Type == Newtonsoft.Json.Linq.JTokenType.Object)
            {
                var v = target as Newtonsoft.Json.Linq.JObject;
                var r = Diff(source as Newtonsoft.Json.Linq.JObject, v);
                if (!r.AreEqual)
                {
                    AddToken(result, fieldName, r);
                }
            }
            else if (source.Type == Newtonsoft.Json.Linq.JTokenType.Array)
            {
                var aS = (source as Newtonsoft.Json.Linq.JArray);
                var aT = (target as Newtonsoft.Json.Linq.JArray);

                if ((aS.Count == 0 || aT.Count == 0) && (aS.Count != aT.Count))
                {
                    AddToken(result, fieldName, source, target);
                }
                else
                {
                    ObjectDiffPatchResult arrayDiff = new ObjectDiffPatchResult();
                    int minCount = Math.Min(aS.Count, aT.Count);
                    for (int i = 0; i < Math.Max(aS.Count, aT.Count); i++)
                    {
                        if (i < minCount)
                        {
                            DiffField(i.ToString(), aS[i], aT[i], arrayDiff);
                        }
                        else if (i >= aS.Count)
                        {
                            AddNewValuesToken(arrayDiff, aT[i], i.ToString());
                        }
                        else
                        {
                            AddOldValuesToken(arrayDiff, aS[i], i.ToString());
                        }
                    }

                    if (!arrayDiff.AreEqual)
                    {
                        if (aS.Count != aT.Count)
                        {
                            AddToken(arrayDiff, PREFIX_ARRAY_SIZE, aS.Count, aT.Count);
                        }
                        AddToken(result, fieldName, arrayDiff);
                    }
                }
            }
            else
            {
                if (!Newtonsoft.Json.Linq.JObject.DeepEquals(source, target))
                {
                    AddToken(result, fieldName, source, target);
                }
            }
            return(result);
        }