/*
 * Copyright (C) 2001-2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (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.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.bebop;

import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.list.ListModelBuilder;
import com.arsdigita.bebop.list.ListCellRenderer;
import com.arsdigita.util.LockableImpl;
import com.arsdigita.xml.Element;
import com.arsdigita.globalization.GlobalizedMessage;

import java.util.Iterator;

/**
 * Displays validation errors for the page. These might have occured due to validation
 * listeners on some state parameters within the page.
 *
 *    @author Stanislav Freidin 
 *    @version $Id: //core-platform/dev/src/com/arsdigita/bebop/PageErrorDisplay.java#9 $
 */
public class PageErrorDisplay extends List  {

    public static final String versionId = "$Id: //core-platform/dev/src/com/arsdigita/bebop/PageErrorDisplay.java#9 $ by $Author: dennis $, $DateTime: 2004/04/07 16:07:11 $";

    private static final String COLOR = "color";

    /**
     * Constructs a new <code>PageErrorDisplay</code>.
     */
    public PageErrorDisplay() {
        this(new PageErrorModelBuilder());
    }

    /**
     * Constructs a new <code>PageErrorDisplay</code> from the errors
     * supplied by a list model builder.
     *
     * @param builder the {@link ListModelBuilder} that will supply the errors
     *
     */
    protected PageErrorDisplay(ListModelBuilder builder) {
        super(builder);
        setCellRenderer(new LabelCellRenderer());
        setTextColor("red");
        setClassAttr("pageErrorDisplay");
    }

    /**
     * Sets the HTML color of the error messages.
     *
     * @param c An HTML color, such as "#99CCFF" or "red"
     */
    public void setTextColor(String c) {
        setAttribute(COLOR, c);
    }

    /**
     * Gets the HTML color of the error messages.
     * @return the HTML color of the error messages.
     */
    public String getTextColor() {
        return getAttribute(COLOR);
    }

    /**
     * Determines if there are errors to display.
     *
     * @param state the current page state
     * @return <code>true</code> if there are any errors to display;
     * <code>false</code> otherwise.
     */
    protected boolean hasErrors(PageState state) {
        return(state.getErrors().hasNext());
    }

    /**
     * Generates the XML for this component. If the state has no errors
     * in it, does not generate any XML.
     *
     * @param state the current page state
     * @param parent the parent XML element
     */
    public void generateXML(PageState state, Element parent) {
        if(hasErrors(state))
            super.generateXML(state, parent);
    }

    // A private class which builds a ListModel based on form errors
    private static class PageErrorModelBuilder extends LockableImpl
        implements ListModelBuilder {

        public PageErrorModelBuilder() {
            super();
        }

        public ListModel makeModel(List l, PageState state) {
            return new StringIteratorModel(state.getErrors());
        }
    }

    // A ListModel which generates items based on an Iterator
    protected static class StringIteratorModel implements ListModel {

        private Iterator m_iter;
        private GlobalizedMessage m_error;
        private int m_i;

        public StringIteratorModel(Iterator iter) {
            m_iter = iter;
            m_error = null;
            m_i = 0;
        }

        public boolean next() {
            if(!m_iter.hasNext()) {
                m_i = 0;
                return false;
            }

            m_error = (GlobalizedMessage)m_iter.next();
            ++m_i;

            return true;
        }

        private void checkState() {
            if(m_i == 0) {
                throw new IllegalStateException (
                                                 "next() has not been called succesfully"
                                                 );
            }
        }

        public Object getElement() {
            checkState();
            return m_error;
        }

        public String getKey() {
            checkState();
            return Integer.toString(m_i);
        }
    }

    // A ListCellRenderer that renders labels
    private static class LabelCellRenderer implements ListCellRenderer {
        public Component getComponent(List list, PageState state, Object value,
                                      String key, int index, boolean isSelected) {
            return new Label((GlobalizedMessage)value);
        }
    }

}
