namespace Lucene.Net.Util
{
    /*
     * 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.
     */

    using DocIdSetIterator = Lucene.Net.Search.DocIdSetIterator;

    /// <summary>
    /// <see cref="OpenBitSet"/> with added methods to bulk-update the bits
    /// from a <see cref="DocIdSetIterator"/>. (DISI stands for <see cref="DocIdSetIterator"/>).
    /// </summary>
    public class OpenBitSetDISI : OpenBitSet
    {
        /// <summary>
        /// Construct an <see cref="OpenBitSetDISI"/> with its bits set
        /// from the doc ids of the given <see cref="DocIdSetIterator"/>.
        /// Also give a maximum size one larger than the largest doc id for which a
        /// bit may ever be set on this <see cref="OpenBitSetDISI"/>.
        /// </summary>
        public OpenBitSetDISI(DocIdSetIterator disi, int maxSize)
            : base(maxSize)
        {
            InPlaceOr(disi);
        }

        /// <summary>
        /// Construct an <see cref="OpenBitSetDISI"/> with no bits set, and a given maximum size
        /// one larger than the largest doc id for which a bit may ever be set
        /// on this <see cref="OpenBitSetDISI"/>.
        /// </summary>
        public OpenBitSetDISI(int maxSize)
            : base(maxSize)
        {
        }

        /// <summary>
        /// Perform an inplace OR with the doc ids from a given <see cref="DocIdSetIterator"/>,
        /// setting the bit for each such doc id.
        /// These doc ids should be smaller than the maximum size passed to the
        /// constructor.
        /// </summary>
        public virtual void InPlaceOr(DocIdSetIterator disi)
        {
            int doc;
            long size = Length; // LUCENENET specific - using Length in place of Size (since they are the same)
            while ((doc = disi.NextDoc()) < size)
            {
                FastSet(doc);
            }
        }

        /// <summary>
        /// Perform an inplace AND with the doc ids from a given <see cref="DocIdSetIterator"/>,
        /// leaving only the bits set for which the doc ids are in common.
        /// These doc ids should be smaller than the maximum size passed to the
        /// constructor.
        /// </summary>
        public virtual void InPlaceAnd(DocIdSetIterator disi)
        {
            int bitSetDoc = NextSetBit(0);
            int disiDoc;
            while (bitSetDoc != -1 && (disiDoc = disi.Advance(bitSetDoc)) != DocIdSetIterator.NO_MORE_DOCS)
            {
                Clear(bitSetDoc, disiDoc);
                bitSetDoc = NextSetBit(disiDoc + 1);
            }
            if (bitSetDoc != -1)
            {
                Clear(bitSetDoc, Length); // LUCENENET specific - using Length in place of Size (since they are the same)
            }
        }

        /// <summary>
        /// Perform an inplace NOT with the doc ids from a given <see cref="DocIdSetIterator"/>,
        /// clearing all the bits for each such doc id.
        /// These doc ids should be smaller than the maximum size passed to the
        /// constructor.
        /// </summary>
        public virtual void InPlaceNot(DocIdSetIterator disi)
        {
            int doc;
            long size = Length; // LUCENENET specific - using Length in place of Size (since they are the same)
            while ((doc = disi.NextDoc()) < size)
            {
                FastClear(doc);
            }
        }

        /// <summary>
        /// Perform an inplace XOR with the doc ids from a given <see cref="DocIdSetIterator"/>,
        /// flipping all the bits for each such doc id.
        /// These doc ids should be smaller than the maximum size passed to the
        /// constructor.
        /// </summary>
        public virtual void InPlaceXor(DocIdSetIterator disi)
        {
            int doc;
            long size = Length; // LUCENENET specific - using Length in place of Size (since they are the same)
            while ((doc = disi.NextDoc()) < size)
            {
                FastFlip(doc);
            }
        }
    }
}