/*
 * 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.formbuilder;


// The class that we are making persistent
import com.arsdigita.bebop.form.OptionGroup;
import com.arsdigita.bebop.form.Option;

// Manages associations with child components
import com.arsdigita.formbuilder.util.PersistentContainerHelper;

// All ACSObjects have a unique id
import com.arsdigita.persistence.OID;
import com.arsdigita.persistence.DataObject;
import com.arsdigita.persistence.metadata.ObjectType;

// Every PersistentComponentFactory can create a Bebop Component
import com.arsdigita.bebop.Component;

// Thrown if the underlying DataObject with given id cannot be found
import com.arsdigita.domain.DataObjectNotFoundException;

// ACS 5 uses Log4J for logging
import org.apache.log4j.Logger;

// Used for the Options
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import com.arsdigita.util.Assert;


/**
 * This class is responsible for persisting Bebop OptionGroups. The OptionGroup
 * is saved with the save() method. To resurrect the OptionGroup, use the constructor
 * taking the id of the saved OptionGroup and then invoke createComponent().
 *
 * @author Peter Marklund
 * @version $Id: //core-platform/dev/src/com/arsdigita/formbuilder/PersistentOptionGroup.java#10 $
 *
 */
public abstract class PersistentOptionGroup extends PersistentWidget {

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

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

    // Just like the PersistentFormSection We delegate the association
    // with the child components to this object
    private PersistentContainerHelper m_container =
        new PersistentContainerHelper(this);

    /**
     * BASE_DATA_OBJECT_TYPE represents the full name of the
     * underlying DataObject of this class.
     */
    public static final String BASE_DATA_OBJECT_TYPE =
        "com.arsdigita.formbuilder.Widget";

    // *** Constructors -------------

    /**
     * Constructor that creates a new OptionGroup domain object that
     * can be saved to the database later on.
     */
    public PersistentOptionGroup(String typeName) {
        super(typeName);
    }

    public PersistentOptionGroup(ObjectType type) {
        super(type);
    }

    public PersistentOptionGroup(DataObject obj) {
        super(obj);
    }

    /**
     * Extending classes can use this constructor to set the sub class
     * id and object type.
     */
    public PersistentOptionGroup(OID oID)
        throws DataObjectNotFoundException {

        super(oID);
    }


    public void delete() {
        clearOptions();
        super.delete();
    }

    /**
     * Create a sub class of OptionGroup. This method
     * must be implemented by sub clases.
     */
    public abstract Component createComponent();


    // *** Public API

    public void addOption(PersistentOption option) {

        m_container.addComponent(option);
    }

    public void addOption(PersistentOption option, boolean selected) {

        m_container.addComponent(option);
        setOptionSelected(option, selected);
    }

    public void addOption(PersistentOption option, int position) {

        m_container.addComponent(option, position);
    }

    public void addOption(PersistentOption option, int position, boolean selected) {

        m_container.addComponent(option, position);
        setOptionSelected(option, selected);
    }

    public void removeOption(PersistentOption option) {

        m_container.removeComponent(option);
    }

    // this is only used for single selection option groups
    private final static String TOO_MANY_OPTIONS_SELECTED =
        "Only one option may be selected by default on this option group.";

    public void setOptionSelected(PersistentOption option, boolean selected) {

        if (!isMultiple()) {
            // only one option may be selected
            // to this selected list better be empty
            Assert.assertTrue(getSelectedOptions().size() == 0, TOO_MANY_OPTIONS_SELECTED);
        }

        m_container.setComponentSelected(option, selected);
    }

    public abstract boolean isMultiple();

    /**
     * Will remove the association with the options and also attempt
     * to delete the options themselves.
     */
    public void clearOptions() {

        // We need to fetch the options so that we can delete them too
        Iterator optionIter = m_container.getComponents().iterator();

        // Delete the association with the options
        m_container.clearComponents();

        // Delete the options themselves
        while (optionIter.hasNext()) {

            PersistentComponentFactory componentFactory =
                (PersistentComponentFactory)optionIter.next();

            componentFactory.delete();
        }
    }

    /**
     * Returns an iterator over the PersistentOption objects contained in this
     * option group
     */
    public Collection getOptions() {

        return m_container.getComponents();
    }

    protected List getSelectedOptions() {
        return m_container.getSelectedComponents();
    }

    //*** Attribute metadata

    /**
     * I am overriding this method since I don't want default value to be
     * supplied on the add/edit form of PersistentOptionGroups
     */
    public AttributeMetaDataList getAttributeMetaData() {

        AttributeMetaDataList list = new AttributeMetaDataList();

        list.add(new AttributeMetaData("parameterName", "HTML parameter name", true)); // required

        return list;
    }

    protected void addDataToComponent(Component component) {

        OptionGroup optionGroup = (OptionGroup)component;

        // Add all options to the option group
        Iterator optionIter = getOptions().iterator();
        while(optionIter.hasNext()) {

            PersistentOption optionFactory = (PersistentOption)optionIter.next();

            optionGroup.addOption((Option)optionFactory.createComponent());
        }

        // Set all options that are selected
        Iterator selectedIter = getSelectedOptions().iterator();
        while (selectedIter.hasNext()) {

            PersistentOption optionFactory = (PersistentOption)selectedIter.next();

            optionGroup.setOptionSelected((Option)optionFactory.createComponent());
        }
    }
}
