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

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.commons.contract.Context;
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.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.context.HttpContext;
import org.apache.slide.projector.context.ProjectorContext;
import org.apache.slide.projector.engine.Job;
import org.apache.slide.projector.engine.ProcessorManager;
import org.apache.slide.projector.engine.Scheduler;
import org.apache.slide.projector.expression.EventExpression;
import org.apache.slide.projector.processor.SimpleProcessor;
import org.apache.slide.projector.value.MultipleStreamable;
import org.apache.slide.projector.value.Streamable;
import org.apache.slide.projector.value.TypedInputStream;
import org.apache.slide.projector.value.URI;
import org.apache.slide.projector.value.URIValue;

/**
 * @version $Revision: 1.8 $
 */

public class CachedContent implements Processor {
    private static Logger logger = Logger.getLogger(CachedContent.class.getName());

    public final static String URL = "url";
    
    private final static ResultDescriptor []resultDescriptors = new ResultDescriptor[] {
        new ResultDescriptor(StateDescriptor.OK_DESCRIPTOR,
            new ResultEntryDescriptor[] {
            new ResultEntryDescriptor(SimpleProcessor.OUTPUT, new LocalizedMessage("cachedContent/result/output"), AnyConstraints.UNCONSTRAINED),
            new ResultEntryDescriptor(URL, new LocalizedMessage("cachedContent/result/url"), URIConstraints.UNCONSTRAINED),
    }
    )};
    
    private final static ParameterDescriptor[] parameterDescriptors = 
        new ParameterDescriptor[] { 
            new ParameterDescriptor(SimpleProcessor.INPUT, 
                    new ParameterMessage("cachedContent/parameter/input"), 
                    new URIConstraints()) };
    
    public Result process(Map parameter, Context context) throws Exception {
        ProjectorContext projectorContext = (ProjectorContext)context;
        URI uri = (URI)parameter.get(SimpleProcessor.INPUT);
        String url = "";
        if ( context instanceof HttpContext ) {
            url = ((HttpContext)context).getContextPath()+"/"+ProcessorManager.getInstance().getURI(this)+"?input="+uri;
        }
        // check for cached result
        Map resultEntries = new HashMap();
        Object output = context.getStore(Projector.CACHE_STORE).get(uri.toString(), context);
        if ( output == null ) {
            output = Projector.getRepository().getResource(uri, projectorContext.getCredentials());
            if ( output instanceof TypedInputStream ) {
                output = new MultipleStreamable((Streamable)output); 
            }
            // cache result...
            context.getStore(Projector.CACHE_STORE).put(uri.toString(), output, context);
            // ...and add dispose condition
            Map jobParameter = new HashMap();
            jobParameter.put(Dispose.STORE, Projector.CACHE_STORE);
            jobParameter.put(Dispose.KEY, new String(uri.toString()));
            EventExpression expression = new EventExpression("Update");
            expression.addProperty(EventExpression.DEPTH, "0");
            expression.addProperty(EventExpression.URI, uri.toString());
            Scheduler.getInstance().registerJob(new Job(projectorContext.getProcessId()+":"+projectorContext.getStep(), new URIValue("dispose"), expression, expression, jobParameter, false, false));
			Scheduler.getInstance().saveJobs();
        }
        resultEntries.put(SimpleProcessor.OUTPUT, output);
        // build url to activate this processor on top level
        resultEntries.put(URL, new String(url));
        return new Result(StateDescriptor.OK, resultEntries);
    }

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

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