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

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

import org.apache.commons.contract.Context;
import org.apache.commons.contract.Processor;
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.StateDescriptor;
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.HttpContext;
import org.apache.slide.projector.context.ProjectorContext;
import org.apache.slide.projector.processor.ProcessException;
import org.apache.slide.projector.processor.SimpleProcessor;
import org.apache.slide.projector.processor.process.Process;
import org.apache.slide.projector.value.URI;

public class Link implements Processor {
	private final static String PROCESSOR = "processor";
	private final static String CONTINUE = "continue";
	private final static String PARAMETERS = "parameterS";
	
	private final static ParameterDescriptor[] parameterDescriptors = new ParameterDescriptor[] {
			new ParameterDescriptor(PROCESSOR, new ParameterMessage("link/parameter/processor"), new URIConstraints()),
			new ParameterDescriptor(Process.STEP, new ParameterMessage("link/parameter/step"), new StringConstraints(), null),
			new ParameterDescriptor(CONTINUE, new ParameterMessage("link/parameter/continue"), new BooleanConstraints(), Boolean.TRUE),
			new ParameterDescriptor(PARAMETERS, new ParameterMessage("link/parameter/parameters"), MapConstraints.UNCONSTRAINED, new HashMap())
	};
    private final static ResultDescriptor[] resultDescriptors = new ResultDescriptor[] {
            ResultDescriptor.OK
    };
	
	public Result process(Map parameter, Context context) throws Exception {
		URI uri = (URI)parameter.get(PROCESSOR); 
		boolean continueProcess = ((Boolean)parameter.get(CONTINUE)).booleanValue();
		Map parameterMap = (Map)parameter.get(PARAMETERS);
		Object step = parameter.get(Process.STEP);
		StringBuffer linkBuffer = new StringBuffer(128);
		if ( context instanceof HttpContext ) {
            linkBuffer.append(((HttpContext)context).getContextPath()).append(uri);
            boolean first = true;
            if ( continueProcess ) {
            	parameterMap.put(Projector.PROCESS_ID_PARAMETER, ((ProjectorContext)context).getProcessId());
            }
            if ( step != null ) {
            	parameterMap.put(Process.STEP, step);
            }
            for ( Iterator i = parameterMap.entrySet().iterator(); i.hasNext(); ) {
            	Map.Entry entry = (Map.Entry)i.next();
            	if ( first ) {
            		linkBuffer.append('?');
            		first = false;
            	} else {
            		linkBuffer.append('&');
            	}
        		linkBuffer.append(entry.getKey());
        		linkBuffer.append('=');
        		linkBuffer.append(entry.getValue());
            }
		} else {
            throw new ProcessException(new LocalizedError("httpContextRequired"));
        }
        return new Result(StateDescriptor.OK, SimpleProcessor.OUTPUT, new String(linkBuffer.toString()));
	}

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

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