/// <summary>
 /// Obfuscates private keys by replacing them with a constant value.
 /// </summary>
 /// <param name="content">The request content to be obfuscated.</param>
 /// <param name="searchFormat">The search format string.</param>
 /// <param name="requestFieldMap">The request field map.</param>
 /// <returns><paramref name="content"/> with private keys obfuscated.</returns>
 private string ObfuscateRequest(string content, string searchFormat, MappedFieldList requestFieldMap)
 {
     return requestFieldMap.Where(f => f.MapType == MapType.PrivateValue)
                           .Select(field => string.Format(searchFormat, field.Target, field.Source))
                           .Aggregate(content, (current, pattern) => Regex.Replace(current, pattern, HttpResources.ObfuscatedFieldReplacement));
 }
        /// <summary>
        /// Populates <paramref name="target"/> with values from <paramref name="source"/> and <paramref name="response"/>
        /// as defined by <paramref name="fieldMap"/>. It also returns a new <see cref="Newtonsoft.Json.Linq.JObject"/> with mapped values.
        /// </summary>
        /// <param name="source">The response body from which to get values.</param>
        /// <param name="response">The response object from which to get values.</param>
        /// <param name="fieldMap">A definition of field mappings.</param>
        /// <param name="target">The target object to populate with mapped key/values.</param>
        /// <returns>A new <see cref="Newtonsoft.Json.Linq.JObject"/> with mapped values.</returns>
        public JObject MapObject(JObject source, HttpWebResponse response, MappedFieldList fieldMap, ApplicationData target)
        {
            JObject outObject = new JObject();
            IEnumerable<MappedField> validMappings = fieldMap.Where(m => !string.IsNullOrEmpty(m.Target) && !string.IsNullOrEmpty(m.Source));

            foreach (MappedField map in validMappings)
            {
                switch (map.MapType)
                {
                    case MapType.Content:
                        JToken token = source.SelectToken(map.Source);
                        if (token != null)
                        {
                            outObject.Add(map.Target, token);
                            if (target != null)
                            {
                                if (token.Type == JTokenType.Array && token.First().Type == JTokenType.Object)
                                {
                                    var repeater = new NestedDictionary[token.Children().Count()];
                                    var i = 0;
                                    foreach (var row in token)
                                    {
                                        repeater[i] = new NestedDictionary();

                                        foreach (JProperty fieldProp in row.OfType<JProperty>())
                                        {
                                            object targetValue = fieldProp.Value.Type == JTokenType.Array ? fieldProp.Value.Values<string>().ToArray() as object : fieldProp.Value.ToString();
                                            if (repeater[i].ContainsKey(fieldProp.Name))
                                            {
                                                repeater[i][fieldProp.Name] = targetValue;
                                            }
                                            else
                                            {
                                                repeater[i].Add(fieldProp.Name, targetValue);
                                            }
                                        }

                                        i++;
                                    }

                                    target.SetValue(map.Target, repeater);
                                }
                                else
                                {
                                    object targetValue = token.Type == JTokenType.Array ? token.Values<string>().ToArray() as object : token.Value<string>();
                                    target.SetValue(map.Target, targetValue, true);
                                }
                            }
                        }

                        break;

                    case MapType.Property:
                        this.MapPropertyField(response, map, target);
                        break;

                    default:
                        throw new InvalidOperationException(string.Format(ExceptionMessages.InvalidMapType, map.MapType));
                }
            }

            return outObject;
        }