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

import org.apache.cactus.*;
import org.apache.cactus.util.*;

import com.arsdigita.bebop.*;
import com.arsdigita.bebop.parameters.*;
import com.arsdigita.bebop.form.*;
import com.arsdigita.bebop.event.*;

import com.arsdigita.dispatcher.*;
import com.arsdigita.util.URLRewriter;

import javax.servlet.Servlet;
import javax.servlet.http.*;
import java.net.HttpURLConnection;
import java.util.*;

/**
 * Tests various BeBop form processing functionality
 * especially as per SDM bug #183490
 *
 * @author Anukul Kapoor
 */

public class BebopFormCactusTest extends ServletTestCase {

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

    Page page;
    Form form;
    PageState pagestate;
    FormData formdata;

    boolean firedInitEvent;
    boolean firedValidationEvent;
    boolean firedProcessEvent;
    boolean firedSubmissionEvent;

    Collection listenerLog;

    public BebopFormCactusTest(String theName) {
        super(theName);
    }

    /** This instantiates a new form as part of the testing fixture.
     */

    public void initForm() {
        form = new Form("test");

        form.add(new TextField(new StringParameter("s_param")));
        form.add(new TextField(new NumberParameter("n_param")));
        form.add(new Submit("send_form"));

        page = new Page("Test Form");

        page.add(new Label("Hello, World!"));
        page.add(form);
    }

    public void setUp() {
        // Workaround for "(root cause: Request context does not subclass
        // KernelRequestContext:
        // com.arsdigita.formbuilder.test.DummyRequestContext)"
        com.arsdigita.util.URLRewriter.clearParameterProviders();

        initForm();

        s = new BaseDispatcherServlet() {
                protected RequestContext authenticateUser
                    (HttpServletRequest req,
                     HttpServletResponse resp,
                     RequestContext ctx)
                    throws RedirectException {
                    return ctx;
                }

                public void dispatch(HttpServletRequest req,
                                     HttpServletResponse resp,
                                     RequestContext actx)
                    throws javax.servlet.ServletException, java.io.IOException {
                    pagestate = page.process(request,response);
                    formdata = form.process(pagestate);
                }
            };

    }

    /** Simple validation that Init listener is run
     */

    public void beginFormInit(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
    }

    public void testFormInit()
        throws javax.servlet.ServletException, java.io.IOException {
        firedInitEvent = false;

        form.addInitListener(
                             new FormInitListener() {
                                 public void init(FormSectionEvent e) {
                                     firedInitEvent = true;
                                 }
                             });

        page.lock();

        s.init(config);
        s.service(request,response);
        assertTrue(firedInitEvent);
    }

    public void setSubmissionVar(WebRequest req) {
        // this diddles the request to trigger a submission event
        req.addParameter(form.getModel().getMagicTagName(), "valid");
    }

