/*
* Copyright 2015 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.rf.ide.core.testdata.mapping.table;
import java.util.ArrayList;
import java.util.List;
import org.rf.ide.core.testdata.model.RobotFile;
import org.rf.ide.core.testdata.model.table.exec.descs.ForDescriptorInfo;
import org.rf.ide.core.testdata.text.read.IRobotLineElement;
import org.rf.ide.core.testdata.text.read.ParsingState.TableType;
import org.rf.ide.core.testdata.text.read.RobotLine;
import org.rf.ide.core.testdata.text.read.recognizer.RobotToken;
import org.rf.ide.core.testdata.text.read.recognizer.RobotTokenType;
import org.rf.ide.core.testdata.text.read.separators.Separator;
import org.rf.ide.core.testdata.text.read.separators.Separator.SeparatorType;
@SuppressWarnings("PMD.GodClass")
public class ElementPositionResolver {
public PositionInformation buildPositionDescription(final RobotFile model, final RobotLine currentLine,
final RobotToken currentToken) {
final PositionInformation posInfo = new PositionInformation();
final List<IRobotLineElement> lineElements = new ArrayList<>(currentLine.getLineElements());
lineElements.add(currentToken);
final int numberOfElements = lineElements.size();
for (int elemIndex = 0; elemIndex < numberOfElements; elemIndex++) {
final IRobotLineElement elem = lineElements.get(elemIndex);
if (elem instanceof Separator) {
if (posInfo.getSeparatorsPosIndexes().isEmpty()) {
posInfo.setLineSeparator((SeparatorType) elem.getTypes().get(0));
}
posInfo.addSeparatorPosIndex(elemIndex);
} else if (elem instanceof RobotToken) {
if (elem.getTypes().contains(RobotTokenType.PRETTY_ALIGN_SPACE)) {
posInfo.addPrettyAlignPosIndex(elemIndex);
} else if (elem.getTypes().contains(RobotTokenType.PREVIOUS_LINE_CONTINUE)) {
posInfo.addPreviousLineContinuePosIndex(elemIndex);
} else {
posInfo.addRobotTokenPosIndex(elemIndex);
}
}
}
return posInfo;
}
public static class PositionInformation {
private SeparatorType lineSeparator = SeparatorType.TABULATOR_OR_DOUBLE_SPACE;
private final List<Integer> robotTokensPosIndexes = new ArrayList<>();
private final List<Integer> previousLineContinuePosIndexes = new ArrayList<>();
private final List<Integer> prettyAlignPosIndexes = new ArrayList<>();
private final List<Integer> separatorsPosIndexes = new ArrayList<>();
private boolean wasLastSeparator = false;
private boolean isFirstSeparator = false;
private void setLineSeparator(final SeparatorType lineSeparator) {
this.lineSeparator = lineSeparator;
}
private void addRobotTokenPosIndex(final int robotTokenPosIndex) {
robotTokensPosIndexes.add(robotTokenPosIndex);
this.wasLastSeparator = false;
}
private void addPrettyAlignPosIndex(final int prettyAlignPosIndex) {
prettyAlignPosIndexes.add(prettyAlignPosIndex);
}
private void addPreviousLineContinuePosIndex(final int prevLineContIndex) {
previousLineContinuePosIndexes.add(prevLineContIndex);
}
private void addSeparatorPosIndex(final int separatorPosIndex) {
if (robotTokensPosIndexes.isEmpty() && separatorsPosIndexes.isEmpty()) {
isFirstSeparator = true;
}
separatorsPosIndexes.add(separatorPosIndex);
this.wasLastSeparator = true;
}
public SeparatorType getLineSeparator() {
return lineSeparator;
}
public List<Integer> getRobotTokensPosIndexes() {
return robotTokensPosIndexes;
}
public List<Integer> getSeparatorsPosIndexes() {
return separatorsPosIndexes;
}
public List<Integer> getPrettyAlignPosIndexes() {
return prettyAlignPosIndexes;
}
public List<Integer> getPreviousLineContinuePosIndexes() {
return previousLineContinuePosIndexes;
}
public boolean isContinuePreviousLineTheFirstToken(final TableType type) {
boolean result = false;
if (!previousLineContinuePosIndexes.isEmpty()) {
final int theFirstContinue = previousLineContinuePosIndexes.get(0);
if (!robotTokensPosIndexes.isEmpty()) {
final int theFirstToken = robotTokensPosIndexes.get(0);
result = theFirstContinue < theFirstToken;
} else {
result = true;
}
}
if (result) {
if (type == TableType.KEYWORD || type == TableType.TEST_CASE) {
if (getLineSeparator() == SeparatorType.TABULATOR_OR_DOUBLE_SPACE) {
result = getSeparatorsPosIndexes().size() == 1;
} else {
result = getSeparatorsPosIndexes().size() >= 2;
}
}
}
return result;
}
public int getColumnIndex() {
int column = 0;
if (!robotTokensPosIndexes.isEmpty() || !separatorsPosIndexes.isEmpty()) {
final int numberOfSeparators = separatorsPosIndexes.size();
if (getLineSeparator() == SeparatorType.PIPE) {
if (wasLastSeparator) {
column = numberOfSeparators - 1;
} else {
column = numberOfSeparators;
}
} else {
if (wasLastSeparator) {
column = numberOfSeparators + 1;
} else {
column = robotTokensPosIndexes.size();
if (isFirstSeparator()) {
column++;
}
}
}
}
return column;
}
public boolean isLastSeparator() {
return wasLastSeparator;
}
public boolean isFirstSeparator() {
return isFirstSeparator;
}
}
public enum PositionExpected implements IPositionCheckable {
TABLE_HEADER {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return isReallyFirstElement(posInfo, currentToken);
}
},
SETTING_TABLE_ELEMENT_DECLARATION {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return isReallyFirstElement(posInfo, currentToken);
}
},
TEST_CASE_NAME {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
boolean result = isReallyFirstElement(posInfo, currentToken);
if (!result) {
final List<IRobotLineElement> lineElements = currentLine.getLineElements();
if (lineElements.size() == 1) {
if (lineElements.get(0).getTypes().contains(RobotTokenType.PRETTY_ALIGN_SPACE)) {
result = true;
}
}
}
return result;
}
},
USER_KEYWORD_NAME {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
boolean result = isReallyFirstElement(posInfo, currentToken);
if (!result) {
final List<IRobotLineElement> lineElements = currentLine.getLineElements();
if (lineElements.size() == 1) {
if (lineElements.get(0).getTypes().contains(RobotTokenType.PRETTY_ALIGN_SPACE)) {
result = true;
}
}
}
return result;
}
},
VARIABLE_DECLARATION_IN_VARIABLE_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return isReallyFirstElement(posInfo, currentToken);
}
},
LINE_CONTINUE_NEWLINE_FOR_SETTING_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return posInfo.isContinuePreviousLineTheFirstToken(TableType.SETTINGS);
}
},
LINE_CONTINUE_NEWLINE_FOR_VARIABLE_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return posInfo.isContinuePreviousLineTheFirstToken(TableType.VARIABLES);
}
},
LINE_CONTINUE_NEWLINE_FOR_TESTCASE_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return posInfo.isContinuePreviousLineTheFirstToken(TableType.TEST_CASE);
}
},
LINE_CONTINUE_NEWLINE_FOR_KEYWORD_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return posInfo.isContinuePreviousLineTheFirstToken(TableType.KEYWORD);
}
},
LINE_CONTINUE_INLINED_FOR_TESTCASE_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return isInlined(posInfo);
}
},
LINE_CONTINUE_INLINED_FOR_KEYWORD_TABLE {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return isInlined(posInfo);
}
},
LINE_CONTINUE_INLINED_IN_FOR_LOOP {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
boolean isInlined = false;
final List<IRobotLineElement> elements = new ArrayList<>(currentLine.getLineElements());
if (currentToken != null) {
elements.add(currentToken);
}
final ForDescriptorInfo forDescInfo = ForDescriptorInfo.build(elements);
if (forDescInfo.getForStartIndex() > -1) {
if (forDescInfo.getForLineContinueInlineIndex() == currentLine.getLineElements().size()) {
isInlined = true;
}
}
return isInlined;
}
},
TEST_CASE_EXEC_ROW_ACTION_NAME {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return !isReallyFirstElement(posInfo, currentToken);
}
},
KEYWORD_EXEC_ROW_ACTION_NAME {
@Override
public boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
return !isReallyFirstElement(posInfo, currentToken);
}
};
private static boolean isInlined(final PositionInformation posInfo) {
boolean result = false;
if (posInfo.getPreviousLineContinuePosIndexes().size() == 1
&& posInfo.getRobotTokensPosIndexes().size() == 1) {
final int theFirstPreviousContinue = posInfo.getPreviousLineContinuePosIndexes().get(0);
final int theFirstToken = posInfo.getRobotTokensPosIndexes().get(0);
if (theFirstToken < theFirstPreviousContinue) {
final SeparatorType separatorType = posInfo.getLineSeparator();
final List<Integer> separatorsPosIndexes = posInfo.getSeparatorsPosIndexes();
if (separatorType == SeparatorType.PIPE) {
if (separatorsPosIndexes.size() >= 2) {
final int theFirstSeparator = separatorsPosIndexes.get(0);
final int theSecondSeparator = separatorsPosIndexes.get(1);
result = theFirstSeparator < theFirstToken && theFirstToken < theSecondSeparator
&& theSecondSeparator < theFirstPreviousContinue;
}
} else {
if (separatorsPosIndexes.size() == 1) {
final int theFirstSeparator = separatorsPosIndexes.get(0);
result = theFirstToken < theFirstSeparator && theFirstSeparator < theFirstPreviousContinue;
}
}
}
}
return result;
}
private static boolean isReallyFirstElement(final PositionInformation posInfo, final RobotToken currentToken) {
boolean result = false;
final SeparatorType separator = posInfo.getLineSeparator();
if (separator == SeparatorType.PIPE) {
if (posInfo.getSeparatorsPosIndexes().size() == 1 && (posInfo.getRobotTokensPosIndexes().size() == 1
|| posInfo.getPreviousLineContinuePosIndexes().size() == 1)) {
result = posInfo.isFirstSeparator();
}
} else {
boolean meetFirstColumnPosition = (currentToken.getStartColumn() == 0
|| (!posInfo.getPrettyAlignPosIndexes().isEmpty()
&& posInfo.getPrettyAlignPosIndexes().get(0) == 0));
result = meetFirstColumnPosition
&& (posInfo.getRobotTokensPosIndexes().size() == 1
|| posInfo.getPreviousLineContinuePosIndexes().size() == 1)
&& posInfo.getSeparatorsPosIndexes().isEmpty() && !posInfo.isFirstSeparator();
}
return result;
}
}
public boolean isCorrectPosition(final PositionExpected expected, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken) {
final PositionInformation posInfo = buildPositionDescription(model, currentLine, currentToken);
return expected.isExpectedPosition(posInfo, model, currentLine, currentToken);
}
public interface IPositionCheckable {
boolean isExpectedPosition(final PositionInformation posInfo, final RobotFile model,
final RobotLine currentLine, final RobotToken currentToken);
}
}