#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.Generic;
using System.Globalization;
using System.Runtime.Serialization.Formatters;
using Newtonsoft.Json.Serialization;
using System.Runtime.Serialization;

namespace Newtonsoft.Json
{
  /// <summary>
  /// Specifies the settings on a <see cref="JsonSerializer"/> object.
  /// </summary>
  public class JsonSerializerSettings
  {
    internal const ReferenceLoopHandling DefaultReferenceLoopHandling = ReferenceLoopHandling.Error;
    internal const MissingMemberHandling DefaultMissingMemberHandling = MissingMemberHandling.Ignore;
    internal const NullValueHandling DefaultNullValueHandling = NullValueHandling.Include;
    internal const DefaultValueHandling DefaultDefaultValueHandling = DefaultValueHandling.Include;
    internal const ObjectCreationHandling DefaultObjectCreationHandling = ObjectCreationHandling.Auto;
    internal const PreserveReferencesHandling DefaultPreserveReferencesHandling = PreserveReferencesHandling.None;
    internal const ConstructorHandling DefaultConstructorHandling = ConstructorHandling.Default;
    internal const TypeNameHandling DefaultTypeNameHandling = TypeNameHandling.None;
    internal const FormatterAssemblyStyle DefaultTypeNameAssemblyFormat = FormatterAssemblyStyle.Simple;
    internal static readonly StreamingContext DefaultContext;

    internal const Formatting DefaultFormatting = Formatting.None;
    internal const DateFormatHandling DefaultDateFormatHandling = DateFormatHandling.IsoDateFormat;
    internal const DateTimeZoneHandling DefaultDateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
    internal const DateParseHandling DefaultDateParseHandling = DateParseHandling.DateTime;
    internal static readonly CultureInfo DefaultCulture;
    internal const bool DefaultCheckAdditionalContent = false;

    internal Formatting? _formatting;
    internal DateFormatHandling? _dateFormatHandling;
    internal DateTimeZoneHandling? _dateTimeZoneHandling;
    internal DateParseHandling? _dateParseHandling;
    internal CultureInfo _culture;
    internal bool? _checkAdditionalContent;
    internal int? _maxDepth;
    internal bool _maxDepthSet;

    /// <summary>
    /// Gets or sets how reference loops (e.g. a class referencing itself) is handled.
    /// </summary>
    /// <value>Reference loop handling.</value>
    public ReferenceLoopHandling ReferenceLoopHandling { get; set; }

    /// <summary>
    /// Gets or sets how missing members (e.g. JSON contains a property that isn't a member on the object) are handled during deserialization.
    /// </summary>
    /// <value>Missing member handling.</value>
    public MissingMemberHandling MissingMemberHandling { get; set; }

    /// <summary>
    /// Gets or sets how objects are created during deserialization.
    /// </summary>
    /// <value>The object creation handling.</value>
    public ObjectCreationHandling ObjectCreationHandling { get; set; }

    /// <summary>
    /// Gets or sets how null values are handled during serialization and deserialization.
    /// </summary>
    /// <value>Null value handling.</value>
    public NullValueHandling NullValueHandling { get; set; }

    /// <summary>
    /// Gets or sets how null default are handled during serialization and deserialization.
    /// </summary>
    /// <value>The default value handling.</value>
    public DefaultValueHandling DefaultValueHandling { get; set; }

    /// <summary>
    /// Gets or sets a collection <see cref="JsonConverter"/> that will be used during serialization.
    /// </summary>
    /// <value>The converters.</value>
    public IList<JsonConverter> Converters { get; set; }

    /// <summary>
    /// Gets or sets how object references are preserved by the serializer.
    /// </summary>
    /// <value>The preserve references handling.</value>
    public PreserveReferencesHandling PreserveReferencesHandling { get; set; }

    /// <summary>
    /// Gets or sets how type name writing and reading is handled by the serializer.
    /// </summary>
    /// <value>The type name handling.</value>
    public TypeNameHandling TypeNameHandling { get; set; }

    /// <summary>
    /// Gets or sets how a type name assembly is written and resolved by the serializer.
    /// </summary>
    /// <value>The type name assembly format.</value>
    public FormatterAssemblyStyle TypeNameAssemblyFormat { get; set; }

    /// <summary>
    /// Gets or sets how constructors are used during deserialization.
    /// </summary>
    /// <value>The constructor handling.</value>
    public ConstructorHandling ConstructorHandling { get; set; }

