context: #region License
  // Copyright (c) 2007 James Newton-King
  //
  // Permission is hereby granted, free of charge, to any person
  // obtaining a copy of this software and associated documentation
  // files (the "Software"), to deal in the Software without
  // restriction, including without limitation the rights to use,
  // copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the
  // Software is furnished to do so, subject to the following
  // conditions:
  //
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  // OTHER DEALINGS IN THE SOFTWARE.
  #endregion
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.ComponentModel;
  #if !(NET35 || NET20 || WINDOWS_PHONE)
  using System.Dynamic;
  #endif
  using System.Globalization;
  using System.Linq;
  using System.Reflection;
  using System.Runtime.Serialization.Formatters;
  using Newtonsoft.Json.Linq;
  using Newtonsoft.Json.Utilities;
  using System.Runtime.Serialization;
  using System.Security;
  
  namespace Newtonsoft.Json.Serialization
  {
    internal class JsonSerializerInternalWriter : JsonSerializerInternalBase
    {
      private JsonSerializerProxy _internalSerializer;
      private List<object> _serializeStack;
  
      private List<object> SerializeStack
      {
        get
        {
          if (_serializeStack == null)
            _serializeStack = new List<object>();
  
          return _serializeStack;
        }
      }
  
      public JsonSerializerInternalWriter(JsonSerializer serializer)
        : base(serializer)
      {
      }
  
      public void Serialize(JsonWriter jsonWriter, object value)
      {
        if (jsonWriter == null)
          throw new ArgumentNullException("jsonWriter");
  
        SerializeValue(jsonWriter, value, GetContractSafe(value), null, null);
      }
  
      private JsonSerializerProxy GetInternalSerializer()
      {
        if (_internalSerializer == null)
          _internalSerializer = new JsonSerializerProxy(this);
  
        return _internalSerializer;
      }
  
      private JsonContract GetContractSafe(object value)
      {
        if (value == null)
          return null;
  
        return Serializer.ContractResolver.ResolveContract(value.GetType());
      }
  
      private void SerializePrimitive(JsonWriter writer, object value, JsonPrimitiveContract contract, JsonProperty member, JsonContract collectionValueContract)
      {
        if (contract.UnderlyingType == typeof (byte[]))
        {
          bool includeTypeDetails = ShouldWriteType(TypeNameHandling.Objects, contract, member, collectionValueContract);
          if (includeTypeDetails)
          {
            writer.WriteStartObject();
            WriteTypeProperty(writer, contract.CreatedType);
            writer.WritePropertyName(JsonTypeReflector.ValuePropertyName);
            writer.WriteValue(value);
            writer.WriteEndObject();
            return;
          }
        }
  
        writer.WriteValue(value);
      }
  
      private void SerializeValue(JsonWriter writer, object value, JsonContract valueContract, JsonProperty member, JsonContract collectionValueContract)
      {
        JsonConverter converter = (member != null) ? member.Converter : null;
  
        if (value == null)
        {
          writer.WriteNull();
          return;
        }
  
        if ((converter != null
            || ((converter = valueContract.Converter) != null)
            || ((converter = Serializer.GetMatchingConverter(valueContract.UnderlyingType)) != null)
            || ((converter = valueContract.InternalConverter) != null))
          && converter.CanWrite)
        {
          SerializeConvertable(writer, converter, value, valueContract);
        }
        else if (valueContract is JsonPrimitiveContract)
        {
          SerializePrimitive(writer, value, (JsonPrimitiveContract)valueContract, member, collectionValueContract);
        }
        else if (valueContract is JsonStringContract)
        {
          SerializeString(writer, value, (JsonStringContract)valueContract);
        }
        else if (valueContract is JsonObjectContract)
        {
          SerializeObject(writer, value, (JsonObjectContract)valueContract, member, collectionValueContract);
        }
        else if (valueContract is JsonDictionaryContract)
        {
          JsonDictionaryContract dictionaryContract = (JsonDictionaryContract)valueContract;
          SerializeDictionary(writer, dictionaryContract.CreateWrapper(value), dictionaryContract, member, collectionValueContract);
        }
        else if (valueContract is JsonArrayContract)
        {
          JsonArrayContract arrayContract = (JsonArrayContract)valueContract;
          SerializeList(writer, arrayContract.CreateWrapper(value), arrayContract, member, collectionValueContract);
        }
        else if (valueContract is JsonLinqContract)
        {
          ((JToken)value).WriteTo(writer, (Serializer.Converters != null) ? Serializer.Converters.ToArray() : null);
        }
  #if !SILVERLIGHT && !PocketPC
        else if (valueContract is JsonISerializableContract)
        {
          SerializeISerializable(writer, (ISerializable)value, (JsonISerializableContract)valueContract, member, collectionValueContract);
        }
  #endif
  #if !(NET35 || NET20 || WINDOWS_PHONE)
        else if (valueContract is JsonDynamicContract)
        {
          SerializeDynamic(writer, (IDynamicMetaObjectProvider)value, (JsonDynamicContract)valueContract);
        }
  #endif
      }
  
      private bool ShouldWriteReference(object value, JsonProperty property, JsonContract contract)
      {
        if (value == null)
          return false;
        if (contract is JsonPrimitiveContract)
          return false;
  
        bool? isReference = null;
  
        // value could be coming from a dictionary or array and not have a property
        if (property != null)
          isReference = property.IsReference;
  
        if (isReference == null)
          isReference = contract.IsReference;
  
        if (isReference == null)
        {
          if (contract is JsonArrayContract)
            isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Arrays);
          else
            isReference = HasFlag(Serializer.PreserveReferencesHandling, PreserveReferencesHandling.Objects);
        }
  
        if (!isReference.Value)
          return false;
  
        return Serializer.ReferenceResolver.IsReferenced(this, value);
      }
  
      private void WriteMemberInfoProperty(JsonWriter writer, object memberValue, JsonProperty property, JsonContract contract)
      {
        string propertyName = property.PropertyName;
        object defaultValue = property.DefaultValue;
  
        if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore &&
            memberValue == null)
          return;
  
        if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
          && MiscellaneousUtils.ValueEquals(memberValue, defaultValue))
          return;
  
        if (ShouldWriteReference(memberValue, property, contract))
        {
          writer.WritePropertyName(propertyName);
          WriteReference(writer, memberValue);
          return;
        }
  
        if (!CheckForCircularReference(memberValue, property.ReferenceLoopHandling, contract))
          return;
  
        if (memberValue == null && property.Required == Required.Always)
          throw new JsonSerializationException("Cannot write a null value for property '{0}'. Property requires a value.".FormatWith(CultureInfo.InvariantCulture, property.PropertyName));
  
        writer.WritePropertyName(propertyName);
        SerializeValue(writer, memberValue, contract, property, null);
      }
  
      private bool CheckForCircularReference(object value, ReferenceLoopHandling? referenceLoopHandling, JsonContract contract)
      {
        if (value == null || contract is JsonPrimitiveContract)
          return true;
  
        if (SerializeStack.IndexOf(value) != -1)
        {
          switch (referenceLoopHandling.GetValueOrDefault(Serializer.ReferenceLoopHandling))
          {
            case ReferenceLoopHandling.Error:
              throw new JsonSerializationException("Self referencing loop detected for type '{0}'.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
            case ReferenceLoopHandling.Ignore:
              return false;
            case ReferenceLoopHandling.Serialize:
              return true;
            default:
              throw new InvalidOperationException("Unexpected ReferenceLoopHandling value: '{0}'".FormatWith(CultureInfo.InvariantCulture, Serializer.ReferenceLoopHandling));
          }
        }
  
        return true;
      }
  
      private void WriteReference(JsonWriter writer, object value)
      {
        writer.WriteStartObject();
        writer.WritePropertyName(JsonTypeReflector.RefPropertyName);
        writer.WriteValue(Serializer.ReferenceResolver.GetReference(this, value));
        writer.WriteEndObject();
      }
  
      internal static bool TryConvertToString(object value, Type type, out string s)
      {
  #if !PocketPC
        TypeConverter converter = ConvertUtils.GetConverter(type);
  
        // use the objectType's TypeConverter if it has one and can convert to a string
  
gt:       if (converter != null