/**
* Replication Benchmarker
* https://github.com/score-team/replication-benchmarker/ Copyright (C) 2013
* LORIA / Inria / SCORE Team
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package jbenchmarker.core;
import crdt.CRDT;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* local operation of document. T is a Character or a String.
*
* @author urso
*/
public class SequenceOperation<T> implements LocalOperation, Serializable {
public enum OpType {
insert, delete, replace, update, move, unsupported, noop, revert, undo
};
@Override
public SequenceOperation clone() {
throw new UnsupportedOperationException("Not implemented yet");
/* return new SequenceOperation(type, this.getReplica(), position, numberOf,
new ArrayList(content), new VectorClock(this.getVectorClock()));*/
}
@Override
public LocalOperation adaptTo(CRDT replica) {
int sizeDoc = ((MergeAlgorithm) replica).getDoc().viewLength();
//
if (getType() == OpType.insert) {
if (position > sizeDoc) {
position = sizeDoc; // an insert position exceeds document size
}
} else if (this.type == OpType.delete && sizeDoc == 0) {
return new SequenceOperation(OpType.noop, 0, 0, null);
} else if (this.position >= sizeDoc) {
position = sizeDoc - 1; // a position exceeds document size
}
if ((getType() == OpType.delete || getType() == OpType.update) && position + argument > sizeDoc) {
argument = sizeDoc - position; // delete document at position exceeds document size
}
if ((getType() == OpType.update || getType() == OpType.move) && position + content.size() > sizeDoc) {
content = content.subList(0, sizeDoc - position); // update document at position exceeds document size
}
return this;
}
private OpType type; // type of operation : insert or delete
private int position; // position in the document
private int argument; // length of a del or move position
private List<T> content; // content of an ins / update / move
public List<T> getContent() {
return content;
}
public String getContentAsString() {
StringBuilder s = new StringBuilder();
for (T t : content) {
s.append(t.toString());
}
return s.toString();
}
public int getLenghOfADel() {
return argument;
}
public int getPosition() {
return position;
}
public void setPosition(int p) {
position = p;
}
public int getDestination() {
return argument;
}
public OpType getType() {
return type;
}
public SequenceOperation(OpType type, int position, int argument, List<T> content) {
//super(replica, VC);
this.type = type;
this.position = position;
this.argument = argument;
this.content = content;
}
/*
* Construction of an insert operation (character)
*/
static public SequenceOperation<Character> insert(int position, String content) {
List<Character> l = new ArrayList<Character>();
for (int i = 0; i < content.length(); ++i) {
l.add(content.charAt(i));
}
return new SequenceOperation(OpType.insert, position, 0, l);
}
/*
* Construction of an delete operation
*/
static public SequenceOperation delete(int position, int offset) {
return new SequenceOperation(OpType.delete, position, offset, null);
}
/*
* Construction of a replace operation
*/
static public SequenceOperation<Character> replace(int position, int offset, String content) {
List<Character> l = new ArrayList<Character>();
for (int i = 0; i < content.length(); ++i) {
l.add(content.charAt(i));
}
return new SequenceOperation<Character>(OpType.replace, position, offset, l);
}
/*
* Construction of an update operation
*/
static public SequenceOperation<Character> update(int position, String content) {
List<Character> l = new ArrayList<Character>();
for (int i = 0; i < content.length(); ++i) {
l.add(content.charAt(i));
}
return new SequenceOperation<Character>(OpType.update, position, l.size(), l);
}
/*
* Construction of a move operation (potentially new content)
*/
static public SequenceOperation<Character> move(int position, int destination, String content) {
List<Character> l = new ArrayList<Character>();
for (int i = 0; i < content.length(); ++i) {
l.add(content.charAt(i));
}
return new SequenceOperation<Character>(OpType.move, position, destination, l);
}
static public <T> SequenceOperation<T> replace(int position, int offset, List<T> content) {
return new SequenceOperation(OpType.replace, position, offset, content);
}
/**
* Construction of a noop operation (usefull for pure merge)
*/
public static SequenceOperation noop() {
return new SequenceOperation(OpType.noop, -1, -1, null);
}
/*
* Construction of a stylage operation
*/
static public SequenceOperation<Character> unsupported() {
return new SequenceOperation(OpType.unsupported, -1, -1, null);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof SequenceOperation)) {
return false;
}
final SequenceOperation other = (SequenceOperation) obj;
if (this.type != other.type) {
return false;
}
if (this.position != other.position) {
return false;
}
if (this.argument != other.argument) {
return false;
}
if ((this.content == null) ? (other.content != null) : !this.content.equals(other.content)) {
return false;
}
return super.equals(obj);
}
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + (this.type != null ? this.type.hashCode() : 0);
hash = 89 * hash + this.position;
hash = 89 * hash + this.argument;
hash = 89 * hash + (this.content != null ? this.content.hashCode() : 0);
return 89 * hash + super.hashCode();
}
@Override
public String toString() {
return "SequenceOperation{" + "type=" + type + ", position=" + position + ", arg=" + argument + ", content=" + content + '}';
}
}