/*
 * 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.
 */

package org.apache.datasketches.theta;

import java.lang.foreign.MemorySegment;

import org.apache.datasketches.common.Family;

/**
 * Computes a set difference, A-AND-NOT-B, of two ThetaSketches.
 * This class includes both stateful and stateless operations.
 *
 * <p>The stateful operation is as follows:</p>
 * <pre><code>
 * ThetaAnotB anotb = ThetaSetOperationBuilder.buildAnotB();
 *
 * anotb.setA(ThetaSketch skA); //The first argument.
 * anotb.notB(ThetaSketch skB); //The second (subtraction) argument.
 * anotb.notB(ThetaSketch skC); // ...any number of additional subtractions...
 * anotb.getResult(false); //Get an interim result.
 * anotb.notB(ThetaSketch skD); //Additional subtractions.
 * anotb.getResult(true);  //Final result and resets the ThetaAnotB operator.
 * </code></pre>
 *
 * <p>The stateless operation is as follows:</p>
 * <pre><code>
 * ThetaAnotB anotb = ThetaSetOperationBuilder.buildAnotB();
 *
 * CompactThetaSketch csk = anotb.aNotB(ThetaSketch skA, ThetaSketch skB);
 * </code></pre>
 *
 * <p>Calling the <i>setA</i> operation a second time essentially clears the internal state and loads
 * the new ThetaSketch.</p>
 *
 * <p>The stateless and stateful operations are independent of each other with the exception of
 * sharing the same update hash seed loaded as the default seed or specified by the user as an
 * argument to the builder.</p>
 *
 * @author Lee Rhodes
 */
public abstract class ThetaAnotB extends ThetaSetOperation {

  /**
   * Constructor
   */
  ThetaAnotB() {}

  @Override
  public Family getFamily() {
    return Family.A_NOT_B;
  }

  /**
   * This is part of a multistep, stateful ThetaAnotB operation and sets the given ThetaSketch as the
   * first argument <i>A</i> of <i>A-AND-NOT-B</i>. This overwrites the internal state of this
   * ThetaAnotB operator with the contents of the given sketch.
   * This sets the stage for multiple following <i>notB</i> steps.
   *
   * <p>An input argument of null will throw an exception.</p>
   *
   * <p>Rationale: In mathematics a "null set" is a set with no members, which we call an empty set.
   * That is distinctly different from the java <i>null</i>, which represents a nonexistent object.
   * In most cases it is a programming error due to some object that was not properly initialized.
   * With a null as the first argument, we cannot know what the user's intent is.
   * Since it is very likely that a <i>null</i> is a programming error, we throw a an exception.</p>
   *
   * <p>An empty input argument will set the internal state to empty.</p>
   *
   * <p>Rationale: An empty set is a mathematically legal concept. Although it makes any subsequent,
   * valid argument for B irrelevant, we must allow this and assume the user knows what they are
   * doing.</p>
   *
   * <p>Performing {@link #getResult(boolean)} just after this step will return a compact form of
   * the given argument.</p>
   *
   * @param skA The incoming sketch for the first argument, <i>A</i>.
   */
  public abstract void setA(ThetaSketch skA);

  /**
   * This is part of a multistep, stateful ThetaAnotB operation and sets the given ThetaSketch as the
   * second (or <i>n+1</i>th) argument <i>B</i> of <i>A-AND-NOT-B</i>.
   * Performs an <i>AND NOT</i> operation with the existing internal state of this ThetaAnotB operator.
   *
   * <p>An input argument of null or empty is ignored.</p>
   *
   * <p>Rationale: A <i>null</i> for the second or following arguments is more tolerable because
   * <i>A NOT null</i> is still <i>A</i> even if we don't know exactly what the null represents. It
   * clearly does not have any content that overlaps with <i>A</i>. Also, because this can be part of
   * a multistep operation with multiple <i>notB</i> steps. Other following steps can still produce
   * a valid result.</p>
   *
   * <p>Use {@link #getResult(boolean)} to obtain the result.</p>
   *
   * @param skB The incoming ThetaSketch for the second (or following) argument <i>B</i>.
   */
  public abstract void notB(ThetaSketch skB);

