/*
 *  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.causeway.applib.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Collects together all layout hints for a property of a domain object.
 *
 * @see ActionLayout
 * @see CollectionLayout
 * @see DomainObjectLayout
 * @see Property
 *
 * @since 1.x {@index}
 * @see org.apache.causeway.applib.annotation.ParameterLayout
 */
@Inherited
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@DomainObject(nature=Nature.MIXIN, mixinMethod = "prop") // meta annotation, only applies at class level
@Domain.Include // meta annotation, in support of meta-model validation
public @interface PropertyLayout {

    /**
     * Indicates the css class that a property should have, to
     * allow more targeted styling in <code>application.css</code>.
     *
     * @see ActionLayout#cssClass()
     * @see ParameterLayout#cssClass()
     * @see CollectionLayout#cssClass()
     * @see DomainObjectLayout#cssClass()
     */
    String cssClass()
            default "";

    /**
     * Description of this property, eg to be rendered in a tooltip.
     *
     * @see ActionLayout#describedAs()
     * @see ParameterLayout#describedAs()
     * @see CollectionLayout#describedAs()
     * @see DomainObjectLayout#describedAs()
     */
    String describedAs()
            default "";


    /**
     * Specifies the <b>id</b> of associated <i>FieldSet</i>.
     *
     * <p>
     * A <i>FieldSet</i> is a layout component for property grouping, that can either be specified via
     * a <code>Xxx.layout.xml</code> file (with <code>Xxx</code> the domain object name) or is
     * inferred by the framework via annotations (aka the programming model).
     * <i>FieldSet</i>s are represented in-memory and requires a framework internal unique id per domain
     * object type.
     * </p>
     * <p>
     * Following 2 scenarios have slightly different behavior:
     * </p>
     *
     * <h1>XML layout is present</h1>
     * <p>
     * When a XML layout is present, every <i>FieldSet</i> <b>id</b> is either explicitly specified in
     * the file or may be inferred from a non-empty <b>name</b>.
     * If the <b>name</b> is empty "" or missing, then the <b>id</b> within the file is mandatory.
     * </p><p>
     * If this <i>Property</i> is not already explicitly listed within the XML layout, we lookup the
     * associated <i>FieldSet</i> in the XML layout file first matching by <b>id</b>
     * using {@code @PropertyLayout(fieldSetId=...)} if any, then falling back to matching by (friendly)
     * <b>name</b> using @PropertyLayout(fieldSetName=...)} if any.
     * </p>
     *
     * <h1>XML layout is absent</h1>
     * <p>
     * We reify (in-memory) the associated <i>FieldSet</i> using {@code @PropertyLayout(fieldSetId=...)}
     * (if present) as its <b>id</b> and using {@code @PropertyLayout(fieldSetId=...)} as its (friendly)
     * <b>name</b>.
     * While if no <b>id</b> is provided an <b>id</b> is inferred from the (friendly) <b>name</b>, in which
     * case the (friendly) <b>name</b> must not be empty.
     * Whereas if no (friendly) <b>name</b> is provided a (friendly) <b>name</b> is inferred from the
     * <b>id</b>, in which case the <b>id</b> must not be empty.
     * </p><p>
     * With {@code @PropertyLayout(sequence=...)} the relative position within that <i>FieldSet</i> can be
     * specified.
     * </p>
     *
     * @see Action#choicesFrom()
     * @see ActionLayout#fieldSetId()
     * @see ActionLayout#fieldSetName()
     * @see PropertyLayout#fieldSetName()
     * @see PropertyLayout#sequence()
     */
    String fieldSetId()
            default "__infer";

    /**
     * Specifies the <b>friendly-name</b> of associated <i>FieldSet</i>.
     * <p>
     * Explicitly specifying an empty "" <b>friendly-name</b> will suppress the <i>FieldSet</i>'s label
     * from being rendered.
     * </p>
     * <p>
     * For a more in depth description see {@link PropertyLayout#fieldSetId()}.
     * </p>
     *
     * @see Action#choicesFrom()
     * @see ActionLayout#fieldSetId()
     * @see ActionLayout#fieldSetName()
     * @see PropertyLayout#fieldSetId()
     * @see PropertyLayout#sequence()
     */
    String fieldSetName()
            default "__infer";

