package com.github.czyzby.views;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.utils.I18NBundle;
import com.github.czyzby.Core;
import com.github.czyzby.kiwi.util.common.Strings;
import com.github.czyzby.lml.annotation.LmlAction;
import com.github.czyzby.lml.annotation.LmlActor;
import com.github.czyzby.lml.annotation.LmlBefore;
import com.github.czyzby.lml.annotation.LmlInject;
import com.github.czyzby.lml.parser.LmlParser;
import com.github.czyzby.lml.parser.impl.AbstractLmlView;
import com.github.czyzby.views.container.WebSocketButtons;
import com.github.czyzby.websocket.WebSocket;
import com.github.czyzby.websocket.WebSocketAdapter;
import com.github.czyzby.websocket.WebSocketListener;
import com.github.czyzby.websocket.WebSockets;
import com.github.czyzby.websocket.data.WebSocketCloseCode;
import com.github.czyzby.websocket.net.ExtendedNet;
import com.kotcrab.vis.ui.widget.VisTextField;
/** Example of cross-platform web sockets usage. Connects with external web sockets echo server. Allows the user to send
* his input to the server, prints the responses and any major status changes.
*
* @author MJ */
public class Echo extends AbstractLmlView {
private final WebSocket webSocket = ExtendedNet.getNet().newWebSocket("echo.websocket.org", 80);
private I18NBundle bundle; // Standard LibGDX i18n API.
@LmlActor("status") Label status;
@LmlActor("input") VisTextField input;
/** Value of this field is created and filled by LML parser. Delegating management of widgets disable status from
* {@link Echo} to another class ({@link WebSocketButtons}) makes the code a little bit cleaner. */
@LmlInject WebSocketButtons buttons;
public Echo() {
super(Core.newStage());
webSocket.addListener(getListener());
}
@Override
public FileHandle getTemplateFile() {
return Gdx.files.internal("views/Echo.lml");
}
/** Invoked before Echo.lml template parsing. Extracts {@link I18NBundle} from current LML parser.
*
* @param parser used to parse LML template. */
@LmlBefore
void assignBundle(final LmlParser parser) {
bundle = parser.getData().getDefaultI18nBundle();
}
@LmlAction("open")
void connect() {
if (!webSocket.isSupported()) {
status.setText(bundle.get("notSupported"));
return;
}
try {
webSocket.connect();
} catch (final Exception exception) {
status.setText(bundle.get("connectionError"));
Gdx.app.error("Echo", exception.getMessage());
}
}
/** @return a new instance of {@link WebSocketListener}, displaying status messages in case of any web socket
* events. */
private WebSocketListener getListener() {
return new WebSocketAdapter() {
@Override
public boolean onOpen(final WebSocket webSocket) {
buttons.onConnect();
status.setText(bundle.get("connected"));
return FULLY_HANDLED;
}
@Override
public boolean onMessage(final WebSocket webSocket, final String packet) {
status.setText(bundle.get("message") + " " + packet);
return FULLY_HANDLED;
}
@Override
public boolean onClose(final WebSocket webSocket, final WebSocketCloseCode code, final String reason) {
buttons.onDisconnect();
status.setText(bundle.get("disconnected"));
return FULLY_HANDLED;
}
};
}
@LmlAction("send")
void sendMessage() {
if (webSocket.isOpen()) {
final String message = input.getText();
webSocket.send(message);
input.setText(Strings.EMPTY_STRING);
status.setText(bundle.get("sent") + " " + message);
}
}
@LmlAction("disconnect")
void disconnect() {
if (webSocket.isOpen()) {
WebSockets.closeGracefully(webSocket); // Null-safe closing method that catches and logs any exceptions.
}
}
@Override
public void dispose() {
super.dispose();
disconnect();
}
@Override
public String getViewId() {
return "ws";
}
}