package org.freeplane.plugin.remote.server;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.docear.messages.Messages.ListenToUpdateOccurrenceRespone;
import org.freeplane.features.map.NodeModel;
import org.freeplane.plugin.remote.v10.model.updates.AddNodeUpdate;
import org.freeplane.plugin.remote.v10.model.updates.ChangeNodeAttributeUpdate;
import org.freeplane.plugin.remote.v10.model.updates.DeleteNodeUpdate;
import org.freeplane.plugin.remote.v10.model.updates.MapUpdate;
import org.freeplane.plugin.remote.v10.model.updates.MoveNodeUpdate;
import akka.actor.ActorRef;
public class OpenMindmapInfo implements Serializable {
private static final long serialVersionUID = 1L;
private final URL mapUrl;
private final Set<NodeModel> lockedNodes;
private long lastAccessTime;
private long lastUpdateTime;
private final String name;
private final List<MapUpdate> updateList;
private final List<ActorRef> listeningActors;
public OpenMindmapInfo(URL mapUrl, String name) {
this.mapUrl = mapUrl;
this.name = name;
this.lockedNodes = new HashSet<NodeModel>();
this.updateList = new ArrayList<MapUpdate>();
this.listeningActors = new ArrayList<ActorRef>();
updateAccessTime();
}
public URL getMapUrl() {
updateAccessTime();
return mapUrl;
}
public Set<NodeModel> getLockedNodes() {
updateUpdateTime();
return lockedNodes;
}
public void addLockedNode(NodeModel freeplaneNode) {
updateAccessTime();
updateUpdateTime();
lockedNodes.add(freeplaneNode);
}
public void removeLockedNode(NodeModel freeplaneNode) {
updateAccessTime();
updateUpdateTime();
lockedNodes.remove(freeplaneNode);
}
public long getLastAccessTime() {
return lastAccessTime;
}
public long getLastUpdateTime() {
return lastUpdateTime;
}
public String getName() {
return name;
}
private void updateAccessTime() {
lastAccessTime = System.currentTimeMillis();
}
//update and revision related
private void updateUpdateTime() {
lastUpdateTime = System.currentTimeMillis();
}
public int getCurrentRevision() {
return updateList.size();
}
public void addUpdate(MapUpdate updateStatement) {
RemoteController.getLogger().debug("OpenMindmapInfo.addUpdate => update added: "+updateStatement.getClass().getSimpleName());
updateList.add(updateStatement);
updateUpdateTime();
//tell listeners that change has happened
for(ActorRef ref : listeningActors) {
ref.tell(new ListenToUpdateOccurrenceRespone(true), null);
}
//empty list, because they have to register again
listeningActors.clear();
}
public void registerUpdateListener(ActorRef actor) {
listeningActors.add(actor);
}
public List<String> getUpdateListAsJson(long sinceRevisionNumber) {
return getShortUpdateListAsJson((int)sinceRevisionNumber);
}
public List<String> getShortUpdateListAsJson(int sinceRevision) {
final List<String> shortList = new ArrayList<String>();
for(int i = sinceRevision; i < updateList.size(); i++) {
final MapUpdate update = updateList.get(i);
boolean hasMatch = false;
if(update instanceof AddNodeUpdate) {
hasMatch = hasMatch((AddNodeUpdate)update, i+1);
} else if(update instanceof ChangeNodeAttributeUpdate) {
hasMatch = hasMatch((ChangeNodeAttributeUpdate) update, i+1);
} else if(update instanceof MoveNodeUpdate) {
hasMatch = hasMatch((MoveNodeUpdate)update, i+1);
}
if(!hasMatch)
shortList.add(update.toJson());
}
return shortList;
}
private boolean hasMatch(AddNodeUpdate update, int sinceRevision) {
//has to check, if node has been deleted in future
for(int j = sinceRevision; j < updateList.size(); j++) { //check against all coming events
final MapUpdate curUpdate = updateList.get(j);
if(curUpdate instanceof DeleteNodeUpdate) {
final DeleteNodeUpdate delUpdate = (DeleteNodeUpdate)curUpdate;
if (delUpdate.getNodeId().equals(update.getNewNodeId())) {
return true;
}
}
}
return false;
}
private boolean hasMatch(ChangeNodeAttributeUpdate update, int sinceRevision) {
//has to check, if node has been deleted in future
//has to check, if attribute has been changed in future
for(int j = sinceRevision; j < updateList.size(); j++) { //check against all coming events
final MapUpdate curUpdate = updateList.get(j);
if(curUpdate instanceof DeleteNodeUpdate) {
final DeleteNodeUpdate delUpdate = (DeleteNodeUpdate)curUpdate;
if (delUpdate.getNodeId().equals(update.getNodeId())) {
return true;
}
} else if(curUpdate instanceof ChangeNodeAttributeUpdate) {
final ChangeNodeAttributeUpdate changeUpdate =(ChangeNodeAttributeUpdate) curUpdate;
if(changeUpdate.getNodeId().equals(update.getNodeId())
&& changeUpdate.getAttribute().equals(update.getAttribute())) {
return true;
}
}
}
return false;
}
private boolean hasMatch(MoveNodeUpdate update, int sinceRevision) {
//has to check, if node has been deleted in future
for(int j = sinceRevision; j < updateList.size(); j++) { //check against all coming events
final MapUpdate curUpdate = updateList.get(j);
if(curUpdate instanceof DeleteNodeUpdate) {
final DeleteNodeUpdate delUpdate = (DeleteNodeUpdate)curUpdate;
if (delUpdate.getNodeId().equals(update.getNodetoMoveId())) {
return true;
}
}
}
return false;
}
}