package org.apache.slide.projector.processor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.commons.contract.Context;
import org.apache.commons.contract.Result;
import org.apache.commons.contract.constraints.MapConstraints;
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.constraints.TextConstraints;
import org.apache.slide.projector.value.Streamable;
import org.apache.slide.projector.value.Text;

public class TemplateMapRenderer extends TemplateRenderer {
    private static Logger logger = Logger.getLogger(TemplateMapRenderer.class.getName());

    private ParameterDescriptor[] parameterDescriptors;
    private ResultDescriptor[] resultDescriptors = new ResultDescriptor[] { 
            new ResultDescriptor(
            StateDescriptor.OK_DESCRIPTOR,
            new ResultEntryDescriptor[]{
                new ResultEntryDescriptor(OUTPUT, new LocalizedMessage("templateMapRenderer/result/output"), 
                        TextConstraints.UNCONSTRAINED)
            })};

    public void configure(Streamable config) throws ConfigurationException {
        super.configure(config);
        MapConstraints mapValueDescriptor = new MapConstraints();
        List parameterDescriptorList = new ArrayList();
        for ( Iterator i = parameterDescriptions.iterator(); i.hasNext(); ) {
            ParameterDescriptor entryDescriptor = (ParameterDescriptor)i.next();
            // add all map parameters to optional parameters 
            if ( entryDescriptor.getName() == FRAGMENT ) {
                parameterDescriptorList.add(entryDescriptor);
            } else {
                if ( entryDescriptor.isRequired() ) {
                    mapValueDescriptor.addEntryDescriptor(new ParameterDescriptor(entryDescriptor.getName(), new ParameterMessage("templateMapRenderer/mapEntry"), entryDescriptor.getConstraints()));
                } else {
                    mapValueDescriptor.addEntryDescriptor(new ParameterDescriptor(entryDescriptor.getName(), new ParameterMessage("templateMapRenderer/mapEntry"), entryDescriptor.getConstraints(), entryDescriptor.getDefaultValue() ));
                    parameterDescriptorList.add(new ParameterDescriptor(entryDescriptor.getName(), (ParameterMessage)entryDescriptor.getDescription(), entryDescriptor.getConstraints(), null));
                }
            }
        }
        parameterDescriptorList.add(new ParameterDescriptor(SimpleProcessor.INPUT, new ParameterMessage("templateMapRenderer/input"), mapValueDescriptor));
        parameterDescriptors = (ParameterDescriptor[])parameterDescriptorList.toArray(new ParameterDescriptor[parameterDescriptorList.size()]);
    }

    public Result process(Map parameter, Context context) throws Exception {
        String fragment = (String)parameter.get(FRAGMENT);
        Template template = getRequiredFragment(fragment);
        StringBuffer buffer = new StringBuffer(template.getLength());
        Map parameterMap = new HashMap();
        parameterMap.putAll(parameter);
        for ( Iterator j = ((Map)parameter.get(SimpleProcessor.INPUT)).entrySet().iterator(); j.hasNext(); ) {
        	Map.Entry entry = (Map.Entry)j.next();
        	if ( entry.getValue() != null ) {
        		parameterMap.put(entry.getKey(), entry.getValue());
        	}
        }
        template.evaluate(buffer, parameterMap);
        return new Result(OK, OUTPUT, new Text(buffer.toString(), template.getContentType(), false));
    }

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

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