package tool.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;
import tool.ToolModelActivator;
public class ToolMethod extends ToolComponent implements IClassComponent, IEditorInput{
protected String visability;
private String returnType;
private List<ToolParameter> parameters;
private boolean copyReturn = false;
private String returnEvent;
private int returnEventNumber;
private String exceptionEvent;
private int exceptionEventNumber;
private int ID;
private String signature;
private boolean internal;
private List<ToolLocalVariable> localVariables;
public static final String DECLARATION_REGEX = "^has\\s*.+\\s*method\\s+(?s)(.+?)(?-s)HAS PROPERTY id = (\\d+)\\s*;";
public static final String CEX_SIGNATURE_REGEX = "^method\\s+(?s)(.+?)(?-s)begin";
public static final String NAME_REGEX = "has\\s*(public|private|publicinternal)\\s*method\\s+([A-Za-z0-9_.]+)";
public static final String RETURN_REGEX = ":\\s*(COPY|\\s*)([A-Za-z0-9_.]+)\\s+";
// public static final String ID_REGEX = "HAS PROPERTY id = (\\d+)\\s*";
public static final String COMPLETION_REGEX = "where completion = \\(return = ([A-Za-z0-9_.]+)\\((\\d+)\\), exception = ([A-Za-z0-9_.]+)\\((\\d+)\\)\\)";
public static final Pattern declarationPattern = Pattern.compile(DECLARATION_REGEX, Pattern.MULTILINE);
public static final Pattern cexSignaturePattern = Pattern.compile(CEX_SIGNATURE_REGEX, Pattern.MULTILINE);
public static final Pattern namePattern = Pattern.compile(NAME_REGEX);
public static final Pattern returnPattern = Pattern.compile(RETURN_REGEX);
// public static final Pattern idPattCern = Pattern.compile(ID_REGEX);
public static final Pattern completionPattern = Pattern.compile(COMPLETION_REGEX);
private IDocument implementationDocument;
public ToolMethod(Object parent){
super();
this.setParent(parent);
}
public ToolMethod(Object parent, String source){
this(parent);
this.parse(source);
}
public void parse(String source){
parseNamePart(source);
parseParamPart(source);
parseReturnPart(source);
parseCompletionPart(source);
parseSignature(source, declarationPattern);
}
private void parseSignature(String source, Pattern pattern) {
Matcher sig = pattern.matcher(source);
if (sig.find()){
this.signature = sig.group(1);
this.setID(sig.group(2));
}
}
private void parseParamPart(String source){
if (!source.contains("("))
return;
String paramPart = source.substring(source.indexOf('('), source.indexOf(')'));
if (!paramPart.equals("")){
String paramStrings[] = paramPart.split(",");
for (String paramString : paramStrings){
ToolParameter aParam = new ToolParameter(this, paramString);
this.addParameter(aParam);
}
}
}
private void parseCompletionPart(String source){
Matcher completionPart = ToolMethod.completionPattern.matcher(source);
if (completionPart.find()){
this.returnEvent = completionPart.group(1);
this.returnEventNumber = Integer.parseInt(completionPart.group(2));
this.exceptionEvent = completionPart.group(3);
this.exceptionEventNumber = Integer.parseInt(completionPart.group(4));
}
}
private void parseNamePart(String source){
Matcher namePart = ToolMethod.namePattern.matcher(source);
if (namePart.find()){
this.setVisability(namePart.group(1));
this.setToolName(namePart.group(2));
}
}
private void parseReturnPart(String source){
Matcher returnPart = ToolMethod.returnPattern.matcher(source);
if (returnPart.find()){
int groups = returnPart.groupCount();
if (groups == 2){
this.setCopyReturn(true);
this.setReturnType(returnPart.group(2));
} else {
this.setReturnType(returnPart.group(1));
}
}
}
@Override
public IFile getClassFile() {
return this.file;
}
@Override
public void setClassFile(IFile classFile) {
this.file = classFile;
}
@Override
public boolean isPublic() {
if (visability == null)
return false;
return (visability.equalsIgnoreCase("public")) ? true : false;
}
@Override
public void setPublic(boolean pub) {
if (pub){
this.setVisability("public");
} else {
this.setVisability("private");
}
}
public void setVisability(String visability) {
if (visability.equalsIgnoreCase("publicinternal")){
setInternal(true);
setPublic(true);
} else {
propertyChangeSupport.firePropertyChange("visability", this.visability,
this.visability = visability);
setDirty(true);
}
}
public boolean isInternal(){
return this.internal;
}
public void setInternal(boolean internal) {
propertyChangeSupport.firePropertyChange("internal", this.internal,
this.internal = internal);
setDirty(true);
}
public String getVisability(){
return this.visability;
}
public String getReturnType() {
return returnType;
}
public void setReturnType(String returnType) {
propertyChangeSupport.firePropertyChange("returnType", this.returnType,
this.returnType = returnType);
setDirty(true);
}
public boolean isCopyReturn() {
return copyReturn;
}
public void setCopyReturn(boolean copyReturn) {
propertyChangeSupport.firePropertyChange("copyReturn", this.copyReturn,
this.copyReturn = copyReturn);
setDirty(true);
}
public String getReturnEvent() {
return returnEvent;
}
public void setReturnEvent(String returnEvent) {
propertyChangeSupport.firePropertyChange("returnEvent", this.returnEvent,
this.returnEvent = returnEvent);
setDirty(true);
}
public String getExceptionEvent() {
return exceptionEvent;
}
public void addParameter(ToolParameter param){
if (parameters == null)
parameters = new ArrayList<ToolParameter>();
parameters.add(param);
setDirty(true);
}
public void setExceptionEvent(String exceptionEvent) {
propertyChangeSupport.firePropertyChange("exceptionEvent", this.exceptionEvent,
this.exceptionEvent = exceptionEvent);
setDirty(true);
}
public List<ToolParameter> getParameters() {
return parameters;
}
public void setID(String propertyId) {
if (propertyId != null)
this.setID(Integer.parseInt(propertyId));
}
public int getID() {
return ID;
}
public void setID(int iD) {
ID = iD;
}
@Override
public String getLabelText() {
return getToolName(); //this.signature.replaceAll("[\\t\\r\\n\\f\\s]+"," ");
}
public String getSignature() {
return signature;
}
@Override
public String getIconString() {
if (isPublic())
return "icons/public_method.gif";
else
return "icons/private_method.gif";
}
@Override
public boolean exists() {
return true;
}
@Override
public ImageDescriptor getImageDescriptor() {
return ToolModelActivator.getImageDescriptor(getIconString());
}
@Override
public IPersistableElement getPersistable() {
return null;
}
@Override
public String getToolTipText() {
return ((ToolComponent)getParent()).getToolName() + "." + getLabelText();
}
@Override
public Object getAdapter(Class cls) {
return null;
}
@Override
public boolean isReadWrite() {
return ((ToolComponent)getParent()).isReadWrite();
}
/**
* this method locates the method source in the CEX file
* and returns it as a region
*/
public IRegion getMethodSourceRegion(boolean includeSignature) {
IDocument document = getImplementationDocument();
String targetSignature = getSignature().replaceAll("\\.", "\\\\.").trim();
targetSignature = targetSignature.replaceAll("\\(", "\\\\(");
targetSignature = targetSignature.replaceAll("\\)", "\\\\)");
targetSignature = ((ToolComponent)getParent()).getToolName() + "." + targetSignature;
String startRegionRegex = "method\\s+" + targetSignature + "\\s*begin";
String endRegionRegex = "(?s)(.+?)(?-s)end method;";
try {
FindReplaceDocumentAdapter frAdapter = new FindReplaceDocumentAdapter(document);
IRegion startRegion = frAdapter.find(0, startRegionRegex, true, false, false, true);
if (startRegion == null)
return null; // no method implementation
IRegion endRegion = frAdapter.find(startRegion.getOffset()+startRegion.getLength()+"begin".length(), endRegionRegex, true, false, false, true);
IRegion sourceRegion = null;
if (includeSignature){
sourceRegion = new Region(startRegion.getOffset(), "begin".length()+startRegion.getLength()+endRegion.getLength());
} else {
sourceRegion = new Region(endRegion.getOffset(), endRegion.getLength()-"end method;".length());
}
return sourceRegion;
} catch (BadLocationException e) {
ToolModelActivator.showError("Error finding method source region.", e);
}
return null;
}
@Override
public IFile getFile() {
if (this.file != null)
return file;
ToolComponent toolClass = (ToolComponent)this.getParent();
if (toolClass.getFile() == null){
// we are in a PEX file so got to the Plan
ToolPlan plan = (ToolPlan) toolClass.getParent();
return plan.getFile();
} else {
return toolClass.getFile();
}
}
public IDocument getImplementationDocument() {
if (this.implementationDocument == null){
IDocumentProvider provider = new TextFileDocumentProvider();
try
{
IFile implFile = getFile();
provider.connect(implFile);
this.implementationDocument = provider.getDocument(implFile);
}
catch (CoreException e)
{
}
}
return this.implementationDocument;
}
@Override
public String getLabelText(int options) {
if ((options & LabelProvider.FULL_PATH) == LabelProvider.FULL_PATH){
ToolClass cls = (ToolClass)getParent();
return cls.getPlanName() + "." + cls.getToolName() + "." + getLabelText();
}
return getLabelText();
}
public String toImplamentationSource(){
StringBuilder sb = new StringBuilder();
sb.append("method ");
sb.append(((ToolClass)getParent()).getToolName());
sb.append(".");
sb.append(getName());
if (parameters != null){
sb.append("(");
boolean first = true;
for (ToolParameter param : parameters){
if (first)
first = false;
else
sb.append(",\n\t");
sb.append(param.toSource());
}
sb.append(")");
}
if (returnType != null){
sb.append(": ");
sb.append(returnType);
}
//TODO completion events
sb.append("\n");
sb.append("begin\n");
//TODO method source
sb.append("end method;\n");
return sb.toString();
}
@Override
public String toSource() {
StringBuilder sb = new StringBuilder();
sb.append("has ");
sb.append(getVisability());
sb.append(" method ");
sb.append(getName());
if (parameters != null){
sb.append("(");
boolean first = true;
for (ToolParameter param : parameters){
if (first)
first = false;
else
sb.append(",\n\t");
sb.append(param.toSource());
}
sb.append(")");
}
if (returnType != null){
sb.append(": ");
sb.append(returnType);
}
//TODO completion events
sb.append(" HAS PROPERTY id = ");
sb.append(getID());
sb.append(";");
return sb.toString();
}
@Override
public String getName() {
return getToolName();
}
public void addLocalVariable(String name, String typeName){
ToolType type = (ToolType) ToolType.findType(getProject(), typeName);
ToolLocalVariable local = new ToolLocalVariable(name, type);
if (this.localVariables == null)
this.localVariables = new ArrayList<ToolLocalVariable>();
this.localVariables.add(local);
}
public void clearLocalVariables(){
if (this.localVariables != null){
this.localVariables.clear();
this.localVariables = null;
}
}
}