using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.Linq.Expressions;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json.Utilities;

namespace Newtonsoft.Json.Linq
{
	public class JValue : JToken, IEquatable<JValue>, IFormattable, IComparable, IComparable<JValue>, IConvertible
	{
		public override Task WriteToAsync(JsonWriter writer, CancellationToken cancellationToken, params JsonConverter[] converters)
		{
			if (converters != null && converters.Length != 0 && this._value != null)
			{
				JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, this._value.GetType());
				if (matchingConverter != null && matchingConverter.CanWrite)
				{
					matchingConverter.WriteJson(writer, this._value, JsonSerializer.CreateDefault());
					return AsyncUtils.CompletedTask;
				}
			}
			switch (this._valueType)
			{
			case JTokenType.Comment:
			{
				object value = this._value;
				return writer.WriteCommentAsync((value != null) ? value.ToString() : null, cancellationToken);
			}
			case JTokenType.Integer:
			{
				object obj;
				if ((obj = this._value) is int)
				{
					int num = (int)obj;
					return writer.WriteValueAsync(num, cancellationToken);
				}
				if ((obj = this._value) is long)
				{
					long num2 = (long)obj;
					return writer.WriteValueAsync(num2, cancellationToken);
				}
				if ((obj = this._value) is ulong)
				{
					ulong num3 = (ulong)obj;
					return writer.WriteValueAsync(num3, cancellationToken);
				}
				if ((obj = this._value) is BigInteger)
				{
					BigInteger bigInteger = (BigInteger)obj;
					return writer.WriteValueAsync(bigInteger, cancellationToken);
				}
				return writer.WriteValueAsync(Convert.ToInt64(this._value, CultureInfo.InvariantCulture), cancellationToken);
			}
			case JTokenType.Float:
			{
				object obj;
				if ((obj = this._value) is decimal)
				{
					decimal num4 = (decimal)obj;
					return writer.WriteValueAsync(num4, cancellationToken);
				}
				if ((obj = this._value) is double)
				{
					double num5 = (double)obj;
					return writer.WriteValueAsync(num5, cancellationToken);
				}
				if ((obj = this._value) is float)
				{
					float num6 = (float)obj;
					return writer.WriteValueAsync(num6, cancellationToken);
				}
				return writer.WriteValueAsync(Convert.ToDouble(this._value, CultureInfo.InvariantCulture), cancellationToken);
			}
			case JTokenType.String:
			{
				object value2 = this._value;
				return writer.WriteValueAsync((value2 != null) ? value2.ToString() : null, cancellationToken);
			}
			case JTokenType.Boolean:
				return writer.WriteValueAsync(Convert.ToBoolean(this._value, CultureInfo.InvariantCulture), cancellationToken);
			case JTokenType.Null:
				return writer.WriteNullAsync(cancellationToken);
			case JTokenType.Undefined:
				return writer.WriteUndefinedAsync(cancellationToken);
			case JTokenType.Date:
			{
				object obj;
				if ((obj = this._value) is DateTimeOffset)
				{
					DateTimeOffset dateTimeOffset = (DateTimeOffset)obj;
					return writer.WriteValueAsync(dateTimeOffset, cancellationToken);
				}
				return writer.WriteValueAsync(Convert.ToDateTime(this._value, CultureInfo.InvariantCulture), cancellationToken);
			}
			case JTokenType.Raw:
			{
				object value3 = this._value;
				return writer.WriteRawValueAsync((value3 != null) ? value3.ToString() : null, cancellationToken);
			}
			case JTokenType.Bytes:
				return writer.WriteValueAsync((byte[])this._value, cancellationToken);
			case JTokenType.Guid:
				return writer.WriteValueAsync((this._value != null) ? ((Guid?)this._value) : null, cancellationToken);
			case JTokenType.Uri:
				return writer.WriteValueAsync((Uri)this._value, cancellationToken);
			case JTokenType.TimeSpan:
				return writer.WriteValueAsync((this._value != null) ? ((TimeSpan?)this._value) : null, cancellationToken);
			default:
				throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", this._valueType, "Unexpected token type.");
			}
		}

