package org.molgenis.generator;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.molgenis.compute.ComputeParameter;
import org.molgenis.compute.ComputeProtocol;
import org.molgenis.protocol.Workflow;
import org.molgenis.protocol.WorkflowElement;
import org.molgenis.util.Tuple;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;
/**
* Created by IntelliJ IDEA.
* User: georgebyelas
* Date: 19/04/2012
* Time: 12:49
* To change this template use File | Settings | File Templates.
*/
public class FoldingMaker
{
private List<ComputeParameter> parameters = null;
private ModelLoader loader = new ModelLoader();
private Workflow workflow;
private static Logger logger = Logger.getLogger(FoldingMaker.class);
public List<Hashtable> removeUnused(List<Hashtable> worksheet, List<ComputeParameter> parameters)
{
this.parameters = parameters;
//in principle all hashtables should be identical
Hashtable<String, String> hashtable0 = worksheet.get(0);
Enumeration keys = hashtable0.keys();
while (keys.hasMoreElements())
{
String key = (String) keys.nextElement();
boolean isUsed = getIsUsed(key);
if (!isUsed)
{
for (Hashtable hashtable : worksheet)
{
hashtable.remove(key);
}
}
}
return worksheet;
}
private boolean getIsUsed(String field)
{
for (ComputeParameter parameter : parameters)
{
if (field.equalsIgnoreCase(parameter.getName()))
{
return true;
}
}
return false;
}
public List<Hashtable> transformToTable(List<Tuple> worksheet)
{
List<Hashtable> list = new ArrayList<Hashtable>();
for (Tuple tuple : worksheet)
{
Hashtable hashtable = new Hashtable();
List<String> fields = tuple.getFields();
for (String field : fields)
{
if (field == null)
continue;
else if (field.equalsIgnoreCase(""))
continue;
String value = tuple.getString(field);
//System.out.println(field + " -> " + value);
if (value == null)
{
hashtable.put(field, "");
//continue;
}
else
hashtable.put(field, value);
}
list.add(hashtable);
}
return list;
}
public void testFolding(Workflow workflow, List<Hashtable> worksheet)
{
Hashtable<String, Object> values = new Hashtable<String, Object>();
Vector<ComputeParameter> complexParameters = new Vector<ComputeParameter>();
Collection<ComputeParameter> parameters = workflow.getWorkflowComputeParameterCollection();
this.workflow = workflow;
Collection<WorkflowElement> elements = workflow.getWorkflowWorkflowElementCollection();
for (WorkflowElement element : elements)
{
ComputeProtocol protocol = (ComputeProtocol) element.getProtocol();
List<ComputeParameter> targets = findTargets(protocol.getScriptTemplate());
if (targets == null)
{
System.out.println(element.getName() + " has no targets ");
}
else
{
System.out.println(element.getName() + " has targets!");
//List<Hashtable> table = fold(targets, worksheet);
//here weaving testing
Iterator<ComputeParameter> itParameter = parameters.iterator();
while (itParameter.hasNext())
{
ComputeParameter parameter = itParameter.next();
if (parameter.getDefaultValue() != null)
{
if (parameter.getDefaultValue().contains("${"))
{
complexParameters.addElement(parameter);
}
else
{
values.put(parameter.getName(), parameter.getDefaultValue());
}
}
else
values.put(parameter.getName(), "");
}
for (int i = 0; i < worksheet.size(); i++)
{
Hashtable<String, Object> line = worksheet.get(i);
Enumeration ekeys = line.keys();
while (ekeys.hasMoreElements())
{
String ekey = (String) ekeys.nextElement();
Object eValues = line.get(ekey);
//System.out.println("#" + ekey + " -> " + eValues);
values.put(ekey, eValues);
}
int count = 0;
while ((complexParameters.size() > 0) && (count < 10))
{
Vector<ComputeParameter> toRemove = new Vector<ComputeParameter>();
for (ComputeParameter computeParameter : complexParameters)
{
String complexValue = weaveFreemarker(computeParameter.getDefaultValue(), values);
if (complexValue.contains("${"))
{
System.out.println(computeParameter.getName() + " -> " + complexValue);
}
else
{
values.put(computeParameter.getName(), complexValue);
toRemove.add(computeParameter);
}
}
complexParameters.removeAll(toRemove);
System.out.println("loop " + count + " removed " + toRemove.size());
count++;
}
}
List<Hashtable> table = fold(targets, worksheet);
for (int i = 0; i < table.size(); i++)
{
Hashtable<String, Object> line = table.get(i);
Enumeration ekeys = line.keys();
while (ekeys.hasMoreElements())
{
String ekey = (String) ekeys.nextElement();
Object eValues = line.get(ekey);
values.put(ekey, eValues);
}
String template = protocol.getScriptTemplate();
String jobListing = weaveFreemarker(template, values);
System.out.println(jobListing);
}
}
}
}
public String weaveFreemarker(String strTemplate, Hashtable<String, Object> values)
{
Configuration cfg = new Configuration();
//cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Template t = null;
StringWriter out = new StringWriter();
try
{
t = new Template("name", new StringReader(strTemplate), cfg);
t.process(values, out);
}
catch (TemplateException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return out.toString();
}
public List<Hashtable> fold(List<ComputeParameter> targets, List<Hashtable> worksheet)
{
//we find all used parameters
Vector<ComputeParameter> parameters = new Vector<ComputeParameter>();
//we assume that all hashtables are the same, which should be true
Hashtable<String, String> hashtable0 = worksheet.get(0);
Enumeration keys = hashtable0.keys();
while (keys.hasMoreElements())
{
String key = (String) keys.nextElement();
ComputeParameter par = findParameter(key);
parameters.add(par);
}
//vector of all targets
Vector<String> vecTargetNames = new Vector<String>();
//find all hasOne
//first find initial hasOnes
Vector<String> vecHasOneNames = new Vector<String>();
for (ComputeParameter target : targets)
{
//this does not work - target.getHasOne()
vecTargetNames.add(target.getName());
List<ComputeParameter> hasOnes = target.getHasOne();
List<String> hasOneNames = target.getHasOne_Name();
vecHasOneNames.addAll(hasOneNames);
continue;
}
int prevSize = 0;
//now find the rest
while (vecHasOneNames.size() > prevSize)
{
Vector<String> temp = new Vector<String>();
for (String hasOneName : vecHasOneNames)
{
ComputeParameter par = findParameter(hasOneName);
List<String> hasOneNames = par.getHasOne_Name();
temp.addAll(hasOneNames);
}
vecHasOneNames.addAll(temp);
prevSize = vecHasOneNames.size();
}
//now we create new folded list
List<Hashtable> folded = new ArrayList<Hashtable>();
//foldered line, where Object can be String of List<String>
Hashtable<String, Object> line = null;
Vector<FoldingUniqueContainer> uniqueContainers = new Vector<FoldingUniqueContainer>();
for (Hashtable initialLine : worksheet)
{
//System.out.println("#" + initialLine.toString());
//vector of all target values is used to build unique key-combination
//unique string
String keyCombination = "";
for (String field : vecTargetNames)
{
String value = (String) initialLine.get(field);
keyCombination += value;
}
//vector of all hasOne is used to build hasOne unique combination
String hasOneCombination = "";
for (String field : vecHasOneNames)
{
String value = (String) initialLine.get(field);
hasOneCombination += value;
}
//check if combination is new unique and create new container
// or exist and add to exist container
uniqueContainers = evaluateUniqueness(uniqueContainers, keyCombination, hasOneCombination, initialLine);
}
//create vector with unique field
Vector<String> unique = new Vector<String>();
unique.addAll(vecTargetNames);
unique.addAll(vecHasOneNames);
for (FoldingUniqueContainer container : uniqueContainers)
{
//these initial lines should be foldered
Vector<Hashtable> initialLines = container.getAllHashtablles();
if (initialLines.size() > 1)
{
line = new Hashtable<String, Object>();
for (Hashtable initialLine : initialLines)
{
Enumeration ekeys = initialLine.keys();
while (ekeys.hasMoreElements())
{
String ekey = (String) ekeys.nextElement();
String eValue = (String) initialLine.get(ekey);
//System.out.println("#" + ekey + " -> " + eValue);
boolean isKeyUnique = isUnique(unique, ekey);
if (isKeyUnique)
{
//we add ones
if (!line.containsKey(ekey))
{
line.put(ekey, eValue);
}
}
else
{
//we create List<String> only once and add all values there
if (!line.containsKey(ekey))
{
//ha-ha we have some many variables that I cannot name a new one!!!
List<String> finalListofValues = new ArrayList<String>();
finalListofValues.add(eValue);
line.put(ekey, finalListofValues);
}
else
{
List<String> finalListofValues = (List<String>) line.get(ekey);
finalListofValues.add(eValue);
line.put(ekey, finalListofValues);
}
}
}
}
}
else
{
line = initialLines.elementAt(0);
}
folded.add(line);
}
return folded;
}
private boolean isUnique(Vector<String> unique, String ekey)
{
for (String str : unique)
{
if (str.equalsIgnoreCase(ekey))
return true;
}
return false;
}
private Vector<FoldingUniqueContainer> evaluateUniqueness(Vector<FoldingUniqueContainer> uniqueContainers,
String keyCombination, String hasOneCombination, Hashtable initialLine)
{
boolean unique = true;
for (FoldingUniqueContainer container : uniqueContainers)
{
String key = container.getKey();
if (key.equalsIgnoreCase(keyCombination))
{
//it is not unique
//let check hasOneCombination
String hasOne = container.getHasOne();
if (hasOne.equalsIgnoreCase(hasOneCombination))
{
//it should be foldered
container.addElement(initialLine);
unique = false;
break;
}
else
{
logger.log(Level.ERROR, "hasOne properties " + hasOne + " & " + hasOneCombination + " are not correct ");
System.exit(1);
}
}
}
if (unique)
{
FoldingUniqueContainer newContainer = new FoldingUniqueContainer(keyCombination, hasOneCombination, initialLine);
uniqueContainers.add(newContainer);
}
return uniqueContainers; //To change body of created methods use File | Settings | File Templates.
}
public List<ComputeParameter> findTargets(String protocol)
{
List<ComputeParameter> list = null;
if (protocol.indexOf(JobGenerator.FLAG) > -1)
{
String str = protocol.substring(protocol.indexOf(JobGenerator.FLAG),
protocol.indexOf("\n", protocol.indexOf(JobGenerator.FLAG)));
list = getParametersFromHeader(str);
return list;
}
return list;
}
public List<ComputeParameter> getParametersFromHeader(String str)
{
List<ComputeParameter> list = new ArrayList<ComputeParameter>();
Vector<String> names = findNames(str);
for (int i = 0; i < names.size(); i++)
{
ComputeParameter par = findParameter(names.elementAt(i));
list.add(par);
}
return list;
}
private ComputeParameter findParameter(String s)
{
Collection<ComputeParameter> parameters = workflow.getWorkflowComputeParameterCollection();
Iterator<ComputeParameter> itr = parameters.iterator();
while (itr.hasNext())
{
ComputeParameter par = itr.next();
String name = par.getName();
if (s.equalsIgnoreCase(name))
return par;
}
System.exit(1);
return null;
}
private Vector<String> findNames(String list)
{
list = list.trim();
Vector<String> names = new Vector<String>();
int posEmpty = list.indexOf(" ") + 1;
if (posEmpty == 0)
return names;
list = list.substring(posEmpty);
while (list.indexOf(",") > -1)
{
int posComa = list.indexOf(",");
String name = list.substring(0, posComa).trim();
if (name != "")
names.addElement(name);
list = list.substring(posComa + 1);
}
names.add(list);
return names;
}
public void setWorkflow(Workflow workflow)
{
this.workflow = workflow;
}
}