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


import com.arsdigita.formbuilder.util.GlobalizationUtil ; 


// We add a link back to the index page
import com.arsdigita.bebop.Link;

import com.arsdigita.formbuilder.FormBuilderDispatcher;

import com.arsdigita.formbuilder.SimpleQuestionnaire;
import com.arsdigita.formbuilder.PersistentWidget;
import com.arsdigita.formbuilder.PersistentTextField;
import com.arsdigita.formbuilder.PersistentTextArea;
import com.arsdigita.formbuilder.PersistentSingleSelect;
import com.arsdigita.formbuilder.PersistentMultipleSelect;
import com.arsdigita.formbuilder.PersistentCheckboxGroup;
import com.arsdigita.formbuilder.PersistentRadioGroup;
import com.arsdigita.formbuilder.PersistentDate;
import com.arsdigita.formbuilder.PersistentLabel;

import com.arsdigita.formbuilder.AttributeMetaData;

// For sharing persitent questionnaire across methods on a request basis
import com.arsdigita.bebop.RequestLocal;

// For the widget selections list
import com.arsdigita.bebop.List;
import com.arsdigita.bebop.list.ListModel;
import com.arsdigita.bebop.list.ListModelBuilder;

import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;

// For setting the page title dynamically
import com.arsdigita.bebop.event.PrintListener;
import com.arsdigita.bebop.event.PrintEvent;

// For storing the form_id
import com.arsdigita.bebop.parameters.BigDecimalParameter;
import com.arsdigita.bebop.parameters.StringParameter;
import com.arsdigita.bebop.parameters.IntegerParameter;

// For setting the default selection of the widget list

// For layout
import com.arsdigita.bebop.ColumnPanel;

import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.Form;
import com.arsdigita.bebop.FormData;
import com.arsdigita.bebop.MetaForm;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.form.Submit;
import com.arsdigita.bebop.form.TextField;

import com.arsdigita.bebop.parameters.NotEmptyValidationListener;

import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;

// When retrieving the questionnaire
import java.math.BigDecimal;
import com.arsdigita.domain.DataObjectNotFoundException;
import com.arsdigita.util.UncheckedWrapperException;

// Form validation
import com.arsdigita.bebop.event.FormValidationListener;
import com.arsdigita.bebop.event.FormSectionEvent;

// For toggling display of components on the page

// For redirection
import com.arsdigita.bebop.event.ActionListener;
import com.arsdigita.bebop.event.ActionEvent;

import com.arsdigita.formbuilder.util.FormBuilderUtil;

// logging
import org.apache.log4j.Logger;


/**
 * On this page the admin may add widgets to the persistent form. The
 * admin comes to this page after the FormPropertiesPage.
 *
 * @author Peter Marklund
 * @version $Id: //core-platform/dev/src/com/arsdigita/formbuilder/ui/FormBuildingPage.java#13 $
 *
 */
public class FormBuildingPage extends TemplatePage {

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

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

    private static FormBuildingPage s_instance;

    // The components on the page
    private Link m_indexLink; // link back to index page
    // Panel where questions are added and edited
    private ColumnPanel m_questionPanel;
    private ColumnPanel m_widgetListPanel;
    private List m_widgetList;
    private QuestionPropertiesForm m_questionForm;
    private MetaForm m_previewForm;
    private Form m_moveForm;
    private Form m_deleteForm;

    // Global Page State parameters
    public BigDecimalParameter m_formID;
    public StringParameter m_pageMode;
    public IntegerParameter m_questionPosition;
    public BigDecimalParameter m_widgetID;
    public StringParameter m_parameterName;

    // I keep single select and multiple select widgets in separate maps. If the process
    // listener supplies parameter metadata we check if the parameter is multiple or not
    // and use either of the maps depending on this
    private static HashMap s_singleValueWidgetMap = new HashMap();
    private static HashMap s_multipleValueWidgetMap = new HashMap();

