/*
 * Created on Aug 20, 2003
 */

package fr.eisti.lassi.elearning.cocoon.sitemap;

import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.acting.ComposerAction;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.store.Store;
import org.apache.cocoon.components.source.SourceUtil;
import org.w3c.dom.Document;

import fr.eisti.lassi.elearning.*;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>An action named StepManagerAction which given the process-map.xml, 
 * a language and the current step of the transformations returns the 
 * next step to accomplish.</p>
 * 
 * <p>For example, for a source document of the language 'java' and at 
 * transformation step 'oop', the StepManagerAction will return 'pp'.</p>
 * 
 * <p>If the current step is last step 'p', then the action will return 
 * null, hence finishing the transformations.</p>
 * 
 * @author Cedric Vidal
 */
public class StepManagerAction extends ComposerAction implements ThreadSafe {
	
	private String processMapUri = null;
	private Source processMapSource = null;
	private ProcessMap processMap = null;

	public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception {
		String lang = parameters.getParameter("lang", null);
		String step = parameters.getParameter("step", lang);
		
		processMapUri = parameters.getParameter("process-map", source);
		Store store = null;
		ProcessMapEntry processMapEntry = null;
		
		try {
			processMapSource = resolver.resolveURI(processMapUri);

			// Retrieve the process map from the transient store
			store = (Store) this.manager.lookup(Store.TRANSIENT_STORE);
			processMapEntry = (ProcessMapEntry) store.get(this.processMapSource.getURI());

			// If the process map has changed, recreates the object
			if ((processMapEntry==null) || (processMapEntry.getValidity()==null) ||
					(processMapEntry.getValidity().isValid(this.processMapSource.getValidity()) <= 0)) {

				getLogger().info("(Re)building the process map from '"+
					this.processMapSource.getURI()+"'");
				
				if (this.processMapSource.getInputStream()==null) {
					throw new Exception("Source '"+
						this.processMapSource.getURI()+
						"' not found");
				}
				
				Document doc = SourceUtil.toDOM(processMapSource);
				DocumentProcessMapLoader processMapLoader = new DocumentProcessMapLoader(doc);
				this.processMap = processMapLoader.load();
				
				store.store(this.processMapSource.getURI(), new ProcessMapEntry(this.processMapSource.getValidity(), this.processMap) );
				
			} else {
				getLogger().info("Got process map from store for '"+
								 this.processMapSource.getURI()+"'");
				this.processMap = processMapEntry.getProcessMap();
			}
		} finally {
			if (processMapSource != null)
				resolver.release(processMapSource);
			
			if (store!=null) {
				this.manager.release(store);
			}
		}
		
		String next = processMap.getStepAfter(step);
		
		if ( next != null ) {
			Map map = new HashMap();
			getLogger().info("Language is " + lang + ", current step is " + step + ", next step is " + next);
			map.put("next", next);
			return map;
		} else {
			getLogger().info("Language is " + lang + ", current step is " + step + ", transformation is finished");
			return null;
		}
		
	}
}
