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

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

import org.apache.commons.contract.Context;
import org.apache.commons.contract.Information;
import org.apache.commons.contract.Processor;
import org.apache.commons.contract.Result;
import org.apache.commons.contract.descriptor.ParameterDescriptor;
import org.apache.commons.contract.descriptor.ResultDescriptor;
import org.apache.commons.contract.i18n.ParameterMessage;
import org.apache.commons.i18n.LocalizedError;
import org.apache.slide.projector.Projector;
import org.apache.slide.projector.constraints.URIConstraints;
import org.apache.slide.projector.context.ProjectorContext;
import org.apache.slide.projector.engine.ProcessorManager;
import org.apache.slide.projector.processor.ProcessException;
import org.apache.slide.projector.processor.process.Process;
import org.apache.slide.projector.store.FormStore;
import org.apache.slide.projector.value.URI;
import org.apache.slide.projector.value.URIValue;

public class Test implements Processor {
    private final static URI FORM_PROCESSOR = new URIValue("formGenerator");
    private final static URI RESULT_RENDERER = new URIValue("formResult");
    private final static String PROCESSOR = "processor";

    private final static String FORM_STEP = "form";
    private final static String PROCESS_STEP = "process";
    private final static String RESULT_STEP = "result";
    
    private final static ParameterDescriptor[] parameterDescriptors = new ParameterDescriptor[] {
			new ParameterDescriptor(PROCESSOR, new ParameterMessage("test/parameter/processor"), new URIConstraints(), null),
	};
    private final static ResultDescriptor[] resultDescriptors = new ResultDescriptor[] {
            ResultDescriptor.OK
    };

	public Result process(Map parameter, Context context) throws Exception {
		URI processorUri = ProcessorManager.getInstance().getURI(this); 
		((ProjectorContext)context).setBookmark(processorUri);
		Object uri = parameter.get(PROCESSOR); 
        if ( uri == null || uri == null ) {
        	uri = (URI)context.getStore(Projector.SESSION_STORE).get(PROCESSOR, context);
        }
        if ( uri == null ) {
        	throw new ProcessException(new LocalizedError("test/noProcessorSpecified"));
        }
        ((ProjectorContext)context).setProcess((URI)uri);
    	context.getStore(Projector.SESSION_STORE).put(PROCESSOR, uri, context);
    	Object stepResource = (Object)context.getStore(Projector.FORM_STORE).get(Process.STEP, context);
    	String step;
    	if ( stepResource == null ) {
    		step = FORM_STEP;
    	} else {
    		step = stepResource.toString();
    	}
		((ProjectorContext)context).setStep(step);
		Processor formProcessor = ProcessorManager.getInstance().getProcessor(FORM_PROCESSOR);
        Processor resultRenderer = ProcessorManager.getInstance().getProcessor(RESULT_RENDERER);
        Processor processor = ProcessorManager.getInstance().getProcessor((URI)uri);
    	parameter.put(Control.ACTION, uri);
        parameter.put(ControlComposer.LOCALE, ProcessorManager.getInstance().process(ProcessorManager.LOCALE_RESOLVER, context.getStore(Projector.REQUEST_HEADER_STORE).get("accept-language", context), context));
        parameter.put(FormGenerator.TARGET_STEP, PROCESS_STEP);
        Result result = null;
        if ( step.equals(FORM_STEP) ) {
        	result = formProcessor.process(parameter, context);
        } else if ( step.equals(PROCESS_STEP) ) {
        	parameter.putAll(((Map)((FormStore)context.getStore(Projector.FORM_STORE)).getDomain()));
        	Result processorResult = ProcessorManager.process(processor, parameter, context);
        	if ( hasErrors(context.getInformations()) ) {
            	((ProjectorContext)context).setStep(FORM_STEP);
        		((FormStore)context.getStore(Projector.FORM_STORE)).put(ControlComposer.VALIDATE, Boolean.TRUE, context);
        		result = formProcessor.process(parameter, context);
        	} else {
        		Map resultParameters = new HashMap();
        		resultParameters.put("state", new String(processorResult.getState()));
        		result = ProcessorManager.process(resultRenderer, resultParameters, context);
        		((FormStore)context.getStore(Projector.FORM_STORE)).clear(context);
        	}
        } else {
    		((FormStore)context.getStore(Projector.FORM_STORE)).clear(context);
        	return Result.OK;
        }
        return result;
	}

    protected boolean hasErrors(List informations) {
        for ( Iterator i = informations.iterator(); i.hasNext(); ) {
        	Information info = (Information)i.next();
        	if ( info.getSeverity() == Information.ERROR ) {
                return true;
            }
        }
        return false;
    }

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

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