    // Used in add, edit and parameter modes
    private RequestLocal m_widgetSelectionMap =
        new RequestLocal() {
            public Object initialValue(PageState pageState) {

                // If the listener has parameter data - check if the current parameter is mutliple
                // or not.
                if (FormBuildingPage.this.getQuestionnaire(pageState).listenerHasMetaData()) {

                    // Get the metadata of the current parameter
                    AttributeMetaData parameterMetaData =
                        getQuestionForm().getParameterMetaData(pageState);

                    if (parameterMetaData.isMultiple()) {
                        return s_multipleValueWidgetMap;
                    } else {
                        return s_singleValueWidgetMap;
                    }
                } else {
                    // No parameter data - provide a choice of both single and multiple widgets
                    HashMap widgetMap = new HashMap();
                    widgetMap.putAll(s_singleValueWidgetMap);
                    widgetMap.putAll(s_multipleValueWidgetMap);

                    return widgetMap;
                }
            }
        };

    static {

        s_singleValueWidgetMap.put(PersistentTextField.class.getName(), "Text Field");
        s_singleValueWidgetMap.put(PersistentTextArea.class.getName(), "Text Area");

        s_multipleValueWidgetMap.put(PersistentSingleSelect.class.getName(), "Single Option Select Box");
        s_multipleValueWidgetMap.put(PersistentMultipleSelect.class.getName(), "Multiple Option Select Box");
        s_multipleValueWidgetMap.put(PersistentCheckboxGroup.class.getName(), "Checkbox Group");
        s_multipleValueWidgetMap.put(PersistentRadioGroup.class.getName(), "Radio Group");

        s_singleValueWidgetMap.put(PersistentDate.class.getName(), "Date Widget");
    }

    // The questionnaire that we are editing
    private RequestLocal m_simpleQuestionnaire =
        new RequestLocal() {
            public Object initialValue(PageState pageState) {

                BigDecimal formID = FormBuildingPage.this.getFormID(pageState);
                SimpleQuestionnaire questionnaire;
                try {
                    questionnaire =
                        new SimpleQuestionnaire(formID);

                } catch (DataObjectNotFoundException e) {
                    throw new UncheckedWrapperException(e);
                }

                return questionnaire;
            }
        };

    /**
     * Private Constructor since we are using the Singleton design pattern
     */
    private FormBuildingPage() {
        super(getStaticTitle());
    }

    /**
     * Provide access to the single instance of this page.
     */
    public static FormBuildingPage instance() {

        if (s_instance == null) {
            s_instance = new FormBuildingPage();
        }

        return s_instance;
    }

    public static String getStaticTitle() {
        return "Manage Questions of a Questionnaire";
    }

    public String getRelativeURL() {
        return "build-form"  + FormBuilderDispatcher.getURLEnding();
    }

    protected void buildPage() {

        // Make the title dynamic
        setDynamicTitle();

        // Initialize and register the state parameters
        setupGlobalPageState();

        // Add all components to the page along with process listeners
        addPageComponents();

        // Add an action listener that will display either the question form
        // or the preview form
        addActionListener(getDisplayListener());

        // For redirecting to other pages
        addActionListener(getActionListener());
    }

    private void addPageComponents() {

        // Add top link back to the index page
        add(getIndexLink());

        // Add the question panel
        add(getQuestionPanel());

        // Add the preview form shown in view mode
        add(getPreviewForm());

        // Bottom link back to the index page
        add(getIndexLink());
    }

    private void setDynamicTitle() {

        // Make the title show the admin name of the form
        Label titleLabel = new Label(GlobalizationUtil.globalize("formbuilder.ui.manage_questions_of_a_form"));
        titleLabel.addPrintListener(
                                    new PrintListener() {
                                        public void prepare(PrintEvent e) {
                                            Label inner_titleLabel = (Label)e.getTarget();

                                            String adminName =
                                                FormBuildingPage.this.getQuestionnaire(e.getPageState()).getAdminName();

                                            inner_titleLabel.setLabel("Manage Questions of Form \"" + adminName + "\"");
                                        }
                                    }
                                    );
        setTitle(titleLabel);
    }