  /**
   * Gets the result of the multistep, stateful operation ThetaAnotB that have been executed with calls
   * to {@link #setA(ThetaSketch)} and ({@link #notB(ThetaSketch)} or
   * {@link #notB(org.apache.datasketches.theta.ThetaSketch)}).
   *
   * @param reset If <i>true</i>, clears this operator to the empty state after this result is
   * returned. Set this to <i>false</i> if you wish to obtain an intermediate result.
   *
   * @return the result of this operation as an ordered, on-heap {@link CompactThetaSketch}.
   */
  public abstract CompactThetaSketch getResult(boolean reset);

  /**
   * Gets the result of the multistep, stateful operation ThetaAnotB that have been executed with calls
   * to {@link #setA(ThetaSketch)} and ({@link #notB(ThetaSketch)} or
   * {@link #notB(org.apache.datasketches.theta.ThetaSketch)}).
   *
   * @param dstOrdered If <i>true</i>, the result will be an ordered {@link CompactThetaSketch}.
   * <a href="{@docRoot}/resources/dictionary.html#dstOrdered">See Destination Ordered</a>.
   *
   * @param dstSeg if not <i>null</i> the given MemorySegment will be the target location of the result.
   *
   * @param reset If <i>true</i>, clears this operator to the empty state after this result is
   * returned. Set this to <i>false</i> if you wish to obtain an intermediate result.
   *
   * @return the result of this operation as a {@link CompactThetaSketch} in the given dstSeg.
   */
  public abstract CompactThetaSketch getResult(boolean dstOrdered, MemorySegment dstSeg, boolean reset);

  /**
   * Perform A-and-not-B set operation on the two given sketches and return the result as an
   * ordered CompactThetaSketch on the heap.
   *
   * <p>This a stateless operation and has no impact on the internal state of this operator.
   * Thus, this is not an accumulating update and does not interact with the {@link #setA(ThetaSketch)},
   * {@link #notB(ThetaSketch)}, {@link #getResult(boolean)}, or
   * {@link #getResult(boolean, MemorySegment, boolean)} methods.</p>
   *
   * <p>If either argument is null an exception is thrown.</p>
   *
   * <p>Rationale: In mathematics a "null set" is a set with no members, which we call an empty set.
   * That is distinctly different from the java <i>null</i>, which represents a nonexistent object.
   * In most cases <i>null</i> is a programming error due to a non-initialized object. </p>
   *
   * <p>With a null as the first argument we cannot know what the user's intent is and throw an
   * exception. With a null as the second argument for this method we must return a result and
   * there is no following possible viable arguments for the second argument so we thrown an
   * exception.</p>
   *
   * @param skA The incoming sketch for the first argument. It must not be null.
   * @param skB The incoming sketch for the second argument. It must not be null.
   * @return an ordered CompactThetaSketch on the heap
   */
  public CompactThetaSketch aNotB(final ThetaSketch skA, final ThetaSketch skB) {
    return aNotB(skA, skB, true, null);
  }

  /**
   * Perform A-and-not-B set operation on the two given sketches and return the result as a
   * CompactThetaSketch.
   *
   * <p>This a stateless operation and has no impact on the internal state of this operator.
   * Thus, this is not an accumulating update and does not interact with the {@link #setA(ThetaSketch)},
   * {@link #notB(ThetaSketch)}, {@link #getResult(boolean)}, or
   * {@link #getResult(boolean, MemorySegment, boolean)} methods.</p>
   *
   * <p>If either argument is null an exception is thrown.</p>
   *
   * <p>Rationale: In mathematics a "null set" is a set with no members, which we call an empty set.
   * That is distinctly different from the java <i>null</i>, which represents a nonexistent object.
   * In most cases <i>null</i> is a programming error due to a non-initialized object. </p>
   *
   * <p>With a null as the first argument we cannot know what the user's intent is and throw an
   * exception. With a null as the second argument for this method we must return a result and
   * there is no following possible viable arguments for the second argument so we thrown an
   * exception.</p>
   *
   * @param skA The incoming sketch for the first argument. It must not be null.
   * @param skB The incoming sketch for the second argument. It must not be null.
   * @param dstOrdered
   * <a href="{@docRoot}/resources/dictionary.html#dstOrdered">See Destination Ordered</a>.
   * @param dstSeg the destination MemorySegment
   * @return the result as a CompactThetaSketch.
   */
  public abstract CompactThetaSketch aNotB(ThetaSketch skA, ThetaSketch skB, boolean dstOrdered,
      MemorySegment dstSeg);

}
