/*
 * $Header: /home/cvspublic/jakarta-slide/projector/src/java/org/apache/slide/projector/processor/form/Form.java,v 1.8 2004/11/28 13:54:06 dflorey Exp $
 * $Revision: 1.8 $
 * $Date: 2004/11/28 13:54:06 $
 *
 * ====================================================================
 *
 * Copyright 2004 The Apache Software Foundation 
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.apache.slide.projector.processor.form;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.contract.Context;
import org.apache.commons.contract.Result;
import org.apache.commons.contract.constraints.BooleanConstraints;
import org.apache.commons.contract.constraints.MapConstraints;
import org.apache.commons.contract.constraints.StringConstraints;
import org.apache.commons.contract.descriptor.ParameterDescriptor;
import org.apache.commons.contract.descriptor.ResultDescriptor;
import org.apache.commons.contract.descriptor.ResultEntryDescriptor;
import org.apache.commons.contract.descriptor.StateDescriptor;
import org.apache.commons.contract.i18n.ParameterMessage;
import org.apache.commons.i18n.LocalizedMessage;
import org.apache.slide.projector.Projector;
import org.apache.slide.projector.constraints.AnyConstraints;
import org.apache.slide.projector.constraints.URIConstraints;
import org.apache.slide.projector.engine.ProcessorManager;
import org.apache.slide.projector.processor.ConfigurationException;
import org.apache.slide.projector.processor.process.Process;
import org.apache.slide.projector.value.Streamable;
import org.apache.slide.projector.value.URI;

/**
 * The Form class
 * 
 */
public class Form extends ControlComposer {
	public final static String CONTROL_IDENTIFIER = "control:";
    public final static String TRIGGER_IDENTIFIER = "trigger:";

    private ParameterDescriptor[] parameterDescriptors;
    
    private final static ResultDescriptor []resultDescriptors = new ResultDescriptor[] {
            new ResultDescriptor(new StateDescriptor(DEFAULT_STATE, new LocalizedMessage("form/state/default")),
                    new ResultEntryDescriptor[]{
                    new ResultEntryDescriptor(OUTPUT, new LocalizedMessage("form/output"), AnyConstraints.UNCONSTRAINED)
            }),
            new ResultDescriptor(new StateDescriptor(VALID_STATE, new LocalizedMessage("form/state/default")),
                    new ResultEntryDescriptor[]{
                    new ResultEntryDescriptor(OUTPUT, new LocalizedMessage("form/output"), AnyConstraints.UNCONSTRAINED)
            }),
            new ResultDescriptor(new StateDescriptor(INVALID_STATE, new LocalizedMessage("form/state/default")),
                    new ResultEntryDescriptor[]{
                    new ResultEntryDescriptor(OUTPUT, new LocalizedMessage("form/output"), AnyConstraints.UNCONSTRAINED)
            })};

    public Result process(Map parameter, Context context) throws Exception {
        Object formResult = context.getStore(Projector.FORM_STORE).get(FormHandler.RESULT, context);
    	if ( formResult instanceof Result ) {
            if ( !((Result)formResult).getState().equals(VALID_STATE) &&
                    !((Result)formResult).getState().equals(INVALID_STATE) &&
                    !((Result)formResult).getState().equals(DEFAULT_STATE) ) {
                ((Result)formResult).setState(DEFAULT_STATE);  
            }
            return (Result)formResult;  
    	}
    	Object a = parameter.get(ACTION); 
    	URI actionUri = (URI)a;
        Locale locale = ((Locale)context.getStore(Projector.SESSION_STORE).get(LOCALE, context));
    	List informations = context.getInformations();
        parameter.put(HANDLER, ProcessorManager.getInstance().process(ProcessorManager.URL, parameter.get(HANDLER), context));
        List controlDescriptions = new ArrayList();
        List triggerDescriptions = new ArrayList();
        for (int i = 0; i < parameterDescriptors.length; i++) {
        	String parameterName = parameterDescriptors[i].getName(); 
        	Object value = parameter.get(parameterName);
            if (parameterName.startsWith(CONTROL_IDENTIFIER)) {
            	((Map)value).put(CONTROL_NAME, parameterName);
            	controlDescriptions.add(value);
            } else if (parameterName.startsWith(TRIGGER_IDENTIFIER)) {
            	((Map)value).put(TRIGGER_NAME, parameterName);
            	triggerDescriptions.add(value);
            }
        }
        parameter.put(ControlComposer.CONTROL_DESCRIPTIONS, controlDescriptions.toArray());
        parameter.put(ControlComposer.TRIGGER_DESCRIPTIONS, triggerDescriptions.toArray());
        ProcessorManager.prepareValues(super.getParameterDescriptors(), parameter, context);
        Result controlComposerResult = super.process(parameter, context);
        Object[] generatedControls = (Object [])controlComposerResult.getResultEntries().get(GENERATED_CONTROLS);
        for ( int i = 0; i < generatedControls.length; i++ ) {
        	Iterator j = ((Map)generatedControls[i]).entrySet().iterator();
        	Map.Entry entry = (Map.Entry)j.next();
        	parameter.put(entry.getKey(), entry.getValue());
        }
        Object[] generatedTriggers = (Object [])controlComposerResult.getResultEntries().get(GENERATED_TRIGGERS);
        for ( int i = 0; i < generatedTriggers.length; i++ ) {
        	Iterator j = ((Map)generatedTriggers[i]).entrySet().iterator();
        	Map.Entry entry = (Map.Entry)j.next();
        	parameter.put(entry.getKey(), entry.getValue());
        }
    	parameter.put(RENDERED_ERRORS, controlComposerResult.getResultEntries().get(RENDERED_ERRORS));
        Template template = defaultTemplate;
        String state = controlComposerResult.getState();
        if ( state == VALID_STATE && validTemplate != null ) {
            template = validTemplate;
        } else if ( state == INVALID_STATE && invalidTemplate != null ) {
            template = invalidTemplate;
        }
        return new Result(state, OUTPUT, renderFragment(template, parameter));
    }

