/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.rf.ide.core.testdata.text.write.tables; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.rf.ide.core.testdata.model.AModelElement; import org.rf.ide.core.testdata.model.FilePosition; import org.rf.ide.core.testdata.model.RobotFile; import org.rf.ide.core.testdata.model.table.ARobotSectionTable; import org.rf.ide.core.testdata.model.table.IExecutableStepsHolder; import org.rf.ide.core.testdata.model.table.RobotExecutableRow; import org.rf.ide.core.testdata.model.table.TableHeader; import org.rf.ide.core.testdata.text.read.EndOfLineBuilder.EndOfLineTypes; import org.rf.ide.core.testdata.text.read.IRobotLineElement; import org.rf.ide.core.testdata.text.read.IRobotTokenType; 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.write.DumpLineUpdater; import org.rf.ide.core.testdata.text.write.DumperHelper; import org.rf.ide.core.testdata.text.write.EmptyLineDumper; import org.rf.ide.core.testdata.text.write.SectionBuilder.Section; import org.rf.ide.core.testdata.text.write.SectionBuilder.SectionType; public abstract class AExecutableTableDumper implements ISectionTableDumper { private final DumperHelper aDumpHelper; private final DumpLineUpdater lineUpdater; private final List<IExecutableSectionElementDumper> dumpers; public AExecutableTableDumper(final DumperHelper aDumpHelper, final List<IExecutableSectionElementDumper> dumpers) { this.aDumpHelper = aDumpHelper; this.lineUpdater = new DumpLineUpdater(aDumpHelper); this.dumpers = dumpers; } protected DumperHelper getDumperHelper() { return this.aDumpHelper; } protected EmptyLineDumper getEmptyDumperHelper() { return getDumperHelper().getEmptyLineDumper(); } protected DumpLineUpdater getLineDumperHelper() { return this.lineUpdater; } @SuppressWarnings("unchecked") @Override public void dump(final RobotFile model, final List<Section> sections, final int sectionWithHeaderPos, final TableHeader<? extends ARobotSectionTable> th, final List<AModelElement<ARobotSectionTable>> sorted, final List<RobotLine> lines) { getDumperHelper().getHeaderDumpHelper().dumpHeader(model, th, lines); getDumperHelper().getHashCommentDumper().dumpHashCommentsIfTheyExists(th, null, model, lines); getEmptyDumperHelper().dumpEmptyLines(model, lines, (AModelElement<ARobotSectionTable>) th, sorted.isEmpty()); if (!sorted.isEmpty()) { final List<Section> execUnits = SectionType.filterByType(sections, sectionWithHeaderPos, getSectionType()); final int lastIndexToDump = getDumperHelper().getLastSortedToDump(model, execUnits, new ArrayList<>(sorted)); AModelElement<?> last = null; for (int execUnitIndex = 0; execUnitIndex <= lastIndexToDump; execUnitIndex++) { addLineSeparatorIfIsRequired(model, lines); final AModelElement<ARobotSectionTable> execUnit = sorted.get(execUnitIndex); if (execUnitIndex > 0) { getDumperHelper().getHashCommentDumper().dumpHashCommentsIfTheyExists(sorted.get(execUnitIndex - 1), execUnit, model, lines); } @SuppressWarnings("rawtypes") final IExecutableStepsHolder execHolder = (IExecutableStepsHolder) execUnit; final RobotToken elemDeclaration = execHolder.getHolder().getDeclaration(); final FilePosition filePosition = elemDeclaration.getFilePosition(); int fileOffset = -1; if (filePosition != null && !filePosition.isNotSet()) { fileOffset = filePosition.getOffset(); } final RobotLine currentLine = getLineForToken(model, fileOffset); addSeparatorInTheBeginning(model, lines, elemDeclaration, currentLine); if (!elemDeclaration.isDirty() && currentLine != null) { getLineDumperHelper().updateLine(model, lines, elemDeclaration); addSuffixAfterTokenDeclaration(model, lines, elemDeclaration, currentLine); } else { getLineDumperHelper().updateLine(model, lines, elemDeclaration); } final List<AModelElement<? extends IExecutableStepsHolder<?>>> sortedUnits = getSortedUnits(execHolder); final int sortedUnitsSize = sortedUnits.size(); for (int sortedUnitId = 0; sortedUnitId < sortedUnitsSize; sortedUnitId++) { final AModelElement<? extends IExecutableStepsHolder<?>> execElement = sortedUnits .get(sortedUnitId); addLineSeparatorIfIsRequiredAfterExecElement(model, lines, execHolder, execElement); IExecutableSectionElementDumper elemDumper = null; for (final IExecutableSectionElementDumper dumper : dumpers) { if (dumper.isServedType(execElement)) { elemDumper = dumper; break; } } elemDumper.dump(model, sections, sectionWithHeaderPos, th, sortedUnits, execElement, lines); getEmptyDumperHelper().dumpEmptyLines(model, lines, execUnit, execUnitIndex == lastIndexToDump); last = execElement; } if (sortedUnits.isEmpty()) { last = null; } getEmptyDumperHelper().dumpEmptyLines(model, lines, execUnit, execUnitIndex == lastIndexToDump); } if (last != null) { getDumperHelper().getHashCommentDumper().dumpHashCommentsIfTheyExists(last, null, model, lines); } if (lastIndexToDump == sorted.size() - 1) { sorted.clear(); } else { for (int elemIndex = 0; elemIndex <= lastIndexToDump; elemIndex++) { sorted.remove(0); } } } } private void addLineSeparatorIfIsRequiredAfterExecElement(final RobotFile model, final List<RobotLine> lines, final IExecutableStepsHolder<AModelElement<? extends ARobotSectionTable>> execHolder, final AModelElement<? extends IExecutableStepsHolder<?>> execElement) { if (!lines.isEmpty()) { final RobotLine lastLine = lines.get(lines.size() - 1); final IRobotLineElement endOfLine = lastLine.getEndOfLine(); if ((endOfLine == null || endOfLine.getFilePosition().isNotSet() || endOfLine.getTypes().contains(EndOfLineTypes.NON) || endOfLine.getTypes().contains(EndOfLineTypes.EOF)) && !lastLine.getLineElements().isEmpty()) { final boolean shouldSeparateLine = shouldSeparateLine(execHolder, execElement); if (shouldSeparateLine) { final IRobotLineElement lineSeparator = getDumperHelper().getLineSeparator(model); getLineDumperHelper().updateLine(model, lines, lineSeparator); } } } } private void addSuffixAfterTokenDeclaration(final RobotFile model, final List<RobotLine> lines, final RobotToken elemDeclaration, final RobotLine currentLine) { final List<IRobotLineElement> lineElements = currentLine.getLineElements(); final int tokenPosIndex = lineElements.indexOf(elemDeclaration); if (lineElements.size() - 1 > tokenPosIndex + 1) { for (int index = tokenPosIndex + 1; index < lineElements.size(); index++) { final IRobotLineElement nextElem = lineElements.get(index); final List<IRobotTokenType> types = nextElem.getTypes(); if (types.contains(RobotTokenType.PRETTY_ALIGN_SPACE) || types.contains(RobotTokenType.ASSIGNMENT)) { getLineDumperHelper().updateLine(model, lines, nextElem); } else { break; } } } } private void addSeparatorInTheBeginning(final RobotFile model, final List<RobotLine> lines, final RobotToken elemDeclaration, final RobotLine currentLine) { if (currentLine != null) { getDumperHelper().getSeparatorDumpHelper().dumpSeparatorsBeforeToken(model, currentLine, elemDeclaration, lines); } else if (getDumperHelper().isSeparatorForExecutableUnitName( getDumperHelper().getSeparator(model, lines, elemDeclaration, elemDeclaration))) { if (!getDumperHelper().wasSeparatorBefore(lines)) { final Separator sep = getDumperHelper().getSeparator(model, lines, elemDeclaration, elemDeclaration); if (sep.getText().equals(" | ")) { sep.setText("| "); sep.setRaw("| "); } getDumperHelper().getDumpLineUpdater().updateLine(model, lines, sep); } } } private RobotLine getLineForToken(final RobotFile model, final int fileOffset) { RobotLine currentLine = null; if (fileOffset >= 0) { final Optional<Integer> lineIndex = model.getRobotLineIndexBy(fileOffset); if (lineIndex.isPresent()) { currentLine = model.getFileContent().get(lineIndex.get()); } } return currentLine; } private void addLineSeparatorIfIsRequired(final RobotFile model, final List<RobotLine> lines) { if (!lines.isEmpty()) { final RobotLine lastLine = lines.get(lines.size() - 1); final IRobotLineElement endOfLine = lastLine.getEndOfLine(); if ((endOfLine == null || endOfLine.getFilePosition().isNotSet() || endOfLine.getTypes().contains(EndOfLineTypes.NON) || endOfLine.getTypes().contains(EndOfLineTypes.EOF)) && !lastLine.getLineElements().isEmpty()) { final IRobotLineElement lineSeparator = getDumperHelper().getLineSeparator(model); getLineDumperHelper().updateLine(model, lines, lineSeparator); } } } private boolean shouldSeparateLine( final IExecutableStepsHolder<AModelElement<? extends ARobotSectionTable>> execUnit, final AModelElement<? extends IExecutableStepsHolder<?>> execElement) { boolean shouldSeparateLine = true; final IRobotLineElement execUnitDec = execUnit.getHolder().getDeclaration(); if (execUnitDec.getStartOffset() >= 0) { final RobotFile model = execUnit.getHolder().getParent().getParent(); final Optional<Integer> robotLineIndexBy = model.getRobotLineIndexBy(execUnitDec.getStartOffset()); if (robotLineIndexBy.isPresent()) { final RobotLine lastLine = model.getFileContent().get(robotLineIndexBy.get()); final Optional<Integer> execUnitPos = lastLine.getElementPositionInLine(execUnitDec); final IRobotLineElement execElemDec = execElement.getDeclaration(); final Optional<Integer> execElemPos = lastLine.getElementPositionInLine(execElemDec); if (execUnitPos.isPresent() && execElemPos.isPresent()) { shouldSeparateLine = false; } } } return shouldSeparateLine; } public abstract List<AModelElement<? extends IExecutableStepsHolder<?>>> getSortedUnits( final IExecutableStepsHolder<?> execHolder); @SuppressWarnings({ "unchecked", "rawtypes" }) public void revertExecutableRowToCorrectPlace( final List<AModelElement<? extends IExecutableStepsHolder<?>>> sortedUnits, final IExecutableStepsHolder<?> execHolder) { if (execHolder.getExecutionContext().isEmpty()) { return; } final int size = sortedUnits.size(); int indexInExec = 0; for (int i = 0; i < size; i++) { final AModelElement<? extends IExecutableStepsHolder<?>> elem = sortedUnits.get(i); if (elem instanceof RobotExecutableRow) { sortedUnits.set(i, (RobotExecutableRow) execHolder.getExecutionContext().get(indexInExec++)); } } } }