    /**
     * Make sure that page global data (form_id) is fetched from
     * the URL and added to the global page state.
     */
    private void setupGlobalPageState() {

        // Initialize the state parameters
        m_formID = new BigDecimalParameter("form_id");
        m_pageMode = new StringParameter("page_mode");
        m_questionPosition = new IntegerParameter("question_position");
        m_widgetID = new BigDecimalParameter("widget_id");
        m_parameterName = new StringParameter("parameter_name");

        // Keep the form_id in the global state of the page
        addGlobalStateParam(m_formID);

        // We need to preserver the page mode (one of add, edit, move, delete)
        addGlobalStateParam(m_pageMode);

        // Preserve the question position needed for add, move and delete
        addGlobalStateParam(m_questionPosition);

        // Preserver the widget_id needed for edit
        addGlobalStateParam(m_widgetID);

        // In parameter page mode we need the name of the parameter we are adding
        // a question for
        addGlobalStateParam(m_parameterName);
    }

    /*
     * Used for displaying either the question form or the preview form (in view mode).
     */
    private ActionListener getDisplayListener() {

        return new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    PageState pageState = e.getPageState();

                    String pageMode = FormBuildingPage.this.getPageMode(pageState);

                    if (pageMode == null || pageMode.equals("view") ||
                        FormBuildingPage.this.isSuccessfulSubmission(pageState)) {

                        displayPreviewForm(pageState);
                    } else {
                        displayQuestionPanel(pageState);

                        // We first unselect all components on the panel to then depending on the
                        // page mode select the ones we need
                        hideQuestionPanelComponents(pageState);

                        if (pageMode.equals("add") || pageMode.equals("parameter")) {
                            // There is selection of widgets
                            FormBuildingPage.this.getWidgetListPanel().setVisible(pageState, true);

                            // The form for specifying the new question
                            FormBuildingPage.this.getQuestionForm().setVisible(pageState, true);

                            // Set default selection of the widget list if selection is there
                            List widgetList = FormBuildingPage.this.getWidgetList();
                            if (!widgetList.isSelected(pageState)) {
                                String defaultKey = FormBuildingPage.this.getDefaultWidgetKey(pageState);
                                widgetList.setSelectedKey(pageState, defaultKey);
                            }

                        } else if (pageMode.equals("edit")) {

                            // Select the widget to be edited
                            selectWidget(pageState);

                            // Display only the question form with prefilled values
                            FormBuildingPage.this.getQuestionForm().setVisible(pageState, true);

                        } else if (pageMode.equals("move")) {

                            // Display only the move form
                            FormBuildingPage.this.getMoveForm().setVisible(pageState, true);

                        } else if (pageMode.equals("delete")) {

                            // Display only the delete form
                            FormBuildingPage.this.getDeleteForm().setVisible(pageState, true);
                        }
                    }
                }

                private void selectWidget(PageState pageState) {
                    Integer position =
                        FormBuildingPage.this.getQuestionPosition(pageState);

                    if (position == null) {
                        return;
                    }

                    // FIXME: what is the point of the following lines that I'm
                    // commenting out for now? -- 2002-11-26
//                     SimpleQuestionnaire questionnaire =
//                         FormBuildingPage.this.getQuestionnaire(pageState);

//                     String widgetClass =
//                         questionnaire.getQuestionWidget(position.intValue()).getClass().getName();
                }

                private void displayPreviewForm(PageState pageState) {
                    FormBuildingPage.this.getQuestionPanel().setVisible(pageState, false);
                    FormBuildingPage.this.getPreviewForm().setVisible(pageState, true);
                }