    public void configure(Streamable config) throws ConfigurationException {
        super.configure(config);
        ParameterDescriptor[] parentParameterDescriptors = super.getParameterDescriptors();
        int counter = 0;
        List parameterList = new ArrayList();
        for (int i = 0; i < parentParameterDescriptors.length; i++) {
            if (parentParameterDescriptors[i].getName().startsWith(CONTROL_IDENTIFIER)) {
                parameterList.add(new ParameterDescriptor(parentParameterDescriptors[i].getName(),
                        new ParameterMessage("form/control"),
                        new MapConstraints(new ParameterDescriptor[] {
                            new ParameterDescriptor(CONTROL, new ParameterMessage("form/control"), new URIConstraints()),
                            new ParameterDescriptor(CONTROL_CONTAINER, new ParameterMessage("form/controlContainer"),  new URIConstraints(), null),
                            new ParameterDescriptor(Control.ACTION, new ParameterMessage("control/action"), new URIConstraints(), null),
                            new ParameterDescriptor(Control.PARAMETER, new ParameterMessage("control/parameter"), new StringConstraints())
                        })));
            } else if (parentParameterDescriptors[i].getName().startsWith(TRIGGER_IDENTIFIER)) {
                    parameterList.add(new ParameterDescriptor(parentParameterDescriptors[i].getName(),
                            new ParameterMessage("form/trigger"),
                            new MapConstraints(new ParameterDescriptor[] {
                                new ParameterDescriptor(TRIGGER, new ParameterMessage("form/trigger"), new URIConstraints()),
                                new ParameterDescriptor(TRIGGER_CONTAINER, new ParameterMessage("form/triggerContainer"),  new URIConstraints(), null),
                                new ParameterDescriptor(Trigger.ACTION, new ParameterMessage("trigger/action"), new URIConstraints(), null),
	        					new ParameterDescriptor(Trigger.VALIDATE, new ParameterMessage("trigger/validate"), new BooleanConstraints(), Boolean.TRUE),
                                new ParameterDescriptor(Process.STEP, new ParameterMessage("trigger/step"),  new AnyConstraints(), null)
                            })));
            } else if (!parentParameterDescriptors[i].getName().equals(FRAGMENT) 
            		&& !parentParameterDescriptors[i].getName().equals(CONTROL_DESCRIPTIONS)
            		&& !parentParameterDescriptors[i].getName().equals(TRIGGER_DESCRIPTIONS)
					&& !parentParameterDescriptors[i].getName().equals(RENDERED_ERRORS)
					&& !parentParameterDescriptors[i].getName().equals(HANDLER)
					&& !parentParameterDescriptors[i].getName().equals(METHOD)) {
                parameterList.add(parentParameterDescriptors[i]);
            }
        }
        parameterList.add(new ParameterDescriptor(HANDLER, new ParameterMessage("form/handler"), new URIConstraints(), Projector.DEFAULT_FORM_HANDLER));
        parameterList.add(new ParameterDescriptor(METHOD, new ParameterMessage("form/method"), new StringConstraints(methods), new String(POST)));
        parameterList.add(new ParameterDescriptor(ACTION, new ParameterMessage("form/action"), new URIConstraints()));
        parameterDescriptors = (ParameterDescriptor[])parameterList.toArray(new ParameterDescriptor[parameterList.size()]);
    }

    public ParameterDescriptor[] getParameterDescriptors() {
        return parameterDescriptors;
    }

    public ResultDescriptor[] getResultDescriptors() {
        return resultDescriptors;
    }
}