/*
* #!
* Ontopia Vizigator
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* 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 net.ontopia.topicmaps.viz;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import com.touchgraph.graphlayout.graphelements.ImmutableGraphEltSet;
import com.touchgraph.graphlayout.graphelements.Locality;
import net.ontopia.topicmaps.core.TopicIF;
public class VizigatorUser extends TimerTask {
// Note: VizPanel uses this variable set the initial state of a menu.
public static final boolean INITIALLY_ENABLED = false;
protected static final int EXPAND_NODE = 0;
protected static final int FOCUS_NODE = 1;
protected static final int HIDE_NODE = 2;
protected static final int HIDE_EDGE = 3;
protected static final int UNDO = 4;
protected static final int REDO = 5;
protected int runCount;
protected int hideNodeCount;
protected int hideFocusNodeCount;
protected int hideEdgeCount;
protected int focusNodeCount;
protected int expandNodeCount;
protected int undoCount;
protected int redoCount;
VizController controller;
protected boolean enabled;
Random random;
long millis;
Timer timer;
public VizigatorUser(VizController controller, long millis) {
this.controller = controller;
this.millis = millis;
random = new Random();
runCount = 0;
hideNodeCount = 0;
hideFocusNodeCount = 0;
hideEdgeCount = 0;
focusNodeCount = 0;
expandNodeCount = 0;
undoCount = 0;
redoCount = 0;
timer = null;
enabled = INITIALLY_ENABLED;
setEnabled(enabled);
}
/**
* This method is called on schedule by the timer.
*/
public void run() {
if (!enabled)
return;
useVizigator();
runCount++;
}
protected void useVizigator() {
ImmutableGraphEltSet ges = controller.getView().getTGPanel().getGES();
int nodeCount = ges.nodeCount();
VizDebugUtils.debug("**** useVizigator() + nodes: " + nodeCount +
" runs: " + runCount + " ****");
VizDebugUtils.debug("******** operations summary " +
"- hideNode(" + hideNodeCount +
") hideFocusNode(" + hideFocusNodeCount +
") hideEdge(" + hideEdgeCount +
") expandNode(" + expandNodeCount +
") focusNode(" + focusNodeCount +
") undo(" + undoCount +
") redo(" + redoCount +
")");
int expandNodeWeight = 500;
int focusNodeWeight = 30;
int hideNodeWeight = 300;
int hideEdgeWeight = 200;
int undoWeight = 200;
int redoWeight = 200;
int hideFocusNodeProbability = 20;
if (nodeCount < 5) {
expandNodeWeight = 900;
hideNodeWeight = 70;
hideEdgeWeight = 30;
} else if (nodeCount < 10) {
expandNodeWeight = 750;
hideNodeWeight = 170;
hideEdgeWeight = 80;
} else if (nodeCount < 50) {
expandNodeWeight = 600;
hideNodeWeight = 270;
hideEdgeWeight = 130;
} else if (nodeCount < 100) {
expandNodeWeight = 400;
hideNodeWeight = 400;
hideEdgeWeight = 200;
} else if (nodeCount < 120) {
expandNodeWeight = 300;
hideNodeWeight = 470;
hideEdgeWeight = 230;
} else if (nodeCount < 140) {
expandNodeWeight = 200;
hideNodeWeight = 540;
hideEdgeWeight = 260;
} else if (nodeCount < 150) {
expandNodeWeight = 150;
hideNodeWeight = 580;
hideEdgeWeight = 270;
} else if (nodeCount < 160) {
expandNodeWeight = 100;
hideNodeWeight = 600;
hideEdgeWeight = 300;
} else if (nodeCount < 170) {
expandNodeWeight = 50;
hideNodeWeight = 630;
hideEdgeWeight = 320;
} else if (nodeCount < 180) {
expandNodeWeight = 40;
hideNodeWeight = 640;
hideEdgeWeight = 320;
} else if (nodeCount < 190) {
expandNodeWeight = 20;
hideNodeWeight = 650;
hideEdgeWeight = 330;
} else if (nodeCount < 200) {
expandNodeWeight = 10;
hideNodeWeight = 660;
hideEdgeWeight = 330;
} else {
expandNodeWeight = 2;
hideNodeWeight = 666;
hideEdgeWeight = 332;
}
int totalWeight = expandNodeWeight + hideNodeWeight + hideEdgeWeight +
focusNodeWeight + undoWeight + redoWeight;
int choice = random.nextInt(totalWeight);
int opcode;
if (choice < expandNodeWeight)
opcode = EXPAND_NODE;
else if (choice < expandNodeWeight + focusNodeWeight)
opcode = FOCUS_NODE;
else if (choice < expandNodeWeight + focusNodeWeight + hideNodeWeight)
opcode = HIDE_NODE;
else if (choice < expandNodeWeight + focusNodeWeight + hideNodeWeight
+ hideEdgeWeight)
opcode = HIDE_EDGE;
else if (choice < expandNodeWeight + focusNodeWeight + hideNodeWeight
+ hideEdgeWeight + undoWeight)
opcode = UNDO;
else
opcode = REDO;
if (opcode == EXPAND_NODE || opcode == FOCUS_NODE || opcode == HIDE_NODE) {
TMAbstractNode node = (TMAbstractNode)ges.getRandomNode();
if (node == null)
return;
if (opcode == EXPAND_NODE) {
controller.expandNode(node);
expandNodeCount++;
} else if (opcode == FOCUS_NODE) {
controller.focusNode(node);
focusNodeCount++;
} else if (opcode == HIDE_NODE) {
if (node == controller.getFocusNode()) {
if (random.nextInt(100) < hideFocusNodeProbability) {
controller.hideNode(node);
hideFocusNodeCount++;
}
} else {
controller.hideNode(node);
hideNodeCount++;
}
}
} else if (opcode == HIDE_EDGE) {
// Note: Using argument false (not distinct) since this gives a list.
// This makes finding an edge more efficient.
Collection edges = controller.getView().debug
.getObjectsOfType(TMAbstractEdge.class, false);
TMAbstractEdge edge = (TMAbstractEdge)pickRandom(edges);
if (edge == null)
return;
if (opcode == HIDE_EDGE) {
controller.hideEdge(edge);
hideEdgeCount++;
}
} else if (opcode == UNDO) {
controller.undo();
undoCount++;
} else if (opcode == REDO) {
controller.redo();
redoCount++;
}
}
protected TMAbstractNode pickRandomNode() {
TopicIF type = null;
TMAbstractNode node = null;
int tries = 50;
while (tries > 0 && node == null) {
tries++;
type = pickRandomType();
node = pickRandomNode(type);
}
return node;
}
protected Object pickRandom(Collection items) {
int size = items.size();
if (size == 0)
return null;
int index = random.nextInt(size);
if (items instanceof List) {
List itemsList = (List)items;
return itemsList.get(index);
}
Iterator itemsIt = items.iterator();
for (int i = 0; i < index; i++)
itemsIt.next();
return itemsIt.next();
}
protected TopicIF pickRandomType() {
return (TopicIF)pickRandom(controller.getAllTopicTypes());
}
protected TMAbstractNode pickRandomNode(TopicIF type) {
if (type == null)
return null;
return (TMAbstractNode)pickRandom(controller.getView()
.getTopicNodesFor(type));
}
/**
* Enables/disables this motion killer.
* Note: VizPanel uses the value of enabled to build menus, so this method
* should only be changed (indirectly) from there.
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
if (enabled) {
timer = new Timer();
timer.scheduleAtFixedRate(this, millis, millis);
} else if (timer != null) {
timer.cancel();
timer = null;
}
}
public boolean getEnabled() {
return enabled;
}
}