    /**
     * Indicates where in the UI the property
     * should <i>not</i> be visible.
     *
     * @see ActionLayout#hidden()
     * @see CollectionLayout#hidden()
     */
    Where hidden()
            default Where.NOT_SPECIFIED;

    /**
     * In forms, positioning of the label (left, top or none) relative to the property value.
     *
     * <p>
     * If not specified, the default depends upon the property value's
     * datatype (including whether the field is {@link #multiLine()}.
     * </p>
     *
     * @see #multiLine()
     * @see ParameterLayout#labelPosition()
     */
    LabelPosition labelPosition()
            default LabelPosition.NOT_SPECIFIED;

    /**
     * For string properties (and parameters), render as a text area over specified number of lines.
     *
     * <p>
     *     If set to &gt; 1, then {@link #labelPosition()} defaults to
     *     {@link LabelPosition#TOP top}.
     * </p>
     *
     * @see ParameterLayout#multiLine()
     */
    int multiLine()
            default -1;

    /**
     * Name of this property (overriding the name derived from its name in code).
     *
     * <p>
     * A typical use case is if the desired name is a reserved Java keyword, such as `default` or `package`.
     * </p>
     *
     * @see ActionLayout#named()
     * @see ParameterLayout#named()
     * @see CollectionLayout#named()
     * @see DomainObjectLayout#named()
     * @see DomainServiceLayout#named()
     */
    String named()
            default "";

    /**
     * Whether this property should be used to construct the navigable chain of breadcrumbs in the UI.
     *
     * <p>
     *     Only one property can be annotated as such per domain class.
     * </p>
     */
    Navigable navigable()
            default Navigable.NOT_SPECIFIED;

    /**
     * How the properties of this domain object are be edited, either {@link PromptStyle#DIALOG dialog} or {@link PromptStyle#INLINE inline}.
     */
    PromptStyle promptStyle()
            default PromptStyle.NOT_SPECIFIED;

    /**
     * Indicates that the value held by the property never changes over time, even when other properties of the object
     * do change.
     *
     * <p>
     *     Setting this attribute to <tt>RepaintPolicy.NO_REPAINT</tt> is used as a hint to the viewer to not repaint
     *     the property after an AJAX update of some other property/ies of the object have changed.
     *     This is primarily for performance, eg can improve the user experience when rendering PDFs/blobs.
     * </p>
     *
     * <p>
     *     Note that for this to work, the viewer will also ensure that none of the property's parent component
     *     (such as a tab group panel) are re-rendered.
     * </p>
     *
     * <p>
     *     Design note: we considered implementing this an "immutable" flag on the {@link Property } annotation
     *     (because this flag is typically appropriate for immutable/unchanging properties of a domain object).
     *     However, we decided not to do that, on the basis that it might be interpreted as having a deeper impact
     *     within the framework than simply a hint for rendering.
     * </p>
     */
    Repainting repainting()
            default Repainting.NOT_SPECIFIED;


    /**
     * The order of this member relative to other members in the same (layout) group,
     * given in <i>Dewey-decimal</i> notation.
     * <p>
     * Also governs slot-in order for the layout group that collects all unreferenced <i>Properties</i>,
     * unless overwritten via application scoped config option that enforced alphabetical order:
     * <br>
     * {@code causeway.applib.annotation.propertyLayout.sequencePolicyIfUnreferenced}
     * <p>
     * An alternative is to use the <code>Xxx.layout.xml</code> file,
     * where <code>Xxx</code> is the domain object name.
     * @see ActionLayout#sequence()
     * @see CollectionLayout#sequence()
     */
    String sequence()
            default "";

    /**
     * The typical entry length of a field, use to determine the optimum width
     * for display.
     *
     * <p>
     *     Note: the Wicket viewer does not use this information.
     * </p>
     *
     * @see ParameterLayout#typicalLength()
     */
    int typicalLength()
            default -1;

}