    public void beginFormListeners(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /** Tests that Process, Validation, and Form listeners are run
     *  and Init listeners are NOT run
     *  when processing a form submission
     */

    public void testFormListeners()
        throws javax.servlet.ServletException, java.io.IOException {

        firedProcessEvent = false;
        firedValidationEvent = false;
        firedSubmissionEvent = false;
        firedInitEvent = false;

        form.addProcessListener(
                                new FormProcessListener() {
                                    public void process(FormSectionEvent e) {
                                        firedProcessEvent = true;
                                    }
                                });

        form.addValidationListener(
                                   new FormValidationListener() {
                                       public void validate(FormSectionEvent e) {
                                           firedValidationEvent = true;
                                       }
                                   });

        form.addSubmissionListener(
                                   new FormSubmissionListener() {
                                       public void submitted(FormSectionEvent e) {
                                           firedSubmissionEvent = true;
                                       }
                                   });

        form.addInitListener(
                             new FormInitListener() {
                                 public void init(FormSectionEvent e) {
                                     firedInitEvent = true;
                                 }
                             });


        page.lock();

        s.init(config);
        s.service(request,response);

        assertTrue(firedProcessEvent);
        assertTrue(firedValidationEvent);
        assertTrue(firedSubmissionEvent);
        assertTrue(! firedInitEvent);
    }

    /** Inner class for testing various listeners.
     *  Records processing by stashing integer into listenerLog
     *  and throws exception if needed.
     */

    class TestListener
        implements FormSubmissionListener, FormInitListener,
                   FormProcessListener, FormValidationListener    {
        int num;
        boolean throwsException;

        public TestListener(int n, boolean t) {
            num = n;
            throwsException = t;
        }

        public TestListener(int n) {
            this(n,false);
        }

        public void submitted(FormSectionEvent e)
            throws FormProcessException {
            listenerLog.add(new Integer(num));
            if(throwsException) {
                throw new FormProcessException("Fake exception");
            }
        }

        public void init(FormSectionEvent e)
            throws FormProcessException {
            listenerLog.add(new Integer(num));
            if(throwsException) {
                throw new FormProcessException("Fake exception");
            }
        }

        public void validate(FormSectionEvent e)
            throws FormProcessException {
            listenerLog.add(new Integer(num));
            if(throwsException) {
                throw new FormProcessException("Fake exception");
            }
        }

        public void process(FormSectionEvent e)
            throws FormProcessException {
            listenerLog.add(new Integer(num));
            if(throwsException) {
                throw new FormProcessException("Fake exception");
            }
        }
    }

    public void beginFormSubmissionEarlyException(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /**
     * Tests that all submission listeners are run despite an early exception
     */

    public void testFormSubmissionEarlyException()
        throws javax.servlet.ServletException, java.io.IOException {

        listenerLog = new ArrayList();

        form.addSubmissionListener(new TestListener(1,true));
        form.addSubmissionListener(new TestListener(2));
        form.addSubmissionListener(new TestListener(3));

        page.lock();

        s.init(config);
        s.service(request,response);

        assertTrue(listenerLog.contains(new Integer(1)));
        assertTrue(listenerLog.contains(new Integer(2)));
        assertTrue(listenerLog.contains(new Integer(3)));
    }

    public void beginFormSubmissionMiddleException(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /**
     * Tests that all submission listeners are run despite an exception
     */

    public void testFormSubmissionMiddleException()
        throws javax.servlet.ServletException, java.io.IOException {


        listenerLog = new ArrayList();

        form.addSubmissionListener(new TestListener(1));
        form.addSubmissionListener(new TestListener(2,true));
        form.addSubmissionListener(new TestListener(3));

        page.lock();

        s.init(config);
        s.service(request,response);

        assertTrue(listenerLog.contains(new Integer(1)));
        assertTrue(listenerLog.contains(new Integer(2)));
        assertTrue(listenerLog.contains(new Integer(3)));
    }

    public void beginFormSubmissionLateException(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /**
     * Tests that all submission listeners are run despite a late exception
     */

    public void testFormSubmissionLateException()
        throws javax.servlet.ServletException, java.io.IOException {

        listenerLog = new ArrayList();

        form.addSubmissionListener(new TestListener(1));
        form.addSubmissionListener(new TestListener(2));
        form.addSubmissionListener(new TestListener(3,true));

        page.lock();

        s.init(config);
        s.service(request,response);

        assertTrue(listenerLog.contains(new Integer(1)));
        assertTrue(listenerLog.contains(new Integer(2)));
        assertTrue(listenerLog.contains(new Integer(3)));
    }

    public void beginFormProcessListenerOrder(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /**
     * Tests that form process listeners are run in the order added
     */

    public void testFormProcessListenerOrder()
        throws javax.servlet.ServletException, java.io.IOException {

        listenerLog = new ArrayList();

        form.addProcessListener(new TestListener(1));
        form.addProcessListener(new TestListener(2));
        form.addProcessListener(new TestListener(3));

        page.lock();

        s.init(config);
        s.service(request,response);

        java.util.List l = (java.util.List) listenerLog;

        assertTrue(l.get(0).equals(new Integer(1)));
        assertTrue(l.get(1).equals(new Integer(2)));
        assertTrue(l.get(2).equals(new Integer(3)));
    }

    public void beginFormValidationException(WebRequest req) {
        req.setURL("localhost", "/enterprise", "/foo.jsp", "", null);
        initForm();
        setSubmissionVar(req);
    }

    /**
     * Tests that validation listeners are run despite an exception
     */

    public void testFormValidationException()
        throws javax.servlet.ServletException, java.io.IOException {

        listenerLog = new ArrayList();

        form.addValidationListener(new TestListener(1));
        form.addValidationListener(new TestListener(2,true));
        form.addValidationListener(new TestListener(3));

        page.lock();

        s.init(config);
        s.service(request,response);

        assertTrue(listenerLog.contains(new Integer(1)));
        assertTrue(listenerLog.contains(new Integer(2)));
        assertTrue(listenerLog.contains(new Integer(3)));
    }

}