                private void displayQuestionPanel(PageState pageState) {
                    FormBuildingPage.this.getQuestionPanel().setVisible(pageState, true);
                    FormBuildingPage.this.getPreviewForm().setVisible(pageState, false);
                }

                private void hideQuestionPanelComponents(PageState pageState) {
                    FormBuildingPage.this.getWidgetListPanel().setVisible(pageState,false);
                    FormBuildingPage.this.getQuestionForm().setVisible(pageState, false);
                    FormBuildingPage.this.getMoveForm().setVisible(pageState, false);
                    FormBuildingPage.this.getDeleteForm().setVisible(pageState, false);
                }
            };
    }

    /**
     * Used for redirection to option page
     */
    private ActionListener getActionListener() {

        return new ActionListener() {

                public void actionPerformed(ActionEvent e) {

                    PageState pageState = e.getPageState();

                    // If we added or edited an OptionGroup redirect the admin
                    // to specify options, but only if the submission was successful
                    if ((getPageMode(pageState).equals("add") || getPageMode(pageState).equals("parameter") ||
                         getPageMode(pageState).equals("edit"))
                        && FormBuildingPage.this.isSuccessfulSubmission(pageState)) {

                        PersistentWidget widget = getQuestionForm().getPersistentWidget(pageState);

                        if (widget instanceof com.arsdigita.formbuilder.PersistentOptionGroup) {

                            // I am building a dummy link here just to be able to conveniently
                            // build the URL
                            Link redirectLink = new Link( new Label(GlobalizationUtil.globalize("formbuilder.ui.label_to_be_ignored")),  "url ignored");

                            redirectLink.setVar(OptionGroupPage.instance().m_formID.getName(),
                                                getFormID(pageState).toString());
                            redirectLink.setVar(OptionGroupPage.instance().m_widgetID.getName(),
                                                widget.getID().toString());
                            redirectLink.setVar(OptionGroupPage.instance().m_widgetClass.getName(),
                                                widget.getClass().getName());
                            redirectLink.setVar(OptionGroupPage.instance().m_nOptions.getName(),
                                                getQuestionForm().getNumberOfOptions(pageState));
                            redirectLink.setVar(OptionGroupPage.instance().m_pageMode.getName(),
                                                FormBuildingPage.this.getPageMode(pageState));

                            FormBuilderUtil.redirect(pageState,
                                                     OptionGroupPage.instance().getRelativeURL() +
                                                     redirectLink.getURLVarString());
                        }
                    }

                    // After a successful submission we go back to previewing the form
                    if(FormBuildingPage.this.isSuccessfulSubmission(pageState)) {
                        pageState.setValue(FormBuildingPage.this.m_pageMode, "view");
                    }
                }
            };
    }

    //*** Get Methods for the Components on the Page

    public Link getIndexLink() {

        if (m_indexLink == null) {
            m_indexLink = FormBuilderUtil.createIndexLink();
        }

        return m_indexLink;
    }

    public ColumnPanel getQuestionPanel() {

        if (m_questionPanel == null) {

            //  Use a column panel with two columns
            m_questionPanel = new ColumnPanel(2);

            // Indicate with a header the current action
            Label actionLabel = new Label("");
            actionLabel.setFontWeight(Label.BOLD);
            setDynamicActionLabel(actionLabel);
            m_questionPanel.add(actionLabel, ColumnPanel.FULL_WIDTH);

            // Add the widget selection list to the left
            m_questionPanel.add(getWidgetListPanel(), ColumnPanel.TOP);

            // Add the properties form to the right
            m_questionPanel.add(getQuestionForm(), ColumnPanel.TOP);

            // Add the move form that is only displayed in move mode
            m_questionPanel.add(getMoveForm(), ColumnPanel.FULL_WIDTH);

            // Add the delete form that is only displayed in delete mode
            m_questionPanel.add(getDeleteForm(), ColumnPanel.FULL_WIDTH);
        }

        return m_questionPanel;
    }

    private void setDynamicActionLabel(Label actionLabel) {

        actionLabel.addPrintListener(new PrintListener() {
                public void prepare(PrintEvent e) {

                    Label label = (Label)e.getTarget();
                    PageState pageState = e.getPageState();

                    if (getPageMode(pageState).equals("add")) {

                        // We are adding a question
                        // Indicate the position if there is one
                        if (getQuestionPosition(pageState) != null) {
                            label.setLabel( (String) GlobalizationUtil.globalize("formbuilder.ui.add_a_question_at_position").localize() + getQuestionPosition(pageState));
                        } else {
                            label.setLabel( (String) GlobalizationUtil.globalize("formbuilder.ui.add_a_question").localize());
                        }

                    } else if (getPageMode(pageState).equals("parameter")) {

                        label.setLabel( (String) GlobalizationUtil.globalize("formbuilder.ui.add_a_question_for_parameter").localize() + getParameterName(pageState));

                    } else if (getPageMode(pageState).equals("edit")) {

                        label.setLabel("Edit question \"" + getQuestionName(pageState) + "\"");

                    } else if (getPageMode(pageState).equals("move")) {

                        label.setLabel("Move Question \""  + getQuestionName(pageState) + "\"");

                    } else if (getPageMode(pageState).equals("delete")) {

                        label.setLabel("Delete Question \"" + getQuestionName(pageState) + "\"");
                    }
                }
            });
    }

    public ColumnPanel getWidgetListPanel() {

        if (m_widgetListPanel == null) {

            m_widgetListPanel = new ColumnPanel(1);

            // Add a header above the list
            Label widgetLabel = new Label(GlobalizationUtil.globalize("formbuilder.ui.select_widget"));
            widgetLabel.setFontWeight(Label.BOLD);
            m_widgetListPanel.add(widgetLabel);

            m_widgetListPanel.add(getWidgetList());
        }

        return m_widgetListPanel;
    }

    public List getWidgetList() {

        if (m_widgetList == null) {

            ListModelBuilder listModelBuilder =
                new ListModelBuilder() {
                    public ListModel makeModel(List list, PageState pageState) {

                        Map widgetMap =
                            FormBuildingPage.this.getWidgetSelectionMap(pageState);

                        return new WidgetSelectionListModel(widgetMap);
                    }

                    public boolean isLocked() {
                        return true;
                    }

                    public void lock() {
                        // This class has no data to lock
                    }
                };

            // We have to use a dynamic list here since the selection of widgets
            // is request dependent (depends on parameter metadata)
            m_widgetList = new List(listModelBuilder);
        }

        return m_widgetList;
    }

    private class WidgetSelectionListModel implements ListModel {

        private Map m_map;
        private Iterator m_keyIterator;
        private String m_currentKey;

        public WidgetSelectionListModel(Map map) {

            m_map = map;
            m_keyIterator = map.keySet().iterator();
        }

        public Object getElement() {

            return (String)m_map.get(m_currentKey);
        }

        public String getKey() {

            return m_currentKey;
        }

        public boolean next() {

            boolean hasNext = m_keyIterator.hasNext();

            if (hasNext) {
                m_currentKey = (String)m_keyIterator.next();
            }

            return hasNext;
        }
    }

    public QuestionPropertiesForm getQuestionForm() {

        if (m_questionForm == null) {
            m_questionForm = new QuestionPropertiesForm("question_properties");
        }

        return m_questionForm;
    }

    public MetaForm getPreviewForm() {

        if (m_previewForm == null) {

            m_previewForm = new PreviewForm(true,
                                            new PreviewFormConnector());
        }

        return m_previewForm;
    }

    private class PreviewFormConnector implements PreviewFormPageConnector {

        public SimpleQuestionnaire getQuestionnaire(PageState pageState) {

            return FormBuildingPage.this.getQuestionnaire(pageState);
        }
    }

    public Form getMoveForm() {

        if (m_moveForm == null) {
            m_moveForm = new Form("move_form");

            Label moveLabel = new Label(GlobalizationUtil.globalize("formbuilder.ui.move_question_to_position"));
            moveLabel.addPrintListener(new PrintListener() {
                    public void prepare(PrintEvent event) {
                        PageState pageState = event.getPageState();

                        int nQuestions = FormBuildingPage.this.getQuestionnaire(pageState).getNumberOfQuestions();

                        Label label = (Label)event.getTarget();

                        label.setLabel( (String) GlobalizationUtil.globalize("formbuilder.ui.move_question_to_position_1").localize() + nQuestions + ")");
                    }
                }
                                       );

            m_moveForm.add(moveLabel);
            TextField moveField = new TextField(new IntegerParameter("move_to_position"));
            moveField.addValidationListener(new NotEmptyValidationListener());

            m_moveForm.add(moveField);

            m_moveForm.add(new Submit("move"), ColumnPanel.FULL_WIDTH | ColumnPanel.CENTER);

            m_moveForm.addValidationListener(new FormValidationListener() {
                    public void validate(FormSectionEvent e) {

                        PageState pageState = e.getPageState();
                        FormData data = e.getFormData();

                        if (data == null) {
                            return;
                        }

                        // I can assume that the value is an integer here
                        // since it has already been successfully converted by the IntegerParameter
                        String parameterName = "move_to_position";
                        Integer value = (Integer)data.get(parameterName);

                        if (value == null) {
                            return;
                        }

                        if (value.intValue() < 1) {
                            data.addError(parameterName, "Position must be greater than 1");
                            return;
                        }

                        // Check that position is less than or equal to number of questions
                        int nQuestions = FormBuildingPage.this.getQuestionnaire(pageState).getNumberOfQuestions();

                        if (value.intValue() > nQuestions) {
                            data.addError(parameterName, "Position must be less than or equal to " + nQuestions);
                            return;
                        }
                    }
                });

            m_moveForm.addProcessListener(new FormProcessListener() {
                    public void process(FormSectionEvent e) {
                        FormData formData = e.getFormData();
                        PageState pageState = e.getPageState();

                        // Get the questionnaire
                        SimpleQuestionnaire questionnaire =
                            FormBuildingPage.this.getQuestionnaire(pageState);

                        // Get from and to positions
                        int fromPosition = FormBuildingPage.this.getQuestionPosition(pageState).intValue();
                        int toPosition = ((Integer)formData.get("move_to_position")).intValue();

                        // Move the question
                        questionnaire.moveQuestion(fromPosition, toPosition);
                    }
                });
        }

        return m_moveForm;
    }

    public Form getDeleteForm() {

        if (m_deleteForm == null) {
            m_deleteForm = new Form("delete_form");

            m_deleteForm.add(new Label(GlobalizationUtil.globalize("formbuilder.ui.you_are_about_to_delete_a_question")), ColumnPanel.FULL_WIDTH);

            m_deleteForm.add(new Submit("ok", "Ok"));
            m_deleteForm.add(new Submit("cancel", "Cancel"));

            m_deleteForm.addProcessListener(new FormProcessListener() {
                    public void process(FormSectionEvent e) {
                        FormData formData = e.getFormData();
                        PageState pageState = e.getPageState();

                        String okSubmit = formData.getString("ok");

                        if (okSubmit != null) {

                            // Get the questionnaire
                            SimpleQuestionnaire questionnaire =
                                FormBuildingPage.this.getQuestionnaire(pageState);

                            // Get the question position
                            int questionPosition =
                                FormBuildingPage.this.getQuestionPosition(pageState).intValue();

                            // Delete the question
                            questionnaire.removeQuestion(questionPosition);
                        }
                    }
                });
        }

        return m_deleteForm;
    }

    // In edit, move and delete mode we need the label of the question we are
    // acting on
    private PersistentLabel getQuestionLabel(PageState pageState) {

        SimpleQuestionnaire questionnaire = getQuestionnaire(pageState);

        return questionnaire.getQuestionLabel(getQuestionPosition(pageState).intValue());
    }

    // In edit mode we need the values of the widget for prefilling the form
    private PersistentWidget getQuestionWidget(PageState pageState) {

        SimpleQuestionnaire questionnaire = getQuestionnaire(pageState);

        return questionnaire.getQuestionWidget(getQuestionPosition(pageState).intValue());
    }

    // *** Attribute Methods for the Page

    public BigDecimal getFormID(PageState pageState) {

        return (BigDecimal)pageState.getValue(m_formID);
    }

    /**
     * Returns add mode per default
     */
    public String getPageMode(PageState pageState) {

        String value = (String)pageState.getValue(m_pageMode);

        return value == null ? "view" : value;
    }

    public Integer getQuestionPosition(PageState pageState) {

        return (Integer)pageState.getValue(m_questionPosition);
    }

    public String getQuestionName(PageState pageState) {

        return getQuestionLabel(pageState).getLabel();
    }

    public BigDecimal getWidgetID(PageState pageState) {

        return (BigDecimal)pageState.getValue(m_widgetID);
    }

    public String getParameterName(PageState pageState) {

        String parameterName =
            (String)pageState.getValue(m_parameterName);

        // No parameter name supplied in the URL - try to fetch
        // it from the persistent widget
        if (parameterName == null && getPageMode(pageState).equals("edit")) {
            PersistentWidget widget =
                getQuestionnaire(pageState).getQuestionWidget(getQuestionPosition(pageState).intValue());

            parameterName = widget.getParameterName();
        }

        return parameterName;
    }

    /**
     * Return the class name of the currently selected Widget
     */
    public String getWidgetSelection(PageState pageState) {

        String className = null;

        if (getPageMode(pageState).equals("add") || getPageMode(pageState).equals("parameter")) {
            className = (String)m_widgetList.getSelectedKey(pageState);

            if (className == null) {
                className = getDefaultWidgetKey(pageState);
            }

        } else if (getPageMode(pageState).equals("edit")) {
            return getQuestionForm().getPersistentWidget(pageState).getClass().getName();
        }

        return className;
    }

    public String getWidgetSelectionName(PageState pageState) {

        return (String)getWidgetSelectionMap(pageState).get(getWidgetList().getSelectedKey(pageState));
    }

    public SimpleQuestionnaire getQuestionnaire(PageState pageState) {

        return (SimpleQuestionnaire)m_simpleQuestionnaire.get(pageState);
    }

    public boolean isSuccessfulSubmission(PageState pageState) {

        FormData formData = null;

        // Depending on the page mode we need to query different forms
        if (getPageMode(pageState).equals("move")) {
            formData = getMoveForm().getFormData(pageState);
        } else if (getPageMode(pageState).equals("delete")) {
            formData = getDeleteForm().getFormData(pageState);
        } else {
            formData = getQuestionForm().getFormData(pageState);
        }

        return FormBuilderUtil.isSuccessfulSubmission(formData);
    }

    private Map getWidgetSelectionMap(PageState pageState) {
        return (Map)m_widgetSelectionMap.get(pageState);
    }

    private String getDefaultWidgetKey(PageState pageState) {

        String key = null;

        AttributeMetaData parameterData =
            getQuestionForm().getParameterMetaData(pageState);

        // If there is no meta data we have text field as default
        // Use text field also if this is a single value parameter
        if (parameterData == null || !parameterData.isMultiple()) {
            key = PersistentTextField.class.getName();
        } else if (parameterData.isMultiple()) {
            // Multiple parameter - display select box default
            key =  PersistentCheckboxGroup.class.getName();
        }

        return key;
    }
}
