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

namespace System.Threading.Channels
{
	internal static class ChannelUtilities
	{
		internal static void Complete(TaskCompletionSource tcs, Exception error = null)
		{
			OperationCanceledException ex = error as OperationCanceledException;
			if (ex != null)
			{
				tcs.TrySetCanceled(ex.CancellationToken);
				return;
			}
			if (error != null && error != ChannelUtilities.s_doneWritingSentinel)
			{
				tcs.TrySetException(error);
				return;
			}
			tcs.TrySetResult();
		}

		internal static ValueTask<T> GetInvalidCompletionValueTask<T>(Exception error)
		{
			Task<T> task;
			if (error != ChannelUtilities.s_doneWritingSentinel)
			{
				OperationCanceledException ex = error as OperationCanceledException;
				task = ((ex != null) ? Task.FromCanceled<T>(ex.CancellationToken.IsCancellationRequested ? ex.CancellationToken : new CancellationToken(true)) : Task.FromException<T>(ChannelUtilities.CreateInvalidCompletionException(error)));
			}
			else
			{
				task = Task.FromException<T>(ChannelUtilities.CreateInvalidCompletionException(null));
			}
			Task<T> task2 = task;
			return new ValueTask<T>(task2);
		}

		internal static void QueueWaiter(ref AsyncOperation<bool> tail, AsyncOperation<bool> waiter)
		{
			AsyncOperation<bool> asyncOperation = tail;
			if (asyncOperation == null)
			{
				waiter.Next = waiter;
			}
			else
			{
				waiter.Next = asyncOperation.Next;
				asyncOperation.Next = waiter;
			}
			tail = waiter;
		}

		internal static void WakeUpWaiters(ref AsyncOperation<bool> listTail, bool result, Exception error = null)
		{
			AsyncOperation<bool> asyncOperation = listTail;
			if (asyncOperation != null)
			{
				listTail = null;
				AsyncOperation<bool> next = asyncOperation.Next;
				AsyncOperation<bool> asyncOperation2 = next;
				do
				{
					AsyncOperation<bool> next2 = asyncOperation2.Next;
					asyncOperation2.Next = null;
					if (error == null)
					{
						asyncOperation2.TrySetResult(result);
					}
					else
					{
						asyncOperation2.TrySetException(error);
					}
					asyncOperation2 = next2;
				}
				while (asyncOperation2 != next);
			}
		}

		internal static void FailOperations<T, TInner>(Deque<T> operations, Exception error) where T : AsyncOperation<TInner>
		{
			while (!operations.IsEmpty)
			{
				operations.DequeueHead().TrySetException(error);
			}
		}

		internal static Exception CreateInvalidCompletionException(Exception inner = null)
		{
			if (!(inner is OperationCanceledException))
			{
				if (inner != null)
				{
					if (inner != ChannelUtilities.s_doneWritingSentinel)
					{
						return new ChannelClosedException(inner);
					}
				}
				return new ChannelClosedException();
			}
			return inner;
		}

		internal static readonly Exception s_doneWritingSentinel = new Exception("s_doneWritingSentinel");

		internal static readonly Task<bool> s_trueTask = Task.FromResult<bool>(true);

		internal static readonly Task<bool> s_falseTask = Task.FromResult<bool>(false);

		internal static readonly Task s_neverCompletingTask = new TaskCompletionSource<bool>().Task;
	}
}
