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

import java.util.Arrays;
import java.util.Iterator;

import com.arsdigita.bebop.parameters.*;
import com.arsdigita.bebop.*;
import com.arsdigita.bebop.event.*;
import com.arsdigita.tools.junit.framework.BaseTestCase;
import com.arsdigita.util.HttpServletDummyRequest;

public class ArrayParameterTest extends BaseTestCase {

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

    public static final String ARRAY_PARAM = "ArrayParameter";

    /**
       Constructs a test with the specified name.

       @param name Name of the test
    */
    protected FormData _formData;
    protected ArrayParameter _array;
    protected FormModel _model;
    protected HttpServletDummyRequest _httpRequest;
    protected ParameterListener _validationListener;

    public ArrayParameterTest(String id) {
        super(id);
    }

    /**
       Sets up the test fixture.
    */

    protected void setUp() {
        _array =  new ArrayParameter(ARRAY_PARAM);
        _httpRequest = new HttpServletDummyRequest();

        _model = new FormModel("Validation Test");

        try {
            _model.addFormParam(_array);
        } catch (Exception e) {
            fail("Exception in trying to add parameter model" + e.getMessage());
        }

    }

    protected void createFormData(boolean isSubmission) {
        try {
            _formData = new FormData(_model, _httpRequest, isSubmission);
        } catch (FormProcessException fpe) {
            fail("Form Process Exception trying to create FormData");
        }
    }

    /**
       Tears down the text fixture.
       Called after every test case method.
    */
    protected void tearDown() {
        _formData=null;
        _array=null;
        _model=null;
        _httpRequest=null;
        _validationListener=null;
    }

    public void testOneElement() {
        // The value of this test greatly depends on that the one element in
        // the array looks like an encoded array, i.e. starts with a comma
        String[] specifiedValues= { ",one" };

        _httpRequest.setParameterValues(ARRAY_PARAM, specifiedValues);
        ParameterData p = createParameterData(_array);
        assertTrue("The parameter data should be a string array",
                   p.getValue() instanceof String[]);
        assertTrue(Arrays.equals(specifiedValues, (Object[]) p.getValue()));
    }

    public void testTwoElements() {

        String[] specifiedValues= { "one", "two" };

        _httpRequest.setParameterValues(ARRAY_PARAM, specifiedValues);
        ParameterData p = createParameterData(_array);
        assertTrue("The parameter data should be a string array",
                   p.getValue() instanceof String[]);
        assertTrue(Arrays.equals(specifiedValues, (Object[]) p.getValue()));
    }

    public void testMarshalling() {
        String[] specifiedValues = { ",one", ".,two", "three,a", "four.b",
                                     "five,", "six." };
        String value = _array.marshal(specifiedValues);
        _httpRequest.setParameterValues(ARRAY_PARAM, value);
        ParameterData p = createParameterData(_array);
        assertTrue(p.getValue() instanceof String[]);

        assertTrue(Arrays.equals(specifiedValues, (Object[]) p.getValue()));
        assertEquals(_array.marshal(specifiedValues), value);
        assertTrue(Arrays.equals(specifiedValues, (Object[]) _array.unmarshal(value)));
        assertTrue("The parameter data should be an array", p.isArray());
    }

    public void testMarshallingInteger() {
        _array.setElementParameter(new IntegerParameter("Integer"));
        assertEquals("Integer", _array.getName());
        int n = 5;
        String[] specifiedValues = new String[n];
        Integer[] values = new Integer[n];
        for (int i=0; i<n; i++) {
            values[i] = new Integer(i);
            specifiedValues[i] = values[i].toString();
        }
        _httpRequest.setParameterValues(_array.getName(), specifiedValues);
        ParameterData p = createParameterData(_array);
        assertTrue(p.getValue() instanceof Integer[]);
        assertTrue(Arrays.equals(values, (Object[]) p.getValue()));
        // Now try the same with a marshalled value
        _httpRequest.removeParameterValue(_array.getName());
        _httpRequest.setParameterValues(_array.getName(), p.marshal());
        p = createParameterData(_array);
        assertTrue(Arrays.equals(values, (Object[]) p.getValue()));
    }

    public void testElementValidation() {
        _array.getElementParameter().addParameterListener(
                                                          new NotNullValidationListener());
        String[] specifiedValues = { "one", "", null, "two" };
        _httpRequest.setParameterValues(ARRAY_PARAM, specifiedValues);
        ParameterData p = createParameterData(_array);
        _array.lock();
        try {
            _array.validate(p);
        } catch(FormProcessException e) {
            // expected
        }
        assertTrue(!p.isValid());
        int cnt = 0;
        for (Iterator i = p.getErrors(); i.hasNext(); i.next(), cnt++);
        // FIXME: This should really be 2, but the validation process bails out
        // after the first error in the values is found (the empty string) and
        // doesn't check the second erroneous value, the null
        assertEquals(1, cnt);
    }


    /**
     *  The next two tests make sure that even if the element
     *  begins with the SEP_CHAR value (in this case, a "-").  We
     *  need to test to make sure that we get back the same element that
     *  we started with.
     */
    public void testOneNegativeElement() {
        String[] values = {"-2"};
        String marshaledElement = _array.marshal(values);
        String[] unmarshaledElement = (String[]) _array.unmarshal(marshaledElement);
        final boolean equals = Arrays.equals(values,unmarshaledElement);
        if (!equals) {
            fail("The only argument went in negative and came out positive!. Was: " +  values[0] + " Now: " + unmarshaledElement[0]);
        }

    }


    public void testOnePositiveElement() {
        String[] values = {"2"};
        String marshaledElement = _array.marshal(values);
        Object unmarshaledElement = _array.unmarshal(marshaledElement);
        assertTrue("The only argument went in positive and came out negative",
                   Arrays.equals(values, (String[]) _array.unmarshal
                                 (marshaledElement)));

    }

    private ParameterData createParameterData(ParameterModel m) {
        return m.createParameterData(_httpRequest, true);
    }

}
