/*
 * 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.event.ChangeEvent;
import com.arsdigita.bebop.event.ChangeListener;
import com.arsdigita.util.Assert;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.log4j.Logger;

/**
 * A modal container is a container that manages visibility for a set of
 * components. It allows only one of its children to be visible. One of its
 * children can be selected as the default visible component. If none is
 * selected the child with index equal to zero is used. The modal container
 * sets the appropriate default and PageState-based visibility for its
 * children.
 *
 * @author Archit Shah
 **/
public class ModalContainer extends SimpleContainer implements Resettable {
    public static final String versionId =
        "$Id: //core-platform/dev/src/com/arsdigita/bebop/ModalContainer.java#11 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

    private static final Logger s_log = Logger.getLogger(ModalContainer.class);

    private int m_default = 0;

    private ArrayList m_changeListeners = new ArrayList();

    public ModalContainer() { 
        super();
    }

    public ModalContainer(String tagName,
                          String xmlns) {
        super(tagName, xmlns);
    }

    public void register(Page p) {
        Assert.assertNotLocked(this);

        Iterator it = children();
        while (it.hasNext()) {
            // guaranteed to have at least one child
            Component child = (Component) it.next();
            if (m_default != indexOf(child)) {
                p.setVisibleDefault(child, false);
            }
        }
    }

    public void setDefaultComponent(Component c) {
        Assert.assertNotLocked(this);

        if (!contains(c)) {
            add(c);
        }

        m_default = indexOf(c);
    }

    public Component getDefaultComponent() {
        return get(m_default);
    }

    public void setVisibleComponent(PageState state, Component c) {
        s_log.debug("changing visibility");

        Component old = getVisibleComponent(state);
        try {
            old.setVisible(state, false);
        } catch (NullPointerException e) {
            // rare(?) situation where something messes with the
            // visibility of the components.  don't have to do anything
        }
        c.setVisible(state, true);
        if (old!=c) {
            Iterator listeners = m_changeListeners.iterator();
            while (listeners.hasNext()) {
                ChangeListener l = (ChangeListener) listeners.next();
                l.stateChanged(new ChangeEvent(this, state));
            }
        }
    }

    public Component getVisibleComponent(PageState state) {
        Iterator it = children();
        while (it.hasNext()) {
            Component c = (Component) it.next();
            if (c.isVisible(state)) { return c; }
        }

        return null;
    }

    /**
     * Makes the next component in a wizard sequence visible while hiding all
     * other components.
     **/
    public void next(PageState state) {
        setVisibleComponent(state,
                            get(indexOf(getVisibleComponent(state)) + 1));
    }

    /**
     * Makes the previous component in a wizard sequence visible while hiding
     * all other components.
     **/
    public void previous(PageState state) {
        setVisibleComponent(state,
                            get(indexOf(getVisibleComponent(state)) - 1));
    }

    /**
     * Resets the container to display the default component.
     **/
    public void reset(PageState state) {
        setVisibleComponent(state, getDefaultComponent());
    }

    /**
     * Adds a listener that is called whenever this container's mode
     * (i.e., visible component) is changed using setVisibleComponent().
     **/
    public void addModeChangeListener(ChangeListener cl) {
        Assert.assertNotLocked(this);

        m_changeListeners.add(cl);
    }
}
