using System;
using System.Collections.Generic;
using System.Threading;

namespace System.Reactive
{
	internal static class ExceptionHelper
	{
		public static Exception Terminated { get; } = new ExceptionHelper.TerminatedException();

		public static bool TrySetException(ref Exception field, Exception ex)
		{
			return Interlocked.CompareExchange<Exception>(ref field, ex, null) == null;
		}

		public static Exception Terminate(ref Exception field)
		{
			Exception ex = Volatile.Read<Exception>(ref field);
			if (ex != ExceptionHelper.<Terminated>k__BackingField)
			{
				ex = Interlocked.Exchange<Exception>(ref field, ExceptionHelper.<Terminated>k__BackingField);
			}
			return ex;
		}

		public static bool TryAddException(ref Exception field, Exception ex)
		{
			for (;;)
			{
				Exception ex2 = Volatile.Read<Exception>(ref field);
				if (ex2 == ExceptionHelper.<Terminated>k__BackingField)
				{
					break;
				}
				Exception ex3;
				if (ex2 == null)
				{
					ex3 = ex;
				}
				else
				{
					AggregateException ex4 = ex2 as AggregateException;
					if (ex4 != null)
					{
						ex3 = new AggregateException(new List<Exception>(ex4.InnerExceptions) { ex });
					}
					else
					{
						ex3 = new AggregateException(new Exception[] { ex2, ex });
					}
				}
				if (Interlocked.CompareExchange<Exception>(ref field, ex3, ex2) == ex2)
				{
					return true;
				}
			}
			return false;
		}

		private sealed class TerminatedException : Exception
		{
			internal TerminatedException()
				: base("No further exceptions")
			{
			}
		}
	}
}
