using System;

namespace ProtoBuf
{
    /// <summary>
    /// Additional information about a serialization operation
    /// </summary>
    public sealed class SerializationContext
    {
        private bool frozen;
        internal void Freeze() { frozen = true; }
        private void ThrowIfFrozen() { if (frozen) throw new InvalidOperationException("The serialization-context cannot be changed once it is in use"); }
        private object context;
        /// <summary>
        /// Gets or sets a user-defined object containing additional information about this serialization/deserialization operation.
        /// </summary>
        public object Context
        {
            get { return context; }
            set { if (context != value) { ThrowIfFrozen(); context = value; } }
        }

        private static readonly SerializationContext @default;

        static SerializationContext()
        {
            @default = new SerializationContext();
            @default.Freeze();
        }
        /// <summary>
        /// A default SerializationContext, with minimal information.
        /// </summary>
        internal static SerializationContext Default => @default;
#if PLAT_BINARYFORMATTER

#if !(COREFX || PROFILE259)
        private System.Runtime.Serialization.StreamingContextStates state = System.Runtime.Serialization.StreamingContextStates.Persistence;
        /// <summary>
        /// Gets or sets the source or destination of the transmitted data.
        /// </summary>
        public System.Runtime.Serialization.StreamingContextStates State
        {
            get { return state; }
            set { if (state != value) { ThrowIfFrozen(); state = value; } }
        }
#endif
		/// <summary>
		/// Convert a SerializationContext to a StreamingContext
		/// </summary>
		public static implicit operator System.Runtime.Serialization.StreamingContext(SerializationContext ctx)
        {
#if COREFX
			return new System.Runtime.Serialization.StreamingContext();
#else
            if (ctx == null) return new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence);
            return new System.Runtime.Serialization.StreamingContext(ctx.state, ctx.context);
#endif
        }
        /// <summary>
        /// Convert a StreamingContext to a SerializationContext
        /// </summary>
        public static implicit operator SerializationContext (System.Runtime.Serialization.StreamingContext ctx)
        {
            SerializationContext result = new SerializationContext();

#if !(COREFX || PROFILE259)
            result.Context = ctx.Context;
            result.State = ctx.State;
#endif

			return result;
        }
#endif
    }

}