/*
 * Copyright (C) 2003-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.cms.ui.workflow;

import com.arsdigita.bebop.FormProcessException;
import com.arsdigita.bebop.Label;
import com.arsdigita.bebop.PageState;
import com.arsdigita.bebop.event.FormInitListener;
import com.arsdigita.bebop.event.FormProcessListener;
import com.arsdigita.bebop.event.FormSectionEvent;
import com.arsdigita.bebop.event.FormValidationListener;
import com.arsdigita.bebop.form.Option;
import com.arsdigita.bebop.form.RadioGroup;
import com.arsdigita.bebop.parameters.BooleanParameter;
import com.arsdigita.cms.ContentSection;
import com.arsdigita.cms.dispatcher.Utilities;
import com.arsdigita.cms.ui.ContentItemPage;
import com.arsdigita.cms.workflow.CMSTask;
import com.arsdigita.util.UncheckedWrapperException;
import com.arsdigita.web.RedirectSignal;
import com.arsdigita.web.URL;
import com.arsdigita.web.Web;
import com.arsdigita.workflow.simple.Engine;
import com.arsdigita.workflow.simple.Task;
import com.arsdigita.workflow.simple.TaskException;
import org.apache.log4j.Logger;

import java.util.Iterator;

/**
 * <p>A form that prompts the user to comment on and approve tasks and
 * then finishes the task if it was approved.</p>
 *
 * @author Justin Ross &lt;jross@redhat.com&gt;
 * @version $Id: //cms/dev/src/com/arsdigita/cms/ui/workflow/TaskFinishForm.java#12 $
 */
public final class TaskFinishForm extends CommentAddForm {
    public static final String versionId =
        "$Id: //cms/dev/src/com/arsdigita/cms/ui/workflow/TaskFinishForm.java#12 $" +
        "$Author: dennis $" +
        "$DateTime: 2004/04/07 16:07:11 $";

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

    private final TaskRequestLocal m_task;
    private final Label m_approvePrompt;
    private final RadioGroup m_approve;

    public TaskFinishForm(final TaskRequestLocal task) {
        super(task);

        m_task = task;

        m_approve = new RadioGroup(new BooleanParameter("approve"));
        m_approve.addOption
            (new Option("true", lz("cms.ui.workflow.task.approve")));
        m_approve.addOption
            (new Option("false", lz("cms.ui.workflow.task.reject")));

        m_approvePrompt = new Label(gz("cms.ui.workflow.task.approve_prompt"));

        addComponent(m_approvePrompt);
        addComponent(m_approve);

        addInitListener(new InitListener());
        addValidationListener(new ValidationListener());
        addProcessListener(new ProcessListener());
    }

    private class InitListener implements FormInitListener {
        public final void init(final FormSectionEvent e) {
            s_log.debug("Initializing task finish");

            final PageState state = e.getPageState();

            if (isVisible(state)) {
                final CMSTask task = m_task.getTask(state);

                if (requiresApproval(task)) {
                    m_approvePrompt.setVisible(state, true);
                    m_approve.setVisible(state, true);
                } else {
                    m_approvePrompt.setVisible(state, false);
                    m_approve.setVisible(state, false);
                }
            }
        }
    }

    private class ValidationListener implements FormValidationListener {
        public final void validate(final FormSectionEvent e)
                throws FormProcessException {
            s_log.debug("Validating task finish");

            final PageState state = e.getPageState();
            final CMSTask task = m_task.getTask(state);

            if (requiresApproval(task) && m_approve.getValue(state) == null) {
                throw new FormProcessException
                    (lz("cms.ui.workflow.task.approval_or_reject_required"));
            }
        }
    }

    private class ProcessListener implements FormProcessListener {
        public final void process(final FormSectionEvent e)
                throws FormProcessException {
            s_log.debug("Processing task finish");

            final PageState state = e.getPageState();
            final CMSTask task = m_task.getTask(state);
            boolean finishedTask = false;

            if (requiresApproval(task)) {
                s_log.debug("The task requires approval; checking to see " +
                            "if it's approved");

                // XXX I think the fact that this returns a Boolean is
                // the effect of broken parameter marshalling in
                // Bebop.
                final Boolean isApproved = (Boolean) m_approve.getValue(state);

                if (isApproved.equals(Boolean.TRUE)) {
                    s_log.debug("The task is approved; finishing the task");

                    try {
                        task.finish(Web.getContext().getUser());
                        finishedTask = true;
                    } catch (TaskException te) {
                        throw new UncheckedWrapperException(te);
                    }
                } else {
                    s_log.debug("The task is rejected; reenabling dependent " +
                                "tasks");

                    // Reenable the previous tasks.

                    final Iterator iter = task.getDependencies();

                    while (iter.hasNext()) {
                        final Task dependent = (Task) iter.next();

                        if (s_log.isDebugEnabled()) {
                            s_log.debug
                                ("Reenabling task " + dependent.getLabel());
                        }

                        dependent.enable();
                        dependent.save();
                    }
                }
            } else {
                s_log.debug("The task does not require approval; finishing " +
                            "it");

                try {
                    task.finish(Web.getContext().getUser());
                    finishedTask = true;
                } catch (TaskException te) {
                    throw new UncheckedWrapperException(te);
                }
            }
            if (finishedTask) {
                Iterator tasks = Engine.getInstance().getEnabledTasks(Web.getContext().getUser(),
                                                                      task.getParentID()).iterator();
                while (tasks.hasNext()) {
                    CMSTask thisTask = (CMSTask) tasks.next();
                    if (thisTask.getTaskType().equals(CMSTask.DEPLOY)) {
                        throw new RedirectSignal
                            (URL.there(state.getRequest(), 
                                       ContentItemPage.getItemURL(task.getItem(),
                                                                  ContentItemPage.PUBLISHING_TAB)),
                             true);
                    }
                }
                // redirect to /content-center if streamlined creation mode is active.
                if (ContentSection.getConfig().getUseStreamlinedCreation()) {
                        throw new RedirectSignal
                            (URL.there(state.getRequest(), 
                                       Utilities.getWorkspaceURL()),
                             true);
                }
                
            }
        }
    }

    private static boolean requiresApproval(final CMSTask task) {
        return !task.getTaskType().equals(CMSTask.AUTHOR);
    }
}
