/*
* This software Copyright by the RPTools.net development team, and licensed
* under the GPL Version 3 or, at your option, any later version.
*
* MapTool 2 Source Code 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 source Code. If not, see <http://www.gnu.org/licenses/>
*/
package net.rptools.maptool.webapi;
import net.rptools.lib.AppEvent;
import net.rptools.lib.AppEventListener;
import net.rptools.maptool.client.MapTool;
import net.rptools.maptool.client.ui.zone.ZoneRenderer;
import net.rptools.maptool.model.*;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import java.awt.*;
import java.util.*;
import java.util.List;
public class WebTokenInfo {
private static final WebTokenInfo instance = new WebTokenInfo();
private final AppEventListener appEventListener;
private final Map<Zone, ModelChangeListener> modelChangeListeners = new WeakHashMap<>();
private WebTokenInfo() {
// Add listener for new zones.
appEventListener = new AppEventListener() {
@Override
public void handleAppEvent(AppEvent appEvent) {
if (appEvent.getId().equals(MapTool.ZoneEvent.Added)) {
addTokenChangeListeners();
}
}
};
addTokenChangeListeners();
}
// TODO: This could be a single listener for all zones
private void addTokenChangeListeners() {
for (Zone zone : MapTool.getCampaign().getZones()) {
if (modelChangeListeners.containsKey(zone) == false) {
modelChangeListeners.put(zone, new ModelChangeListener() {
@Override
public void modelChanged(ModelChangeEvent event) {
System.out.println("DEBUG: Event " + event.eventType);
if (event.eventType == Zone.Event.TOKEN_CHANGED) {
tokenChanged((Token) event.getArg());
} else if (event.eventType == Zone.Event.TOKEN_ADDED) {
tokenAdded((Token) event.getArg());
} else if (event.eventType == Zone.Event.TOKEN_REMOVED) {
tokenRemoved((Token) event.getArg());
}
}
});
zone.addModelChangeListener(modelChangeListeners.get(zone));
}
}
}
private void tokenChanged(Token token) {
JSONObject jobj = new JSONObject();
JSONArray tokenArray = new JSONArray();
tokenArray.add(token.getId().toString());
jobj.put("tokensChanged", tokenArray);
MTWebClientManager.getInstance().sendToAllSessions("token-update", jobj);
}
private void tokenAdded(Token token) {
JSONObject jobj = new JSONObject();
JSONArray tokenArray = new JSONArray();
tokenArray.add(token.getId().toString());
jobj.put("tokensAdded", tokenArray);
MTWebClientManager.getInstance().sendToAllSessions("token-update", jobj);
}
private void tokenRemoved(Token token) {
JSONObject jobj = new JSONObject();
JSONArray tokenArray = new JSONArray();
tokenArray.add(token.getId().toString());
jobj.put("tokensRemoved", tokenArray);
MTWebClientManager.getInstance().sendToAllSessions("token-update", jobj);
}
public static WebTokenInfo getInstance() {
return instance;
}
public Token findTokenFromId(String tokenId) {
System.out.println("DEBUG: tokenId = " + tokenId);
final GUID id = new GUID(tokenId);
final List<Token> tokenList = new ArrayList<>();
List<ZoneRenderer> zrenderers = MapTool.getFrame().getZoneRenderers();
for (ZoneRenderer zr : zrenderers) {
tokenList.addAll(zr.getZone().getTokensFiltered(new Zone.Filter() {
public boolean matchToken(Token t) {
return t.getId().equals(id);
}
}));
if (tokenList.size() > 0) {
break;
}
}
if (tokenList.size() > 0) {
return tokenList.get(0);
} else {
return null;
}
}
private Zone findZoneTokenIsOn(Token token) {
List<ZoneRenderer> zrenderers = MapTool.getFrame().getZoneRenderers();
for (ZoneRenderer zr : zrenderers) {
if (zr.getZone().getTokens().contains(token)) {
return zr.getZone();
}
}
return null;
}
void sendTokenInfo(MTWebSocket mtws, String inResponseTo, JSONObject data) {
if (data.containsKey("propertyNames")) {
sendTokenProperties(mtws, inResponseTo, data);
} else {
sendTokenRegisterdProperties(mtws, inResponseTo, data);
}
}
String getTokenValue(Token token, String name) {
if (":name".equalsIgnoreCase(name)) {
return token.getName();
} else if (":notes".equalsIgnoreCase(name)) {
return token.getNotes();
} else if (":label".equalsIgnoreCase(name)) {
return token.getLabel();
}
return "";
}
void sendTokenProperties(MTWebSocket mtws, String inResponseTo, JSONObject data) {
String tokenId = data.getString("tokenId");
Token token = findTokenFromId(tokenId);
if (token == null) {
System.out.println("DEBUG: sendTokenInfo(): Unable to find token " + tokenId);
return;
// FIXME: log this error
}
JSONObject jobj = new JSONObject();
jobj.put("tokenId", tokenId);
JSONArray properties = new JSONArray();
JSONObject propertiesMap = new JSONObject();
JSONArray propToFetch = data.getJSONArray("propertyNames");
for (int i = 0; i < propToFetch.size(); i++) {
String pname = propToFetch.getString(i);
String val;
if (pname.startsWith(":")) {
val = getTokenValue(token, pname);
} else {
val = token.getProperty(pname) == null ? null : token.getProperty(pname).toString();
}
JSONObject jprop = new JSONObject();
jprop.put("name", pname);
jprop.put("value", val);
properties.add(jprop);
propertiesMap.put(pname, val);
}
jobj.put("properties", properties);
jobj.put("propertiesMap", propertiesMap);
mtws.sendMessage("tokenProperties", inResponseTo, jobj);
}
void sendTokenRegisterdProperties(MTWebSocket mtws, String inResponseTo, JSONObject data) {
String tokenId = data.getString("tokenId");
Token token = findTokenFromId(tokenId);
if (token == null) {
System.out.println("DEBUG: sendTokenInfo(): Unable to find token " + tokenId);
return;
// FIXME: log this error
}
JSONObject jobj = new JSONObject();
jobj.put("tokenId", tokenId);
jobj.put("name", token.getName());
jobj.put("label", token.getLabel());
jobj.put("notes", token.getNotes());
JSONObject jprop = new JSONObject();
for (TokenProperty tp : MapTool.getCampaign().getTokenPropertyList(token.getPropertyType())) {
JSONObject jp = new JSONObject();
jp.put("name", tp.getName());
if (tp.getShortName() != null) {
jp.put("shortName", tp.getShortName());
}
if (tp.getDefaultValue() != null) {
jp.put("defaultValue", tp.getDefaultValue());
}
jp.put("value", token.getProperty(tp.getName()));
jp.put("showOnStatSheet", tp.isShowOnStatSheet());
jprop.put(tp.getName(), jp);
}
jobj.put("properties", jprop);
JSONArray jmacros = new JSONArray();
for (MacroButtonProperties macro : token.getMacroList(false)) {
JSONObject jmb = new JSONObject();
jmb.put("label", macro.getLabel());
jmb.put("tooltip", macro.getEvaluatedToolTip());
jmb.put("index", macro.getIndex());
jmb.put("fontColor", macro.getFontColorAsHtml());
jmb.put("displayGroup", macro.getGroupForDisplay());
jmb.put("group", macro.getGroup());
jmb.put("index", macro.getIndex());
jmb.put("autoExecute", macro.getAutoExecute());
jmb.put("maxWidth", macro.getMaxWidth());
jmb.put("minWidth", macro.getMinWidth());
jmb.put("applyToTokens", macro.getApplyToTokens());
jmacros.add(jmb);
}
jobj.put("macros", jmacros);
mtws.sendMessage("tokenInfo", inResponseTo, jobj);
}
void processMacro(JSONObject data) {
// FIXME: need to check parameters.
// FIXME: need to check permissions.
if ("callMacro".equalsIgnoreCase(data.getString("command"))) {
Token token = findTokenFromId(data.getString("tokenId"));
MacroButtonProperties macro = token.getMacro(data.getInt("macroIndex"), false);
macro.executeMacro(token.getId());
}
}
void processSetProperties(JSONObject data) {
final String tokenId = data.getString("tokenId");
final Token token = findTokenFromId(tokenId);
final Zone zone = findZoneTokenIsOn(token);
if (token == null) {
System.out.println("DEBUG: sendTokenInfo(): Unable to find token " + tokenId);
return;
// FIXME: log this error
}
final JSONObject props = data.getJSONObject("properties");
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Set<String> pnames = props.keySet();
for (String pname : pnames) {
String val = props.getString(pname);
token.setProperty(pname, val);
}
zone.putToken(token);
}
});
}
}