		internal JValue(object value, JTokenType type)
		{
			this._value = value;
			this._valueType = type;
		}

		public JValue(JValue other)
			: this(other.Value, other.Type)
		{
		}

		public JValue(long value)
			: this(value, JTokenType.Integer)
		{
		}

		public JValue(decimal value)
			: this(value, JTokenType.Float)
		{
		}

		public JValue(char value)
			: this(value, JTokenType.String)
		{
		}

		[CLSCompliant(false)]
		public JValue(ulong value)
			: this(value, JTokenType.Integer)
		{
		}

		public JValue(double value)
			: this(value, JTokenType.Float)
		{
		}

		public JValue(float value)
			: this(value, JTokenType.Float)
		{
		}

		public JValue(DateTime value)
			: this(value, JTokenType.Date)
		{
		}

		public JValue(DateTimeOffset value)
			: this(value, JTokenType.Date)
		{
		}

		public JValue(bool value)
			: this(value, JTokenType.Boolean)
		{
		}

		public JValue(string value)
			: this(value, JTokenType.String)
		{
		}

		public JValue(Guid value)
			: this(value, JTokenType.Guid)
		{
		}

		public JValue(Uri value)
			: this(value, (value != null) ? JTokenType.Uri : JTokenType.Null)
		{
		}

		public JValue(TimeSpan value)
			: this(value, JTokenType.TimeSpan)
		{
		}

		public JValue(object value)
			: this(value, JValue.GetValueType(null, value))
		{
		}

		internal override bool DeepEquals(JToken node)
		{
			JValue jvalue;
			return (jvalue = node as JValue) != null && (jvalue == this || JValue.ValuesEquals(this, jvalue));
		}

		public override bool HasValues
		{
			get
			{
				return false;
			}
		}

		private static int CompareBigInteger(BigInteger i1, object i2)
		{
			int num = i1.CompareTo(ConvertUtils.ToBigInteger(i2));
			if (num != 0)
			{
				return num;
			}
			if (i2 is decimal)
			{
				decimal num2 = (decimal)i2;
				return 0m.CompareTo(Math.Abs(num2 - Math.Truncate(num2)));
			}
			if (!(i2 is double) && !(i2 is float))
			{
				return num;
			}
			double num3 = Convert.ToDouble(i2, CultureInfo.InvariantCulture);
			return 0.0.CompareTo(Math.Abs(num3 - Math.Truncate(num3)));
		}