    /// <summary>
    /// Gets or sets the contract resolver used by the serializer when
    /// serializing .NET objects to JSON and vice versa.
    /// </summary>
    /// <value>The contract resolver.</value>
    public IContractResolver ContractResolver { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="IReferenceResolver"/> used by the serializer when resolving references.
    /// </summary>
    /// <value>The reference resolver.</value>
    public IReferenceResolver ReferenceResolver { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="SerializationBinder"/> used by the serializer when resolving type names.
    /// </summary>
    /// <value>The binder.</value>
    public SerializationBinder Binder { get; set; }

    /// <summary>
    /// Gets or sets the error handler called during serialization and deserialization.
    /// </summary>
    /// <value>The error handler called during serialization and deserialization.</value>
    public EventHandler<ErrorEventArgs> Error { get; set; }

    /// <summary>
    /// Gets or sets the <see cref="StreamingContext"/> used by the serializer when invoking serialization callback methods.
    /// </summary>
    /// <value>The context.</value>
    public StreamingContext Context { get; set; }

    /// <summary>
    /// Gets or sets the maximum depth allowed when reading JSON. Reading past this depth will throw a <see cref="JsonReaderException"/>.
    /// </summary>
    public int? MaxDepth
    {
      get { return _maxDepth; }
      set
      {
        if (value <= 0)
          throw new ArgumentException("Value must be positive.", "value");

        _maxDepth = value;
        _maxDepthSet = true;
      }
    }

    /// <summary>
    /// Indicates how JSON text output is formatted.
    /// </summary>
    public Formatting Formatting
    {
      get { return _formatting ?? DefaultFormatting; }
      set { _formatting = value; }
    }

    /// <summary>
    /// Get or set how dates are written to JSON text.
    /// </summary>
    public DateFormatHandling DateFormatHandling
    {
      get { return _dateFormatHandling ?? DefaultDateFormatHandling; }
      set { _dateFormatHandling = value; }
    }

    /// <summary>
    /// Get or set how <see cref="DateTime"/> time zones are handling during serialization and deserialization.
    /// </summary>
    public DateTimeZoneHandling DateTimeZoneHandling
    {
      get { return _dateTimeZoneHandling ?? DefaultDateTimeZoneHandling; }
      set { _dateTimeZoneHandling = value; }
    }

    /// <summary>
    /// Get or set how date formatted strings, e.g. "\/Date(1198908717056)\/" and "2012-03-21T05:40Z", are parsed when reading JSON.
    /// </summary>
    public DateParseHandling DateParseHandling
    {
      get { return _dateParseHandling ?? DefaultDateParseHandling; }
      set { _dateParseHandling = value; }
    }

    /// <summary>
    /// Gets or sets the culture used when reading JSON. Defaults to <see cref="CultureInfo.InvariantCulture"/>.
    /// </summary>
    public CultureInfo Culture
    {
      get { return _culture ?? DefaultCulture; }
      set { _culture = value; }
    }

    /// <summary>
    /// Gets a value indicating whether there will be a check for additional content after deserializing an object.
    /// </summary>
    /// <value>
    /// 	<c>true</c> if there will be a check for additional content after deserializing an object; otherwise, <c>false</c>.
    /// </value>
    public bool CheckAdditionalContent
    {
      get { return _checkAdditionalContent ?? DefaultCheckAdditionalContent; }
      set { _checkAdditionalContent = value; }
    }

    static JsonSerializerSettings()
    {
      DefaultContext = new StreamingContext();
      DefaultCulture = CultureInfo.InvariantCulture;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="JsonSerializerSettings"/> class.
    /// </summary>
    public JsonSerializerSettings()
    {
      ReferenceLoopHandling = DefaultReferenceLoopHandling;
      MissingMemberHandling = DefaultMissingMemberHandling;
      ObjectCreationHandling = DefaultObjectCreationHandling;
      NullValueHandling = DefaultNullValueHandling;
      DefaultValueHandling = DefaultDefaultValueHandling;
      PreserveReferencesHandling = DefaultPreserveReferencesHandling;
      TypeNameHandling = DefaultTypeNameHandling;
      TypeNameAssemblyFormat = DefaultTypeNameAssemblyFormat;
      Context = DefaultContext;

      Converters = new List<JsonConverter>();
    }
  }
}