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

import java.util.ArrayList;
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.Processor;
import org.apache.commons.contract.Result;
import org.apache.commons.contract.constraints.ArrayConstraints;
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.URIConstraints;
import org.apache.slide.projector.context.ProjectorContext;
import org.apache.slide.projector.processor.SimpleProcessor;
import org.apache.slide.projector.processor.xml.XPathQuery;
import org.apache.slide.projector.value.DocumentValue;
import org.apache.slide.projector.value.MultipleStreamable;
import org.apache.slide.projector.value.Streamable;
import org.apache.slide.projector.value.URI;
import org.jdom.xpath.XPath;

/**
 */
public class ResultResolver implements Processor {
	private final static String URI_ENTRY = "uri";
	private final static String INSTRUCTIONS = "instructions";
	private final static String INCLUDE_CONTENT = "includeContent";
	private final static String CONTENT_ENTRY = "content";

	private final static ParameterDescriptor[] parameterDescriptors = 
		new ParameterDescriptor[] {
			new ParameterDescriptor(
					SimpleProcessor.INPUT, 
					new ParameterMessage("resultResolver/paramter/input"), 
					new ArrayConstraints(new MapConstraints(
							new ParameterDescriptor(URI_ENTRY, 
							new ParameterMessage("resultResolver/parameter/input/uri"), 
							new URIConstraints())))),
			new ParameterDescriptor(
					INSTRUCTIONS, 
					new ParameterMessage("resultResolver/paramter/instructions"), 
					new MapConstraints(new ParameterDescriptor(MapConstraints.ALL, 
									new ParameterMessage("resultResolver/parameter/instruction/instruction"), 
									new StringConstraints())), null),
			new ParameterDescriptor(
					INCLUDE_CONTENT, 
					new ParameterMessage("resultResolver/paramter/include-content"), 
					new BooleanConstraints(), Boolean.TRUE)
	};
	
	private final static ResultDescriptor[] resultDescriptors = new ResultDescriptor[] { 
	        new ResultDescriptor(StateDescriptor.OK_DESCRIPTOR,
	                new ResultEntryDescriptor[] {
	                new ResultEntryDescriptor(SimpleProcessor.OUTPUT, 
	                        new LocalizedMessage("resultResolver/result/output"),
	                        ArrayConstraints.UNCONSTRAINED)	})
	};
	
	public Result process(Map parameter, Context context) throws Exception {
		Object []values = (Object [])parameter.get(SimpleProcessor.INPUT);
		boolean includeContent = ((Boolean)parameter.get(INCLUDE_CONTENT)).booleanValue();
		Object instructions = parameter.get(INSTRUCTIONS);
		List arrayEntries = new ArrayList();
		for ( int i = 0; i < values.length; i++ ) {
			Map map = (Map)values[i];
			Map resultMap = new HashMap();
			resultMap.putAll(map);
			URI uri = (URI)map.get(URI_ENTRY);
			Object content = Projector.getRepository().getResource(uri, ((ProjectorContext)context).getCredentials()); 
			if ( content != null ) {
				if ( instructions instanceof Map ) {
					if ( includeContent ) {
						content = new MultipleStreamable((Streamable) content);
					}
					DocumentValue documentValue = new DocumentValue((Streamable)content);
					Map instructionMap = (Map)instructions;
					for ( Iterator j = instructionMap.entrySet().iterator(); j.hasNext(); ) {
						Map.Entry entry = (Map.Entry)j.next();
						String key = (String) entry.getKey();
						XPath xPath = XPath.newInstance(entry.getValue().toString());
						List nodeList = xPath.selectNodes(documentValue.getRootElement());
						resultMap.put(key, XPathQuery.createValueFromNodeList(nodeList));
					}
				}
				if ( includeContent ) {
					resultMap.put(CONTENT_ENTRY, content);
				}
			}
			arrayEntries.add(resultMap);
		}
		return new Result(StateDescriptor.OK, SimpleProcessor.OUTPUT, arrayEntries);
	}
	
	public ParameterDescriptor[] getParameterDescriptors() {
		return parameterDescriptors;
	}

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