// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Mvc.Filters;

namespace Microsoft.AspNetCore.Mvc.Internal
{
    /// <summary>
    /// A one-way cursor for filters.
    /// </summary>
    /// <remarks>
    /// This will iterate the filter collection once per-stage, and skip any filters that don't have
    /// the one of interfaces that applies to the current stage.
    ///
    /// Filters are always executed in the following order, but short circuiting plays a role.
    ///
    /// Indentation reflects nesting.
    ///
    /// 1. Exception Filters
    ///     2. Authorization Filters
    ///     3. Action Filters
    ///        Action
    ///
    /// 4. Result Filters
    ///    Result
    ///
    /// </remarks>
    public struct FilterCursor
    {
        private readonly IFilterMetadata[] _filters;
        private int _index;

        public FilterCursor(IFilterMetadata[] filters)
        {
            _filters = filters;
            _index = 0;
        }

        public void Reset()
        {
            _index = 0;
        }

        public FilterCursorItem<TFilter, TFilterAsync> GetNextFilter<TFilter, TFilterAsync>()
            where TFilter : class
            where TFilterAsync : class
        {
            while (_index < _filters.Length)
            {
                var filter = _filters[_index] as TFilter;
                var filterAsync = _filters[_index] as TFilterAsync;

                _index += 1;

                if (filter != null || filterAsync != null)
                {
                    return new FilterCursorItem<TFilter, TFilterAsync>(filter, filterAsync);
                }
            }

            return default(FilterCursorItem<TFilter, TFilterAsync>);
        }
    }
}
