package org.overture.ide.ui.templates;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class VdmCompletionContext
{
private StringBuffer rawScan;
private StringBuffer processedScan;
/**
* Index where replacement must start. For example, if the
* rawScan is '<q' then the offset is -2 since the complete text '<q' should be replaced
*/
private SearchType type = SearchType.Types;
private String proposalPrefix = "";
private List<String> root = new Vector<String>();
public VdmCompletionContext(StringBuffer rawScan)
{
this.rawScan = rawScan;
init();
}
private void init()
{
String[] sepList = {"\n", "\r", "\t", "."};
proposalPrefix = regexStringCleaner(rawScan.toString(),sepList);
List<CharacterOrder> specialCharMatches = specialCharacterOrderExtractor(rawScan.toString());
if (checkLastSpecialCharacter(specialCharMatches, "<"))
{
// Completion of quote, e.g. <Green>
consQuoteContext(specialCharMatches.get(specialCharMatches.size()-1).start);
return;
}
if (proposalPrefix.contains("new"))
{
// Completion of constructors
consConstructorCallContext();
return;
}
if(proposalPrefix.contains("mk_") && checkLastSpecialCharacter(specialCharMatches, "_"))
{
consMkContext();
return;
}
// Completion for foo.bar. This covers things such as instance variables,
// values, a record, a tuple, operations and functions
if (checkLastSpecialCharacter(specialCharMatches, "."))
{ // only works for one . atm
String[] split = rawScan.toString().split("\\.");
consDotContext(split);
return;
}
String[] typeSepList = { " ", "\n", "\r", "\t", "."};
proposalPrefix = regexStringCleaner(proposalPrefix,typeSepList);
}
private String regexStringCleaner(String proposalPrefix,String[] sepList){
//Default
if( proposalPrefix == null || proposalPrefix.isEmpty()){
return "";
}
char charMatch = proposalPrefix.charAt(proposalPrefix.length() - 1); //checks the end of the string
if(charMatch == '\r' || charMatch == '\n' || charMatch == '\t' )
{
proposalPrefix = "";
}
else{
StringBuffer regexp = new StringBuffer("");
regexp.append("[");
for(String s : sepList) {
regexp.append("[");
regexp.append(Pattern.quote(s));
regexp.append("]");
}
regexp.append("]");
String[] bits = proposalPrefix.trim().split(regexp.toString());
proposalPrefix = bits[bits.length-1];
proposalPrefix = proposalPrefix.trim();
}
return proposalPrefix;
}
private void consDotContext(String[] split)
{
this.type = SearchType.Dot;
if(split.length >= 2 ){
this.proposalPrefix = split[1];
}
else{
this.proposalPrefix = split[0];
}
this.root = new Vector<>();
root.add(split[0]);
}
/**
* Constructs the completion context for a constructor call
*
* @param index
*/
private void consConstructorCallContext()
{
// This gives us everything after new, e.g. ' MyClass' if you type 'new MyClass'
proposalPrefix = rawScan.subSequence(rawScan.indexOf("new"),rawScan.length()).toString();
processedScan = rawScan; //new StringBuffer(subSeq);
type = SearchType.New;
}
/**
* Constructs the completion context for a 'mk_' call
*
*/
private void consMkContext() {
final int MK_LENGTH = "mk_".length();
CharSequence subSeq = rawScan.subSequence(MK_LENGTH, rawScan.length());
processedScan = new StringBuffer(subSeq);
proposalPrefix = processedScan.toString().trim();
type = SearchType.Mk;
}
/**
* Contrusts the completion context for the 'mk_token' call
*/
// private void consMK_tokenContext() {
// final int MK_LENGTH = "mk_t".length();
//
// CharSequence subSeq = rawScan.subSequence(MK_LENGTH, rawScan.length());
// processedScan = new StringBuffer(subSeq);
// proposalPrefix = processedScan.toString().trim();
//
// type = SearchType.Mk;
//
// }
/**
* Constructs the completion context for quotes
*
* @param index The index of the '<' character
*/
private void consQuoteContext(int index)
{
processedScan = new StringBuffer(proposalPrefix.subSequence(index, proposalPrefix.length()));
proposalPrefix = processedScan.substring(processedScan.lastIndexOf("<"));
type = SearchType.Quote;
}
private String getQualifiedSource()
{
String res = "";
if (root != null && !root.isEmpty())
{
for (Iterator<String> itr = root.iterator(); itr.hasNext();)
{
res += itr.next();
if (itr.hasNext())
res += ".";
}
}
return res;
}
public int getReplacementOffset()
{
return -proposalPrefix.length();
}
public SearchType getType()
{
return type;
}
public String getProposalPrefix()
{
return proposalPrefix;
}
public List<String> getRoot()
{
return root;
}
@Override
public String toString()
{
return type + " - Root: '" + getQualifiedSource() + "' Proposal: '"
+ proposalPrefix + "'" + " offset: ";
}
public List<CharacterOrder> specialCharacterOrderExtractor(String inputString){
List<CharacterOrder> matches = new ArrayList<CharacterOrder>();
//pattern to compare
Pattern pattern = Pattern.compile("[^a-zA-Z0-9\\( ]");
String cleanInputString = inputString.replaceAll("[[a-zA-Z0-9]*$]", "");
Matcher matcher = pattern.matcher(cleanInputString);
while (matcher.find()) {
matches.add(new CharacterOrder(matcherCleanUp(matcher.group()),matcher.start(),matcher.end()));
}
return matches;
}
public String matcherCleanUp(String match){
String[] typeSepList = {"\n", "\r", "\t"};
return regexStringCleaner(match,typeSepList);
}
public Boolean checkLastSpecialCharacter(List<CharacterOrder> specialCharMatches, String inputString){
if (specialCharMatches != null && !specialCharMatches.isEmpty() && inputString.equals(specialCharMatches.get(specialCharMatches.size()-1).content) )
{
return true;
}
return false;
}
class CharacterOrder
{
public CharacterOrder(String c, int s, int e){
content = c;
end = e;
start = s;
}
public String content;
public int start;
public int end;
};
}