/**
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.waveprotocol.wave.model.document.util;
import org.waveprotocol.wave.model.document.ReadableWDocument;
import org.waveprotocol.wave.model.document.operation.Nindo;
import org.waveprotocol.wave.model.util.Preconditions;
/**
* A builder for applying annotations for a single key to a document in a linear order.
*
* This builder will generate the minimal mutation sequence to apply the requested
* annotations.
*
* NOTE(user): This class is a temporary demo hack to minimise the number
* of mutations emitted. It can modify the semantics of the intended operations
* in the presence of transformation. Only use this class if you know what you
* are doing.
*
*/
@Deprecated
public class AnnotationBuilder<N, E extends N, T extends N> {
/** The builder we will use to construct the annotation */
private final Nindo.Builder b = new Nindo.Builder();
/** The document we will be applying the ops to */
private final ReadableWDocument<N,E,T> doc;
/** The key that we are applying annotations for */
private final String key;
/** Accumulated skips that are yet to be applied */
private int skipAccum;
/** Current position in the range */
private int currentPos;
/** The limit of the range that we are applying to */
private final int rangeEnd;
/** Whether we have actually applied anything yet */
private boolean dirty = false;
/**
* Construct a new annotation builder.
*
* @param doc indexed doc to apply the annotations to
* @param rangeStart document location to begin applying annotations from
* @param rangeEnd document location to apply annotations up to
* @param key key to apply annotations for
*/
public AnnotationBuilder(ReadableWDocument<N,E,T> doc, int rangeStart, int rangeEnd, String key) {
this.doc = doc;
this.skipAccum = rangeStart;
this.currentPos = rangeStart;
this.rangeEnd = rangeEnd;
this.key = key;
}
private static boolean equal(String left, String right) {
return left == null ? right == null : left.equals(right);
}
/**
* Sets the annotation to the given value up to the given location.
*
* @param value value to set for the annotation
* @param end absolute location to set up to
*/
public void setUpTo(String value, int end) {
Preconditions.checkPositionIndexes(currentPos, end, rangeEnd);
while (currentPos < end) {
String currentValue = doc.getAnnotation(currentPos, key);
int nextChange = doc.firstAnnotationChange(currentPos, end, key, currentValue);
if (nextChange == -1) {
nextChange = end;
}
int size = nextChange - currentPos;
if (size > 0) {
if (!equal(currentValue, value)) {
if (skipAccum > 0) {
b.skip(skipAccum);
skipAccum = 0;
}
b.startAnnotation(key, value);
b.skip(size);
b.endAnnotation(key);
dirty = true;
} else {
skipAccum += size;
}
}
currentPos = nextChange;
}
assert (currentPos == end);
}
/** @return the current position we have applied up to */
public int getCurrentPos() {
return currentPos;
}
/** @return true if we have build an annotation to apply */
public boolean getDirty() {
return dirty;
}
/** @return the built document mutation */
public Nindo build() {
return b.build();
}
}