// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package com.amalto.workbench.widgets.composites;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import com.amalto.workbench.i18n.Messages;
/**
* created by liusongbo on Sep 11, 2015
*
*/
public class ElementFKInfoAnnotaioner {
private static Log log = LogFactory.getLog(ElementFKInfoAnnotaioner.class);
private static String separator = "+"; //$NON-NLS-1$
private static final String TYPE = "org.eclipse.ui.workbench.texteditor.error"; //$NON-NLS-1$
private ProjectionAnnotationModel annotationModel;
private IDocument document;
private List<String> xPaths;
public ElementFKInfoAnnotaioner(ProjectionAnnotationModel annotationModel, IDocument document) {
this.annotationModel = annotationModel;
this.document = document;
}
public Set<Annotation> updateAnnotations(ProjectionAnnotationModel annoModel, DocumentEvent event) {
if (event != null) {
this.document = event.fDocument;
}
if (annoModel != null) {
this.annotationModel = annoModel;
}
if (document != null) {
try {
List<ITypedRegion> partitions = Arrays.asList(document.computePartitioning(0, document.getLength()));
Map<Annotation, Position> addedAnnotations = buildAnnotations(partitions);
addAnnotationToModel(addedAnnotations);
return addedAnnotations.keySet();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return new HashSet<Annotation>();
}
private Map<Annotation, Position> buildAnnotations(List<ITypedRegion> partitions)
throws BadLocationException {
Map<Annotation, Position> annotations = new HashMap<Annotation, Position>();
// check if different partitions are connected by '+'
int i = 0;
for (; i < partitions.size(); i++) {
ITypedRegion partion = partitions.get(i);
String partionContent = document.get(partion.getOffset(), partion.getLength());
if (partion.getType().equals(IDocument.DEFAULT_CONTENT_TYPE)) {
if (i == 0 || i == partitions.size() - 1) {
if (i == 0) {
if (partionContent.trim().startsWith(separator)) {
addToAnnotations(0, partionContent.length(), Messages.ElementFKInfoAnnotaioner_shouldNotAtStart, annotations);
}
if (i != partitions.size() - 1 && !partionContent.trim().endsWith(separator)
&& !partionContent.trim().isEmpty()) {
addToAnnotations(partion.getOffset(), partionContent.length(), Messages.ElementFKInfoAnnotaioner_missingAfter,
annotations);
}
}
if (i == partitions.size() - 1) {
if (partionContent.trim().endsWith(separator)) {
addToAnnotations(partion.getOffset(), partionContent.length(), Messages.ElementFKInfoAnnotaioner_shouldNotAtEnd,
annotations);
}
if (i != 0 && !partionContent.trim().startsWith(separator) && !partionContent.trim().isEmpty()) {
addToAnnotations(partion.getOffset(), partionContent.length(), Messages.ElementFKInfoAnnotaioner_missingBefore,
annotations);
}
}
} else {
if (!partionContent.trim().startsWith(separator)) {
addToAnnotations(partion.getOffset(), partionContent.length(), Messages.ElementFKInfoAnnotaioner_missingBefore,
annotations);
}
if (!partionContent.trim().endsWith(separator)) {
addToAnnotations(partion.getOffset(), partionContent.length(), Messages.ElementFKInfoAnnotaioner_missingAfter,
annotations);
}
}
}
}
// check if partition is valid
for (ITypedRegion partition : partitions) {
if (IDocument.DEFAULT_CONTENT_TYPE.equals(partition.getType())) {
int partionOffset = partition.getOffset();
int partionLength = partition.getLength();
String partion = document.get(partionOffset, partionLength);
partionLength = partion.trim().length();
int index = partion.indexOf(partion.trim());
partionOffset += index;
partion = partion.trim();
if (partion.startsWith(separator)) {
partion = partion.substring(1).trim();
partionOffset++;
partionLength--;
}
if (partion.endsWith(separator)) {
partion = partion.substring(0, partion.length() - 1).trim();
partionLength--;
}
if (partion.contains(separator)) {
handleMergedXpaths(partion, partition, xPaths, annotations);
} else {
if (!xPaths.contains(partion) && !partion.isEmpty()) {
addToAnnotations(partionOffset, partionLength,
Messages.bind(Messages.ElementFKInfoAnnotaioner_invalidXpath, partion), annotations);
}
}
}
}
return annotations;
}
/**
* @param partion
*/
private boolean handleMergedXpaths(String partion, ITypedRegion partition, List<String> xpaths,
Map<Annotation, Position> annotations) throws BadLocationException {
int offset = partition.getOffset();
int length = partition.getLength();
String originPartion = document.get(offset, length);
if (originPartion.startsWith(separator)) {
offset++;
}
for (int i = 0; i < partion.length(); i++) {
if (partion.charAt(i) == '+') {
int j = i + 1;
for (; j < partion.length(); j++) {
if (partion.charAt(j) != '+') {
break;
}
}
int len = j - i;
if ((i == 0 || i == partion.length() - 1) || len > 1) {
addToAnnotations(offset + i, len,
Messages.bind(Messages.ElementFKInfoAnnotaioner_redundant, partion.substring(i, j)), annotations);
}
i = j - 1;
} else {
int j = i + 1;
for (; j < partion.length(); j++) {
if (partion.charAt(j) == '+') {
break;
}
}
int len = j - i;
if (!xpaths.contains(partion.substring(i, j).trim())) {
addToAnnotations(offset + i, len,
Messages.bind(Messages.ElementFKInfoAnnotaioner_invalidXpath, partion.substring(i, j)),
annotations);
}
i = j - 1;
}
}
return true;
}
private void addToAnnotations(int offset, int length, String msg, Map<Annotation, Position> annotations) {
Annotation annotation = new Annotation(TYPE, false, msg);
Position position = new Position(offset);
position.setLength(length);
annotations.put(annotation, position);
}
private void addAnnotationToModel(Map<Annotation, Position> addedAnnotations) {
annotationModel.removeAllAnnotations();
Iterator<Annotation> iterator = addedAnnotations.keySet().iterator();
for (; iterator.hasNext();) {
Annotation anno = iterator.next();
annotationModel.addAnnotation(anno, addedAnnotations.get(anno));
}
}
public Set<Annotation> setFKInfos(List<String> xPaths) {
this.xPaths = xPaths;
Set<Annotation> updatedAnnotations = updateAnnotations(null, null);
return updatedAnnotations;
}
}