using Lucene.Net.Search;

namespace Lucene.Net.Join
{
    /*
	 * Licensed to the Apache Software Foundation (ASF) under one or more
	 * contributor license agreements.  See the NOTICE file distributed with
	 * this work for additional information regarding copyright ownership.
	 * The ASF licenses this file to You under the Apache License, Version 2.0
	 * (the "License"); you may not use this file except in compliance with
	 * the License.  You may obtain a copy of the License at
	 *
	 *     http://www.apache.org/licenses/LICENSE-2.0
	 *
	 * Unless required by applicable law or agreed to in writing, software
	 * distributed under the License is distributed on an "AS IS" BASIS,
	 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	 * See the License for the specific language governing permissions and
	 * limitations under the License.
	 */

    /// <summary>
	/// A special sort field that allows sorting parent docs based on nested / child level fields.
	/// Based on the sort order it either takes the document with the lowest or highest field value into account.
	/// 
	/// @lucene.experimental
	/// </summary>
	public class ToParentBlockJoinSortField : SortField
    {
        private readonly bool order;
        private readonly Filter parentFilter;
        private readonly Filter childFilter;

        /// <summary>
        /// Create <see cref="ToParentBlockJoinSortField"/>. The parent document ordering is based on child document ordering (reverse).
        /// </summary>
        /// <param name="field"> The sort field on the nested / child level. </param>
        /// <param name="type"> The sort type on the nested / child level. </param>
        /// <param name="reverse"> Whether natural order should be reversed on the nested / child level. </param>
        /// <param name="parentFilter"> <see cref="Filter"/> that identifies the parent documents. </param>
        /// <param name="childFilter"> <see cref="Filter"/> that defines which child documents participates in sorting. </param>
        public ToParentBlockJoinSortField(string field, SortFieldType type, bool reverse, Filter parentFilter, Filter childFilter) 
            : base(field, type, reverse)
        {
            this.order = reverse;
            this.parentFilter = parentFilter;
            this.childFilter = childFilter;
        }

        /// <summary>
        /// Create <see cref="ToParentBlockJoinSortField"/>.
        /// </summary>
        /// <param name="field"> The sort field on the nested / child level. </param>
        /// <param name="type"> The sort type on the nested / child level. </param>
        /// <param name="reverse"> Whether natural order should be reversed on the nested / child document level. </param>
        /// <param name="order"> Whether natural order should be reversed on the parent level. </param>
        /// <param name="parentFilter"> <see cref="Filter"/> that identifies the parent documents. </param>
        /// <param name="childFilter"> <see cref="Filter"/> that defines which child documents participates in sorting. </param>
        public ToParentBlockJoinSortField(string field, SortFieldType type, bool reverse, bool order, Filter parentFilter, Filter childFilter) 
            : base(field, type, reverse)
        {
            this.order = order;
            this.parentFilter = parentFilter;
            this.childFilter = childFilter;
        }
        
        public override FieldComparer GetComparer(int numHits, int sortPos)
        {
            var wrappedFieldComparer = base.GetComparer(numHits + 1, sortPos);
            if (order)
            {
                return new ToParentBlockJoinFieldComparer.Highest(wrappedFieldComparer, parentFilter, childFilter, numHits);
            }

            return new ToParentBlockJoinFieldComparer.Lowest(wrappedFieldComparer, parentFilter, childFilter, numHits);
        }
    }
}