package org.freeplane.plugin.remote.client;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.freeplane.core.util.LogUtils;
import org.freeplane.features.map.INodeSelectionListener;
import org.freeplane.features.map.NodeModel;
import org.freeplane.features.map.mindmapmode.MMapController;
import org.freeplane.features.mapio.MapIO;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.mode.mindmapmode.MModeController;
import org.freeplane.plugin.remote.client.actors.ApplyChangesActor;
import org.freeplane.plugin.remote.client.actors.InitCollaborationActor;
import org.freeplane.plugin.remote.client.actors.ListenForUpdatesActor;
import org.freeplane.plugin.remote.client.listeners.MapChangeListener;
import org.freeplane.plugin.remote.client.listeners.NodeChangeListener;
import org.freeplane.plugin.remote.client.listeners.NodeViewListener;
import org.freeplane.plugin.remote.client.services.DocearOnlineWs;
import org.freeplane.plugin.remote.client.services.WS;
import scala.concurrent.duration.Duration;
import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.TypedActor;
import akka.actor.TypedProps;
import akka.actor.UntypedActorFactory;
import akka.japi.Creator;
import akka.pattern.Patterns;
import akka.util.Timeout;
import com.typesafe.config.ConfigFactory;
public class ClientController {
// Temp variables, only for developping
public static final String MAP_ID = "5";
public static final String USER = "Julius";
public static final String PW = "secret";
private final ActorSystem system;
private final ActorRef listenForUpdatesActor;
private final ActorRef applyChangeActor;
private final ActorRef initCollaborationactor;
private final WS webservice;
private User user = null;
private final String sourceString;
private boolean isUpdating = false;
private final Map<NodeModel, NodeViewListener> selectedNodesMap = new HashMap<NodeModel, NodeViewListener>();
@SuppressWarnings("serial")
public ClientController() {
// set sourceString, used to identify for updates
try {
final String computername = InetAddress.getLocalHost().getHostName();
sourceString = computername + "_" + System.currentTimeMillis();
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
// create Threadpool
// executor =
// MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(10));
// change class loader
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(Activator.class.getClassLoader());
LogUtils.info("starting Client Plugin...");
system = ActorSystem.create("freeplaneClient", ConfigFactory.load().getConfig("local"));
listenForUpdatesActor = system.actorOf(new Props(new UntypedActorFactory() {
@Override
public Actor create() throws Exception {
return new ListenForUpdatesActor(ClientController.this);
}
}), "updateListener");
applyChangeActor = system.actorOf(new Props(new UntypedActorFactory() {
@Override
public Actor create() throws Exception {
return new ApplyChangesActor(ClientController.this);
}
}), "changeApplier");
initCollaborationactor = system.actorOf(new Props(new UntypedActorFactory() {
@Override
public Actor create() throws Exception {
return new InitCollaborationActor(ClientController.this);
}
}), "initCollaboration");
webservice = TypedActor.get(system).typedActorOf(new TypedProps<DocearOnlineWs>(WS.class, new Creator<DocearOnlineWs>() {
@Override
public DocearOnlineWs create() throws Exception {
return new DocearOnlineWs(ClientController.this);
}
}).withTimeout(Timeout.apply(3, TimeUnit.MINUTES)));
this.registerListeners();
initCollaborationactor.tell(new InitCollaborationActor.Messages.InitCollaborationMode(MAP_ID, USER, PW), null);
// set back to original class loader
Thread.currentThread().setContextClassLoader(contextClassLoader);
}
public static final class CheckForChangesRunnable implements Runnable {
private final ClientController clientController;
public CheckForChangesRunnable(ClientController clientController) {
super();
this.clientController = clientController;
}
@Override
public void run() {
final Map<NodeModel, NodeViewListener> selectedNodesMap = clientController.selectedNodesMap();
for (Map.Entry<NodeModel, NodeViewListener> nodePair : selectedNodesMap.entrySet()) {
final Map<String, Object> attributeValueMap = nodePair.getValue().getChangedAttributes();
final User user = clientController.getUser();
for (Map.Entry<String, Object> entry : attributeValueMap.entrySet()) {
clientController.webservice().changeNode(user.getUsername(), user.getAccessToken(), "5", nodePair.getKey().getID(), entry.getKey(), entry.getValue());
}
nodePair.getValue().updateCurrentState();
}
}
}
/**
* registers all listeners to react on necessary events like created nodes
* Might belong into a new plugin, which sends changes to the server
*/
private void registerListeners() {
// mmapController().addMapLifeCycleListener(new MapLifeCycleListener());
mmapController().addMapChangeListener(new MapChangeListener(this));
mmapController().addNodeChangeListener(new NodeChangeListener(this));
mmapController().addNodeSelectionListener(new INodeSelectionListener() {
@Override
public void onSelect(NodeModel node) {
final NodeViewListener listener = new NodeViewListener(ClientController.this, node, null, null);
node.addViewer(listener);
selectedNodesMap.put(node, listener);
}
@Override
public void onDeselect(NodeModel node) {
final NodeViewListener listener = selectedNodesMap.remove(node);
if (listener != null) {
final Map<String, Object> attributeValueMap = listener.getChangedAttributes();
for (Map.Entry<String, Object> entry : attributeValueMap.entrySet()) {
webservice().changeNode(user.getUsername(), user.getAccessToken(), "5", node.getID(), entry.getKey(), entry.getValue());
}
node.removeViewer(listener);
}
}
});
}
public void stop() {
LogUtils.info("Shutting down client plugin...");
Patterns.gracefulStop(applyChangeActor, Duration.create(5, TimeUnit.SECONDS), system());
Patterns.gracefulStop(listenForUpdatesActor, Duration.create(5, TimeUnit.SECONDS), system());
Patterns.gracefulStop(initCollaborationactor, Duration.create(5, TimeUnit.SECONDS), system());
system.shutdown();
}
public static ModeController getModeController() {
return MModeController.getMModeController();
}
public static MapIO getMapIO() {
return getModeController().getExtension(MapIO.class);
}
public static MMapController mmapController() {
return (MMapController) getModeController().getMapController();
}
public WS webservice() {
return webservice;
}
public String source() {
return sourceString;
}
public boolean isUpdating() {
return isUpdating;
}
public void isUpdating(boolean value) {
isUpdating = value;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public static String loggedInUserName() {
return USER;
}
public ActorRef applyChangesActor() {
return applyChangeActor;
}
public ActorRef listenForUpdatesActor() {
return listenForUpdatesActor;
}
public Map<NodeModel, NodeViewListener> selectedNodesMap() {
return selectedNodesMap;
}
public ActorSystem system() {
return system;
}
}