package com.liferay.ide.velocity.vaulttec.ui.model;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Preferences;
import com.liferay.ide.velocity.editor.VelocityEditor;
import com.liferay.ide.velocity.vaulttec.ui.IPreferencesConstants;
import com.liferay.ide.velocity.vaulttec.ui.VelocityPlugin;
import com.liferay.ide.velocity.vaulttec.ui.editor.text.VelocityTextGuesser;
/**
* DOCUMENT ME!
*
* @version $Revision: 7 $
* @author <a href="mailto:akmal.sarhan@gmail.com">Akmal Sarhan </a>
*/
public class ModelTools
{
private VelocityEditor fEditor;
public ModelTools(VelocityEditor anEditor)
{
fEditor = anEditor;
}
/**
* Uses visitor design pattern to find tree node which contains given line.
*
* @param aLine
* line to find according tree node for
* @return tree node containing given line or null if no tree node found
*/
public ITreeNode getNodeByLine(int aLine)
{
ITreeNode node = fEditor.getRootNode();
if (node != null)
{
TreeNodeLineVisitor visitor = new TreeNodeLineVisitor(aLine);
node.accept(visitor);
return visitor.getNode();
}
return null;
}
/**
* Uses visitor design pattern to find tree node which contains given
* guessed text.
*
* @param aGuess
* document region marking a reference to find according tree
* node with referenced id for
* @return tree node containing referenced id or null if no tree node found
*/
public ITreeNode getNodeByGuess(VelocityTextGuesser aGuess)
{
ITreeNode node = fEditor.getRootNode();
if (node != null)
{
String id;
if (aGuess.getType() == VelocityTextGuesser.TYPE_VARIABLE)
{
id = "$" + aGuess.getText();
} else if (aGuess.getType() == VelocityTextGuesser.TYPE_DIRECTIVE)
{
id = aGuess.getText();
} else
{
return null;
}
// Search the model tree for a node with given ID
TreeNodeIdVisitor visitor = new TreeNodeIdVisitor(id, aGuess.getLine());
node.accept(visitor);
return visitor.getNode();
}
return null;
}
/**
* Returns true if specified line belongs to a <code>#foreach</code>
* block.
*/
public boolean isLineWithinLoop(int aLine)
{
ITreeNode node = fEditor.getRootNode();
if (node != null)
{
if (aLine > 0)
{
// Use visitor pattern to find node which contains given line
TreeNodeLineVisitor visitor = new TreeNodeLineVisitor(aLine);
node.accept(visitor);
node = visitor.getNode();
while (node != null)
{
if (node instanceof Directive)
{
Directive directive = (Directive) node;
if (directive.getType() == Directive.TYPE_FOREACH) { return true; }
}
node = (ITreeNode) node.getParent();
}
}
}
return false;
}
/**
* DOCUMENT ME!
*
* @param aLine
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public List getVariables(int aLine)
{
ITreeNode node = fEditor.getLastRootNode();
if (node != null)
{
TreeNodeVariableVisitor visitor = new TreeNodeVariableVisitor(aLine);
node.accept(visitor);
List variables = visitor.getVariables();
if (isLineWithinLoop(fEditor.getCursorLine()))
{
Preferences prefs = VelocityPlugin.getDefault().getPluginPreferences();
String countName = "$" + prefs.getString(IPreferencesConstants.VELOCITY_COUNTER_NAME);
variables.add(countName);
}
return variables;
}
return new ArrayList();
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public List getMacros()
{
ITreeNode node = fEditor.getLastRootNode();
if (node != null)
{
TreeNodeMacroVisitor visitor = new TreeNodeMacroVisitor();
node.accept(visitor);
return visitor.getMacros();
}
return new ArrayList();
}
private class TreeNodeLineVisitor implements ITreeVisitor
{
private int fLine;
private ITreeNode fNode;
public TreeNodeLineVisitor(int aLine)
{
fLine = aLine;
fNode = null;
}
public boolean visit(ITreeNode aNode)
{
boolean more;
if ((fLine >= aNode.getStartLine()) && (fLine <= aNode.getEndLine()))
{
fNode = aNode;
more = false;
} else
{
more = true;
}
return more;
}
public ITreeNode getNode()
{
return fNode;
}
}
private class TreeNodeIdVisitor implements ITreeVisitor
{
private String fId;
private int fLine;
private ITreeNode fNode;
public TreeNodeIdVisitor(String anId, int aLine)
{
fId = anId;
fLine = aLine;
fNode = null;
}
public boolean visit(ITreeNode aNode)
{
if ((aNode.getStartLine() < fLine) && aNode instanceof Directive)
{
Directive directive = ((Directive) aNode);
// If within macro block then check macro parameters instead
// of ID
if (directive.getType() == Directive.TYPE_MACRO)
{
if (directive.getId().equals(fId))
{
fNode = aNode;
} else if ((fLine >= aNode.getStartLine()) && (fLine <= aNode.getEndLine()))
{
List parameters = ((Directive) aNode).getParameters();
if ((parameters != null) && parameters.contains(fId))
{
fNode = aNode;
}
}
} else
{
String id = directive.getId();
if ((id != null) && id.equals(fId))
{
fNode = aNode;
}
}
}
return true;
}
public ITreeNode getNode()
{
return fNode;
}
}
private class TreeNodeVariableVisitor implements ITreeVisitor
{
private int fLine;
private List fVariables;
public TreeNodeVariableVisitor(int aLine)
{
fLine = aLine;
fVariables = new ArrayList();
}
public boolean visit(ITreeNode aNode)
{
if (aNode instanceof Directive)
{
int type = ((Directive) aNode).getType();
if ((type == Directive.TYPE_FOREACH) || (type == Directive.TYPE_SET))
{
String variable = ((Directive) aNode).getId();
if (!fVariables.contains(variable))
{
fVariables.add(variable);
}
} else if (type == Directive.TYPE_MACRO)
{
if ((fLine >= aNode.getStartLine()) && (fLine <= aNode.getEndLine()))
{
List parameters = ((Directive) aNode).getParameters();
if (parameters != null)
{
fVariables.addAll(parameters);
}
}
}
}
return true;
}
public List getVariables()
{
return fVariables;
}
}
private class TreeNodeMacroVisitor implements ITreeVisitor
{
private List fMacros;
public TreeNodeMacroVisitor()
{
fMacros = new ArrayList();
}
public boolean visit(ITreeNode aNode)
{
if (aNode instanceof Directive)
{
int type = ((Directive) aNode).getType();
if (type == Directive.TYPE_MACRO)
{
fMacros.add(((Directive) aNode).getId());
}
}
return true;
}
public List getMacros()
{
return fMacros;
}
}
}