//  Copyright 2004 The Apache Software Foundation
//
// Licensed 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.tapestry.valid;

import java.util.List;

import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRender;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.form.IFormComponent;

/**
 * Interface used to track validation errors in forms and {@link IFormComponent}s (including
 * {@link org.apache.tapestry.form.AbstractTextField}and its subclasses).
 * <p>
 * In addition, controls how fields that are in error are presented (they can be marked in various
 * ways by the delegate; the default implementation adds two red asterisks to the right of the
 * field).
 * <p>
 * The interface is designed so that a single instance can be shared with many instances of
 * {@link IFormComponent}.
 * <p>
 * Starting with release 1.0.8, this interface was extensively revised (in a non-backwards
 * compatible way) to move the tracking of errors and invalid values (during a request cycle) to the
 * delegate. It has evolved from a largely stateless conduit for error messages into a very stateful
 * tracker of field state.
 * <p>
 * Starting with release 1.0.9, this interface was <em>again</em> reworked, to allow tracking of
 * errors in {@link IFormComponent form components}, and to allow unassociated (with any field)
 * errors to be tracked.
 * <p>
 * <b>Fields vs. Form Components </b> <br>
 * For most simple forms, these terms are pretty much synonymous. Your form will render normally,
 * and each form component will render only once. Some of your form components will be
 * {@link ValidField}components and handle most of their validation internally (with the help of
 * {@link IValidator}objects). In addition, your form listener may do additional validation and
 * notify the validation delegate of additional errors, some of which are associated with a
 * particular field, some of which are unassociated with any particular field.
 * <p>
 * But what happens if you use a {@link org.apache.tapestry.components.Foreach}or
 * {@link org.apache.tapestry.form.ListEdit}inside your form? Some of your components will render
 * multiple times. In this case you will have multiple <em>fields</em>. Each field will have a
 * unique field name (you can see this in the generated HTML). It is this field name that the
 * delegate keys off of, which means that some fields generated by a component may have errors and
 * some may not, it all works fine (with one exception).
 * <p>
 * <b>The Exception </b> <br>
 * The problem is that a component doesn't know its field name until its <code>render()</code>
 * method is invoked (at which point, it allocates a unique field name from the
 * {@link org.apache.tapestry.IForm#getElementId(org.apache.tapestry.form.IFormComponent)}. This is
 * not a problem for the field or its {@link IValidator}, but screws things up for the
 * {@link FieldLabel}.
 * <p>
 * Typically, the label is rendered <em>before</em> the corresponding form component. Form
 * components leave their last assigned field name in their
 * {@link IFormComponent#getName() name property}. So if the form component is in any kind of loop,
 * the {@link FieldLabel}will key its name, {@link IFormComponent#getDisplayName() display name}
 * and error status off of its last renderred value. So the moral of the story is don't use
 * {@link FieldLabel}in this situation.
 * 
 * @author Howard Lewis Ship
 */

public interface IValidationDelegate
{
    /**
     * Invoked before other methods to configure the delegate for the given form component. Sets the
     * current field based on the {@link IFormComponent#getName() name}of the form component (which
     * is almost always a {@link ValidField}).
     * <p>
     * The caller should invoke this with a parameter of null to record unassociated global errors
     * (errors not associated with any particular field).
     * 
     * @since 1.0.8
     */

    public void setFormComponent(IFormComponent component);

    /**
     * Returns true if the current component is in error (that is, had bad input submitted by the
     * end user).
     * 
     * @since 1.0.8
     */

    public boolean isInError();

    /**
     * Returns the string submitted by the client as the value for the current field.
     * 
     * @since 1.0.8
     */

    public String getFieldInputValue();

    /**
     * Returns a {@link List}of {@link IFieldTracking}, in default order (the order in which
     * fields are renderred). A caller should not change the values (the List is immutable). May
     * return null if no fields are in error.
     * 
     * @since 1.0.8
     */

    public List getFieldTracking();

    /**
     * Resets any tracking information for the current field. This will clear the field's inError
     * flag, and set its error message and invalid input value to null.
     * 
     * @since 1.0.8
     */

    public void reset();

    /**
     * Clears all tracking information.
     * 
     * @since 1.0.10
     */

    public void clear();

    /**
     * Clears all errors, but maintains user input. This is useful when a form has been submitted
     * for a semantic other than "process this data". A common example of this is a dependent drop
     * down list; selecting an option in one drop down list forces a submit to repopulate the
     * options in a second, dependent drop down list.
     * <p>
     * In these cases, the user input provided in the request is maintained, but any errors should
     * be cleared out (to prevent unwanted error messages and decorations).
     * 
     * @since 3.0.1
     */

    public void clearErrors();

    /**
     * Records the user's input for the current form component. Input should be recorded even if
     * there isn't an explicit error, since later form-wide validations may discover an error in the
     * field.
     * 
     * @since 3.0
     */

    public void recordFieldInputValue(String input);

    /**
     * The error notification method, invoked during the rewind phase (that is, while HTTP
     * parameters are being extracted from the request and assigned to various object properties).
     * <p>
     * Typically, the delegate simply invokes {@link #record(String, ValidationConstraint)}or
     * {@link #record(IRender, ValidationConstraint)}, but special delegates may override this
     * behavior to provide (in some cases) different error messages or more complicated error
     * renderers.
     */

    public void record(ValidatorException ex);

    /**
     * Records an error in the current field, or an unassociated error if there is no current field.
     * 
     * @param message
     *            message to display (@see RenderString}
     * @param constraint
     *            the constraint that was violated, or null if not known
     * @since 1.0.9
     */

    public void record(String message, ValidationConstraint constraint);

    /**
     * Records an error in the current component, or an unassociated error. The maximum flexibility
     * recorder.
     * 
     * @param errorRenderer
     *            object that will render the error message (@see RenderString}. The object should
     *            implement a reasonable <code>toString()</code> as well, to allow the error
     *            message to be rendered using an Insert component, or used where full markup is not
     *            allowed.
     * @param constraint
     *            the constraint that was violated, or null if not known
     */

    public void record(IRender errorRenderer, ValidationConstraint constraint);

    /**
     * Invoked before the field is rendered. If the field is in error, the delegate may decorate the
     * field in some way (to highlight its error state).
     */

    public void writePrefix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
            IValidator validator);

    /**
     * Invoked just before the &lt;input&gt; element is closed. The delegate can write additional
     * attributes. This is often used to set the CSS class of the field so that it can be displayed
     * differently, if in error (or required).
     * 
     * @since 1.0.5
     */

    public void writeAttributes(IMarkupWriter writer, IRequestCycle cycle,
            IFormComponent component, IValidator validator);

    /**
     * Invoked after the form component is rendered, so that the delegate may decorate the form
     * component (if it is in error).
     */

    public void writeSuffix(IMarkupWriter writer, IRequestCycle cycle, IFormComponent component,
            IValidator validator);

    /**
     * Invoked by a {@link FieldLabel}just before writing the name of the form component.
     */

    public void writeLabelPrefix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle);

    /**
     * Invoked by a {@link FieldLabel}just after writing the name of the form component.
     */

    public void writeLabelSuffix(IFormComponent component, IMarkupWriter writer, IRequestCycle cycle);

    /**
     * Returns true if any form component has errors.
     */

    public boolean getHasErrors();

    /**
     * Returns the {@link IFieldTracking}for the current component, if any. Useful when displaying
     * error messages for individual fields.
     * 
     * @since 3.0.2
     */
    public IFieldTracking getCurrentFieldTracking();
}