/*
 *  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 groovy.contracts;

import org.apache.groovy.contracts.annotations.meta.AnnotationProcessorImplementation;
import org.apache.groovy.contracts.annotations.meta.Precondition;
import org.apache.groovy.contracts.common.impl.RequiresAnnotationProcessor;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * <p>
 * Represents a <b>method precondition</b>.
 * </p>
 * <p>
 * A precondition is a condition that must be met by clients of this class. Whenever the
 * precondition can be satisfied, it is guaranteed that the supplier will fulfil the method's
 * postcondition.
 * </p>
 * <p>
 * A method's precondition is executed <i>as the first statement</i> within a method call. A
 * successor's precondition weakens the precondition of its parent class, e.g. if A.someMethod
 * declares a precondition and B.someMethod overrides the method the preconditions are combined with a boolean OR.
 * </p>
 * <p>
 * Example:
 *
 * <pre>
 *   &#064;Requires({ argument1 != argument2 &amp;&amp; argument2 &gt;= 0 })
 *   void someOperation(def argument1, def argument2)  {
 *     ...
 *   }
 * </pre>
 * </p>
 *
 * @since 4.0.0
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
@Precondition
@AnnotationProcessorImplementation(RequiresAnnotationProcessor.class)
@Repeatable(RequiresConditions.class)
public @interface Requires {
    /**
     * Returns the closure class that evaluates the precondition expression.
     *
     * @return the generated closure class backing the precondition
     */
    Class value();

    /**
     * {@code true} (default): weave the precondition assertion — the current
     * behaviour, a violating caller observes a
     * {@link org.apache.groovy.contracts.PreconditionViolation}.
     * {@code false}: the obligation is <em>already enforced</em> (see
     * {@code direct} for where) — no assertion is generated, and a violating
     * caller observes whatever the existing enforcement does (for example the
     * {@code NullPointerException} of an {@code Objects.requireNonNull}) rather
     * than a {@code PreconditionViolation}. The annotation remains the caller's
     * documented obligation, consumable by readers and tools (verifiers discharge
     * it at call sites regardless of where enforcement lives). An unwoven
     * precondition never contributes to generated assertions — including the
     * inherited precondition weaving of overriding methods.
     *
     * @return whether the precondition assertion is generated
     * @since 6.0.0
     */
    boolean woven() default true;

    /**
     * Information for readers and tools, with no effect on bytecode; ignored
     * (implicitly {@code true}) for woven preconditions. {@code true} (default):
     * a hand-written check enforces the obligation in this body. {@code false}:
     * the obligation is enforced by code this method executes — a validator call
     * such as {@code Objects.requireNonNull} or Guava's {@code Preconditions},
     * possibly transitively — so there is no check to find in this body. Most
     * users never set this; a verification or analysis tool unable to find the
     * claimed enforcement is the usual prompt.
     *
     * @return whether the body itself contains the enforcement
     * @since 6.0.0
     */
    boolean direct() default true;
}