		internal static int Compare(JTokenType valueType, object objA, object objB)
		{
			if (objA == objB)
			{
				return 0;
			}
			if (objB == null)
			{
				return 1;
			}
			if (objA == null)
			{
				return -1;
			}
			switch (valueType)
			{
			case JTokenType.Comment:
			case JTokenType.String:
			case JTokenType.Raw:
			{
				string text = Convert.ToString(objA, CultureInfo.InvariantCulture);
				string text2 = Convert.ToString(objB, CultureInfo.InvariantCulture);
				return string.CompareOrdinal(text, text2);
			}
			case JTokenType.Integer:
				if (objA is BigInteger)
				{
					BigInteger bigInteger = (BigInteger)objA;
					return JValue.CompareBigInteger(bigInteger, objB);
				}
				if (objB is BigInteger)
				{
					BigInteger bigInteger2 = (BigInteger)objB;
					return -JValue.CompareBigInteger(bigInteger2, objA);
				}
				if (objA is ulong || objB is ulong || objA is decimal || objB is decimal)
				{
					return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture));
				}
				if (!(objA is float) && !(objB is float) && !(objA is double) && !(objB is double))
				{
					return Convert.ToInt64(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToInt64(objB, CultureInfo.InvariantCulture));
				}
				return JValue.CompareFloat(objA, objB);
			case JTokenType.Float:
				if (objA is BigInteger)
				{
					BigInteger bigInteger3 = (BigInteger)objA;
					return JValue.CompareBigInteger(bigInteger3, objB);
				}
				if (objB is BigInteger)
				{
					BigInteger bigInteger4 = (BigInteger)objB;
					return -JValue.CompareBigInteger(bigInteger4, objA);
				}
				if (!(objA is ulong) && !(objB is ulong) && !(objA is decimal) && !(objB is decimal))
				{
					return JValue.CompareFloat(objA, objB);
				}
				return Convert.ToDecimal(objA, CultureInfo.InvariantCulture).CompareTo(Convert.ToDecimal(objB, CultureInfo.InvariantCulture));
			case JTokenType.Boolean:
			{
				bool flag = Convert.ToBoolean(objA, CultureInfo.InvariantCulture);
				bool flag2 = Convert.ToBoolean(objB, CultureInfo.InvariantCulture);
				return flag.CompareTo(flag2);
			}
			case JTokenType.Date:
			{
				if (objA is DateTime)
				{
					DateTime dateTime = (DateTime)objA;
					DateTime dateTime2;
					if (objB is DateTimeOffset)
					{
						dateTime2 = ((DateTimeOffset)objB).DateTime;
					}
					else
					{
						dateTime2 = Convert.ToDateTime(objB, CultureInfo.InvariantCulture);
					}
					return dateTime.CompareTo(dateTime2);
				}
				DateTimeOffset dateTimeOffset = (DateTimeOffset)objA;
				DateTimeOffset dateTimeOffset2;
				if (objB is DateTimeOffset)
				{
					dateTimeOffset2 = (DateTimeOffset)objB;
				}
				else
				{
					dateTimeOffset2 = new DateTimeOffset(Convert.ToDateTime(objB, CultureInfo.InvariantCulture));
				}
				return dateTimeOffset.CompareTo(dateTimeOffset2);
			}
			case JTokenType.Bytes:
			{
				byte[] array;
				if ((array = objB as byte[]) == null)
				{
					throw new ArgumentException("Object must be of type byte[].");
				}
				return MiscellaneousUtils.ByteArrayCompare(objA as byte[], array);
			}
			case JTokenType.Guid:
			{
				if (!(objB is Guid))
				{
					throw new ArgumentException("Object must be of type Guid.");
				}
				Guid guid = (Guid)objA;
				Guid guid2 = (Guid)objB;
				return guid.CompareTo(guid2);
			}
			case JTokenType.Uri:
			{
				Uri uri = objB as Uri;
				if (uri == null)
				{
					throw new ArgumentException("Object must be of type Uri.");
				}
				Uri uri2 = (Uri)objA;
				return Comparer<string>.Default.Compare(uri2.ToString(), uri.ToString());
			}
			case JTokenType.TimeSpan:
			{
				if (!(objB is TimeSpan))
				{
					throw new ArgumentException("Object must be of type TimeSpan.");
				}
				TimeSpan timeSpan = (TimeSpan)objA;
				TimeSpan timeSpan2 = (TimeSpan)objB;
				return timeSpan.CompareTo(timeSpan2);
			}
			}
			throw MiscellaneousUtils.CreateArgumentOutOfRangeException("valueType", valueType, "Unexpected value type: {0}".FormatWith(CultureInfo.InvariantCulture, valueType));
		}

		private static int CompareFloat(object objA, object objB)
		{
			double num = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
			double num2 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
			if (MathUtils.ApproxEquals(num, num2))
			{
				return 0;
			}
			return num.CompareTo(num2);
		}

		private static bool Operation(ExpressionType operation, object objA, object objB, out object result)
		{
			if (objA is string || objB is string)
			{
				if (operation != ExpressionType.Add)
				{
					if (operation != ExpressionType.AddAssign)
					{
						goto IL_0021;
					}
				}
				result = ((objA != null) ? objA.ToString() : null) + ((objB != null) ? objB.ToString() : null);
				return true;
			}
			IL_0021:
			if (!(objA is BigInteger) && !(objB is BigInteger))
			{
				if (!(objA is ulong) && !(objB is ulong) && !(objA is decimal) && !(objB is decimal))
				{
					if (!(objA is float) && !(objB is float) && !(objA is double) && !(objB is double))
					{
						if (objA is int || objA is uint || objA is long || objA is short || objA is ushort || objA is sbyte || objA is byte || objB is int || objB is uint || objB is long || objB is short || objB is ushort || objB is sbyte || objB is byte)
						{
							if (objA != null && objB != null)
							{
								long num = Convert.ToInt64(objA, CultureInfo.InvariantCulture);
								long num2 = Convert.ToInt64(objB, CultureInfo.InvariantCulture);
								if (operation <= ExpressionType.Subtract)
								{
									if (operation <= ExpressionType.Divide)
									{
										if (operation == ExpressionType.Add)
										{
											goto IL_0173;
										}
										if (operation != ExpressionType.Divide)
										{
											goto IL_0390;
										}
									}
									else
									{
										if (operation == ExpressionType.Multiply)
										{
											goto IL_019F;
										}
										if (operation != ExpressionType.Subtract)
										{
											goto IL_0390;
										}
										goto IL_0191;
									}
								}
								else if (operation <= ExpressionType.DivideAssign)
								{
									if (operation == ExpressionType.AddAssign)
									{
										goto IL_0173;
									}
									if (operation != ExpressionType.DivideAssign)
									{
										goto IL_0390;
									}
								}
								else
								{
									if (operation == ExpressionType.MultiplyAssign)
									{
										goto IL_019F;
									}
									if (operation != ExpressionType.SubtractAssign)
									{
										goto IL_0390;
									}
									goto IL_0191;
								}
								result = num / num2;
								return true;
								IL_0173:
								result = num + num2;
								return true;
								IL_0191:
								result = num - num2;
								return true;
								IL_019F:
								result = num * num2;
								return true;
							}
							result = null;
							return true;
						}
					}
					else
					{
						if (objA != null && objB != null)
						{
							double num3 = Convert.ToDouble(objA, CultureInfo.InvariantCulture);
							double num4 = Convert.ToDouble(objB, CultureInfo.InvariantCulture);
							if (operation <= ExpressionType.Subtract)
							{
								if (operation <= ExpressionType.Divide)
								{
									if (operation == ExpressionType.Add)
									{
										goto IL_0223;
									}
									if (operation != ExpressionType.Divide)
									{
										goto IL_0390;
									}
								}
								else
								{
									if (operation == ExpressionType.Multiply)
									{
										goto IL_024F;
									}
									if (operation != ExpressionType.Subtract)
									{
										goto IL_0390;
									}
									goto IL_0241;
								}
							}
							else if (operation <= ExpressionType.DivideAssign)
							{
								if (operation == ExpressionType.AddAssign)
								{
									goto IL_0223;
								}
								if (operation != ExpressionType.DivideAssign)
								{
									goto IL_0390;
								}
							}
							else
							{
								if (operation == ExpressionType.MultiplyAssign)
								{
									goto IL_024F;
								}
								if (operation != ExpressionType.SubtractAssign)
								{
									goto IL_0390;
								}
								goto IL_0241;
							}
							result = num3 / num4;
							return true;
							IL_0223:
							result = num3 + num4;
							return true;
							IL_0241:
							result = num3 - num4;
							return true;
							IL_024F:
							result = num3 * num4;
							return true;
						}
						result = null;
						return true;
					}
				}
				else
				{
					if (objA != null && objB != null)
					{
						decimal num5 = Convert.ToDecimal(objA, CultureInfo.InvariantCulture);
						decimal num6 = Convert.ToDecimal(objB, CultureInfo.InvariantCulture);
						if (operation <= ExpressionType.Subtract)
						{
							if (operation <= ExpressionType.Divide)
							{
								if (operation == ExpressionType.Add)
								{
									goto IL_02D3;
								}
								if (operation != ExpressionType.Divide)
								{
									goto IL_0390;
								}
							}
							else
							{
								if (operation == ExpressionType.Multiply)
								{
									goto IL_0303;
								}
								if (operation != ExpressionType.Subtract)
								{
									goto IL_0390;
								}
								goto IL_02F3;
							}
						}
						else if (operation <= ExpressionType.DivideAssign)
						{
							if (operation == ExpressionType.AddAssign)
							{
								goto IL_02D3;
							}
							if (operation != ExpressionType.DivideAssign)
							{
								goto IL_0390;
							}
						}
						else
						{
							if (operation == ExpressionType.MultiplyAssign)
							{
								goto IL_0303;
							}
							if (operation != ExpressionType.SubtractAssign)
							{
								goto IL_0390;
							}
							goto IL_02F3;
						}
						result = num5 / num6;
						return true;
						IL_02D3:
						result = num5 + num6;
						return true;
						IL_02F3:
						result = num5 - num6;
						return true;
						IL_0303:
						result = num5 * num6;
						return true;
					}
					result = null;
					return true;
				}
			}
			else
			{
				if (objA != null && objB != null)
				{
					BigInteger bigInteger = ConvertUtils.ToBigInteger(objA);
					BigInteger bigInteger2 = ConvertUtils.ToBigInteger(objB);
					if (operation <= ExpressionType.Subtract)
					{
						if (operation <= ExpressionType.Divide)
						{
							if (operation == ExpressionType.Add)
							{
								goto IL_0376;
							}
							if (operation != ExpressionType.Divide)
							{
								goto IL_0390;
							}
						}
						else
						{
							if (operation == ExpressionType.Multiply)
							{
								goto IL_03A5;
							}
							if (operation != ExpressionType.Subtract)
							{
								goto IL_0390;
							}
							goto IL_0395;
						}
					}
					else if (operation <= ExpressionType.DivideAssign)
					{
						if (operation == ExpressionType.AddAssign)
						{
							goto IL_0376;
						}
						if (operation != ExpressionType.DivideAssign)
						{
							goto IL_0390;
						}
					}
					else
					{
						if (operation == ExpressionType.MultiplyAssign)
						{
							goto IL_03A5;
						}
						if (operation != ExpressionType.SubtractAssign)
						{
							goto IL_0390;
						}
						goto IL_0395;
					}
					result = bigInteger / bigInteger2;
					return true;
					IL_0376:
					result = bigInteger + bigInteger2;
					return true;
					IL_0395:
					result = bigInteger - bigInteger2;
					return true;
					IL_03A5:
					result = bigInteger * bigInteger2;
					return true;
				}
				result = null;
				return true;
			}
			IL_0390:
			result = null;
			return false;
		}

		internal override JToken CloneToken()
		{
			return new JValue(this);
		}

		public static JValue CreateComment(string value)
		{
			return new JValue(value, JTokenType.Comment);
		}

		public static JValue CreateString(string value)
		{
			return new JValue(value, JTokenType.String);
		}

		public static JValue CreateNull()
		{
			return new JValue(null, JTokenType.Null);
		}

		public static JValue CreateUndefined()
		{
			return new JValue(null, JTokenType.Undefined);
		}

		private static JTokenType GetValueType(JTokenType? current, object value)
		{
			if (value == null)
			{
				return JTokenType.Null;
			}
			if (value == DBNull.Value)
			{
				return JTokenType.Null;
			}
			if (value is string)
			{
				return JValue.GetStringValueType(current);
			}
			if (value is long || value is int || value is short || value is sbyte || value is ulong || value is uint || value is ushort || value is byte)
			{
				return JTokenType.Integer;
			}
			if (value is Enum)
			{
				return JTokenType.Integer;
			}
			if (value is BigInteger)
			{
				return JTokenType.Integer;
			}
			if (value is double || value is float || value is decimal)
			{
				return JTokenType.Float;
			}
			if (value is DateTime)
			{
				return JTokenType.Date;
			}
			if (value is DateTimeOffset)
			{
				return JTokenType.Date;
			}
			if (value is byte[])
			{
				return JTokenType.Bytes;
			}
			if (value is bool)
			{
				return JTokenType.Boolean;
			}
			if (value is Guid)
			{
				return JTokenType.Guid;
			}
			if (value is Uri)
			{
				return JTokenType.Uri;
			}
			if (!(value is TimeSpan))
			{
				throw new ArgumentException("Could not determine JSON object type for type {0}.".FormatWith(CultureInfo.InvariantCulture, value.GetType()));
			}
			return JTokenType.TimeSpan;
		}

		private static JTokenType GetStringValueType(JTokenType? current)
		{
			if (current == null)
			{
				return JTokenType.String;
			}
			JTokenType valueOrDefault = current.GetValueOrDefault();
			if (valueOrDefault != JTokenType.Comment && valueOrDefault != JTokenType.String)
			{
				if (valueOrDefault != JTokenType.Raw)
				{
					return JTokenType.String;
				}
			}
			return current.GetValueOrDefault();
		}

		public override JTokenType Type
		{
			get
			{
				return this._valueType;
			}
		}

		public new object Value
		{
			get
			{
				return this._value;
			}
			set
			{
				object value2 = this._value;
				Type type = ((value2 != null) ? value2.GetType() : null);
				Type type2 = ((value != null) ? value.GetType() : null);
				if (type != type2)
				{
					this._valueType = JValue.GetValueType(new JTokenType?(this._valueType), value);
				}
				this._value = value;
			}
		}

		public override void WriteTo(JsonWriter writer, params JsonConverter[] converters)
		{
			if (converters != null && converters.Length != 0 && this._value != null)
			{
				JsonConverter matchingConverter = JsonSerializer.GetMatchingConverter(converters, this._value.GetType());
				if (matchingConverter != null && matchingConverter.CanWrite)
				{
					matchingConverter.WriteJson(writer, this._value, JsonSerializer.CreateDefault());
					return;
				}
			}
			switch (this._valueType)
			{
			case JTokenType.Comment:
			{
				object value = this._value;
				writer.WriteComment((value != null) ? value.ToString() : null);
				return;
			}
			case JTokenType.Integer:
			{
				object obj;
				if ((obj = this._value) is int)
				{
					int num = (int)obj;
					writer.WriteValue(num);
					return;
				}
				if ((obj = this._value) is long)
				{
					long num2 = (long)obj;
					writer.WriteValue(num2);
					return;
				}
				if ((obj = this._value) is ulong)
				{
					ulong num3 = (ulong)obj;
					writer.WriteValue(num3);
					return;
				}
				if ((obj = this._value) is BigInteger)
				{
					BigInteger bigInteger = (BigInteger)obj;
					writer.WriteValue(bigInteger);
					return;
				}
				writer.WriteValue(Convert.ToInt64(this._value, CultureInfo.InvariantCulture));
				return;
			}
			case JTokenType.Float:
			{
				object obj;
				if ((obj = this._value) is decimal)
				{
					decimal num4 = (decimal)obj;
					writer.WriteValue(num4);
					return;
				}
				if ((obj = this._value) is double)
				{
					double num5 = (double)obj;
					writer.WriteValue(num5);
					return;
				}
				if ((obj = this._value) is float)
				{
					float num6 = (float)obj;
					writer.WriteValue(num6);
					return;
				}
				writer.WriteValue(Convert.ToDouble(this._value, CultureInfo.InvariantCulture));
				return;
			}
			case JTokenType.String:
			{
				object value2 = this._value;
				writer.WriteValue((value2 != null) ? value2.ToString() : null);
				return;
			}
			case JTokenType.Boolean:
				writer.WriteValue(Convert.ToBoolean(this._value, CultureInfo.InvariantCulture));
				return;
			case JTokenType.Null:
				writer.WriteNull();
				return;
			case JTokenType.Undefined:
				writer.WriteUndefined();
				return;
			case JTokenType.Date:
			{
				object obj;
				if ((obj = this._value) is DateTimeOffset)
				{
					DateTimeOffset dateTimeOffset = (DateTimeOffset)obj;
					writer.WriteValue(dateTimeOffset);
					return;
				}
				writer.WriteValue(Convert.ToDateTime(this._value, CultureInfo.InvariantCulture));
				return;
			}
			case JTokenType.Raw:
			{
				object value3 = this._value;
				writer.WriteRawValue((value3 != null) ? value3.ToString() : null);
				return;
			}
			case JTokenType.Bytes:
				writer.WriteValue((byte[])this._value);
				return;
			case JTokenType.Guid:
				writer.WriteValue((this._value != null) ? ((Guid?)this._value) : null);
				return;
			case JTokenType.Uri:
				writer.WriteValue((Uri)this._value);
				return;
			case JTokenType.TimeSpan:
				writer.WriteValue((this._value != null) ? ((TimeSpan?)this._value) : null);
				return;
			default:
				throw MiscellaneousUtils.CreateArgumentOutOfRangeException("Type", this._valueType, "Unexpected token type.");
			}
		}

		internal override int GetDeepHashCode()
		{
			int num = ((this._value != null) ? this._value.GetHashCode() : 0);
			int valueType = (int)this._valueType;
			return valueType.GetHashCode() ^ num;
		}

		private static bool ValuesEquals(object v1, object v2)
		{
			return v1 == v2 || (v1._valueType == v2._valueType && JValue.Compare(v1._valueType, v1._value, v2._value) == 0);
		}

		public bool Equals(JValue other)
		{
			return other != null && JValue.ValuesEquals(this, other);
		}

		public override bool Equals(object obj)
		{
			return this.Equals(obj as JValue);
		}

		public override int GetHashCode()
		{
			if (this._value == null)
			{
				return 0;
			}
			return this._value.GetHashCode();
		}

		public override string ToString()
		{
			if (this._value == null)
			{
				return string.Empty;
			}
			return this._value.ToString();
		}

		public string ToString(string format)
		{
			return this.ToString(format, CultureInfo.CurrentCulture);
		}

		public string ToString(IFormatProvider formatProvider)
		{
			return this.ToString(null, formatProvider);
		}

		public string ToString(string format, IFormatProvider formatProvider)
		{
			if (this._value == null)
			{
				return string.Empty;
			}
			IFormattable formattable;
			if ((formattable = this._value as IFormattable) != null)
			{
				return formattable.ToString(format, formatProvider);
			}
			return this._value.ToString();
		}

		protected override DynamicMetaObject GetMetaObject(Expression parameter)
		{
			return new DynamicProxyMetaObject<JValue>(parameter, this, new JValue.Class3());
		}

		int IComparable.CompareTo(object obj)
		{
			if (obj == null)
			{
				return 1;
			}
			JValue jvalue = obj as JValue;
			object obj2;
			JTokenType jtokenType2;
			if (jvalue != null)
			{
				obj2 = jvalue.Value;
				JTokenType jtokenType;
				if (this._valueType == JTokenType.String)
				{
					if (this._valueType != jvalue._valueType)
					{
						jtokenType = jvalue._valueType;
						goto IL_003E;
					}
				}
				jtokenType = this._valueType;
				IL_003E:
				jtokenType2 = jtokenType;
			}
			else
			{
				obj2 = obj;
				jtokenType2 = this._valueType;
			}
			return JValue.Compare(jtokenType2, this._value, obj2);
		}

		public int CompareTo(JValue obj)
		{
			if (obj == null)
			{
				return 1;
			}
			JTokenType jtokenType;
			if (this._valueType == JTokenType.String)
			{
				if (this._valueType != obj._valueType)
				{
					jtokenType = obj._valueType;
					goto IL_002D;
				}
			}
			jtokenType = this._valueType;
			IL_002D:
			return JValue.Compare(jtokenType, this._value, obj._value);
		}

		TypeCode IConvertible.GetTypeCode()
		{
			if (this._value == null)
			{
				return TypeCode.Empty;
			}
			IConvertible convertible;
			if ((convertible = this._value as IConvertible) != null)
			{
				return convertible.GetTypeCode();
			}
			return TypeCode.Object;
		}

		bool IConvertible.ToBoolean(IFormatProvider provider)
		{
			return (bool)this;
		}

		char IConvertible.ToChar(IFormatProvider provider)
		{
			return (char)this;
		}

		sbyte IConvertible.ToSByte(IFormatProvider provider)
		{
			return (sbyte)this;
		}

		byte IConvertible.ToByte(IFormatProvider provider)
		{
			return (byte)this;
		}

		short IConvertible.ToInt16(IFormatProvider provider)
		{
			return (short)this;
		}

		ushort IConvertible.ToUInt16(IFormatProvider provider)
		{
			return (ushort)this;
		}

		int IConvertible.ToInt32(IFormatProvider provider)
		{
			return (int)this;
		}

		uint IConvertible.ToUInt32(IFormatProvider provider)
		{
			return (uint)this;
		}

		long IConvertible.ToInt64(IFormatProvider provider)
		{
			return (long)this;
		}

		ulong IConvertible.ToUInt64(IFormatProvider provider)
		{
			return (ulong)this;
		}

		float IConvertible.ToSingle(IFormatProvider provider)
		{
			return (float)this;
		}

		double IConvertible.ToDouble(IFormatProvider provider)
		{
			return (double)this;
		}

		decimal IConvertible.ToDecimal(IFormatProvider provider)
		{
			return (decimal)this;
		}

		DateTime IConvertible.ToDateTime(IFormatProvider provider)
		{
			return (DateTime)this;
		}

		object IConvertible.ToType(Type conversionType, IFormatProvider provider)
		{
			return base.ToObject(conversionType);
		}

		private JTokenType _valueType;

		private object _value;

		private class Class3 : DynamicProxy<JValue>
		{
			public override bool TryConvert(JValue instance, ConvertBinder binder, out object result)
			{
				if (binder.Type == typeof(JValue) || binder.Type == typeof(JToken))
				{
					result = instance;
					return true;
				}
				object value = instance.Value;
				if (value == null)
				{
					result = null;
					return ReflectionUtils.IsNullable(binder.Type);
				}
				result = ConvertUtils.Convert(value, CultureInfo.InvariantCulture, binder.Type);
				return true;
			}

			public override bool TryBinaryOperation(JValue instance, BinaryOperationBinder binder, object arg, out object result)
			{
				JValue jvalue;
				object obj = (((jvalue = arg as JValue) != null) ? jvalue.Value : arg);
				ExpressionType operation = binder.Operation;
				if (operation <= ExpressionType.NotEqual)
				{
					if (operation <= ExpressionType.LessThanOrEqual)
					{
						if (operation != ExpressionType.Add)
						{
							switch (operation)
							{
							case ExpressionType.Divide:
								break;
							case ExpressionType.Equal:
								result = JValue.Compare(instance.Type, instance.Value, obj) == 0;
								return true;
							case ExpressionType.ExclusiveOr:
							case ExpressionType.Invoke:
							case ExpressionType.Lambda:
							case ExpressionType.LeftShift:
								goto IL_017C;
							case ExpressionType.GreaterThan:
								result = JValue.Compare(instance.Type, instance.Value, obj) > 0;
								return true;
							case ExpressionType.GreaterThanOrEqual:
								result = JValue.Compare(instance.Type, instance.Value, obj) >= 0;
								return true;
							case ExpressionType.LessThan:
								result = JValue.Compare(instance.Type, instance.Value, obj) < 0;
								return true;
							case ExpressionType.LessThanOrEqual:
								result = JValue.Compare(instance.Type, instance.Value, obj) <= 0;
								return true;
							default:
								goto IL_017C;
							}
						}
					}
					else if (operation != ExpressionType.Multiply)
					{
						if (operation != ExpressionType.NotEqual)
						{
							goto IL_017C;
						}
						result = JValue.Compare(instance.Type, instance.Value, obj) != 0;
						return true;
					}
				}
				else if (operation <= ExpressionType.AddAssign)
				{
					if (operation != ExpressionType.Subtract && operation != ExpressionType.AddAssign)
					{
						goto IL_017C;
					}
				}
				else if (operation != ExpressionType.DivideAssign && operation != ExpressionType.MultiplyAssign && operation != ExpressionType.SubtractAssign)
				{
					goto IL_017C;
				}
				if (JValue.Operation(binder.Operation, instance.Value, obj, out result))
				{
					result = new JValue(result);
					return true;
				}
				IL_017C:
				result = null;
				return false;
			}
		}
	}
}
