/*
 * 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.xml.Element;
import com.arsdigita.util.Assert;

import com.arsdigita.bebop.util.BebopConstants;

/**
 * Generates a list of segments. Each segment consists of a header
 * (which could be any Bebop component) and a body (which, likewise,
 * could be any component). The entire <code>SegmentedPanel</code>
 * look roughly like this:
 *
 * <blockquote><pre><code>
 * ----------------------
 * Header 1
 * ----------------------
 * Body 1
 * More Body 1
 * Even more Body 1
 * ----------------------
 * Header 2
 * ----------------------
 * Body 2
 * More Body 2
 * Even more Body 2
 * </code></pre></blockquote>
 *
 * Typically, the body of each segment will be a {@link SimpleContainer}
 * which contains many other components
 * <p>
 * The XML generated by this component looks something like this:
 * <blockquote><pre><code>
 * &lt;bebop:segmentedPanel&gt;
 *   &lt;bebop:segment id="foo"&gt;
 *     &lt;bebop:segmentHeader&gt;
 *       &lt;aRandomHeaderComponent/&gt;
 *       &lt;anotherRandomHeaderComponent/&gt;
 *       ...
 *     &lt;/bebop:segmentHeader&gt;
 *     &lt;bebop:segmentBody&gt;
 *       &lt;aRandomBodyComponent&gt;
 *       &lt;anotherRandomBodyComponent&gt;
 *       ...
 *     &lt;/bebop:segmentBody&gt;
 *   &lt;/bebop:segment&gt;
 *   ...
 * &lt;/bebop:segmentedPanel&gt;
 * </code></pre></blockquote>
 *
 * @author Michael Pih 
 * @version $Revision: #10 $ $Date: 2004/04/07 $
 * @see #generateXML(PageState, Element)
 */
public class SegmentedPanel extends SimpleContainer
    implements BebopConstants {

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

    public static final String HEADER_CLASS = "seg-header";

    /**
     * Construct a new <code>SegmentedPanel</code>
     */
    public SegmentedPanel() {
        super();
    }

    /**
     * Construct a new <code>SegmentedPanel</code>
     *
     * @param idAttr the XSL ID attribute for this container
     * @see SimpleComponent#setIdAttr(String)
     */
    public SegmentedPanel(String idAttr) {
        this();
        setIdAttr(idAttr);
    }

    /**
     * Add a segment to this container
     *
     * @param header the component that will act as the header
     * @param body the component that will act as the body
     * @return the new segment
     */
    public Segment addSegment(Component header, Component body) {
        Segment s = new Segment(header, body);
        add(s);
        return s;
    }

    /**
     * Add a segment to this container.
     *
     * @param segmentID the XSL ID attribute for the new segment.
     * @param header the component that will act as the header.
     * @param body the component that will act as the body
     * @return the new segment
     */
    public Segment addSegment(String segmentID, Component header, Component body) {
        Segment s = addSegment(header, body);
        s.setIdAttr(segmentID);
        return s;
    }

    /**
     * Add a segment to this container.
     *
     * @param segmentID the XSL ID attribute for the new segment. The XSL template
     *   for this component will render the correct header based on the ID attribute
     * @param body the component that will act as the body
     * @return the new segment
     */
    public Segment addSegment(String segmentID, Component body) {
        return addSegment(segmentID, null, body);
    }

    /**
     * Add and return a new empty segment.
     *
     * @return a new empty segment that is part of the panel.
     */
    public Segment addSegment() {
        Segment result = new Segment();
        add(result);
        return result;
    }

    /**
     * Generate the XML for this component, as described above
     *
     * @param state represents the page state for the current request
     * @param parent the parent XML element
     */
    public void generateXML(PageState state, Element parent) {
        if ( isVisible(state) ) {
            Element panel = parent.newChildElement(BEBOP_SEG_PANEL, BEBOP_XML_NS);
            exportAttributes(panel);
            super.generateXML(state, panel);
        }
    }

    /**
     * A single Segment within this container
     */
    public static class Segment extends SimpleContainer {

        private SimpleContainer m_header, m_body;

        /**
         * Construct an empty <code>Segment</code>
         */
        public Segment() {
            this(null, null);
        }

        /**
         * Construct a new <code>Segment</code>
         *
         * @param header the component which will act as the header; the XSL
         *   class attribute for the component will be set to {@link #HEADER_CLASS}.
         *   Typically, this component will be a {@link Label}
         * @param body the component which represents the body of the segment, Typically,
         *   this component will be a {@link SimpleContainer} or a panel of some sort
         */
        public Segment(Component header, Component body) {
            super();
            if(header != null) addHeader(header);
            if(body!= null) add(body);
        }

        /**
         * Construct a new <code>Segment</code> with no header
         *
         * @param body the component which represents the body of the segment, Typically,
         *   this component will be a {@link SimpleContainer} or a panel of some sort
         */
        public Segment(Component body) {
            this(null, body);
        }

        /**
         * Add a header component.
         *
         * @param c an additional header component
         */
        public void addHeader(Component c) {
            Assert.assertNotLocked(this);
            if(m_header == null) {
                m_header = new SimpleContainer(BEBOP_SEG_HEADER, BEBOP_XML_NS);
                super.add(m_header);
            }
            m_header.add(c);
        }

        /**
         * Add a component to the body of this segment
         */
        public void add(Component c) {
            Assert.assertNotLocked(this);
            if(m_body == null) {
                m_body = new SimpleContainer(BEBOP_SEG_BODY, BEBOP_XML_NS);
                super.add(m_body);
            }
            m_body.add(c);
        }

        /**
         * Add a component to the body of this segment
         */
        public void add(Component c, int constraints) {
            add(c);
        }

        /**
         * Generate the XML for this segment
         *
         * @param state the current page state
         * @param parent the parent XML element
         */
        public void generateXML(PageState state, Element parent) {
            if(isVisible(state)) {
                Element seg = parent.newChildElement(BEBOP_SEGMENT, BEBOP_XML_NS);
                exportAttributes(seg);
                super.generateXML(state, seg);
            }
        }
    }

}
