package Connection;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.text.NumberFormatter;
import api.AddOn;
import classes.AbstractCanvasObject;
import classes.GroupNode;
import classes.HolonElement;
import classes.HolonObject;
import ui.controller.Control;
import ui.view.Console;
/**
* Easy Connection via Http Request. Repeat Request with a delay.
*
* @author tom
*
*/
public class ConnectPhysical implements AddOn{
//Holeg
private Control control;
//Gui
private JPanel content = new JPanel();
private Console console;
private JLabel rotorLabel;
private JLabel houseLabel;
private boolean onlyOnChange = false;
//
Future> future;
private boolean lessInformation = false;
private int delay = 1000;
JLabel warningLabel;
public enum HolonObjectStatus{
Connected , NotSelected, ObjectDeleted
}
public class PhysicalLinkWrapper{
public HolonObject hObject;
public HolonObjectStatus status;
public String postAddress;
PhysicalLinkWrapper(HolonObject hObject, HolonObjectStatus status, String postAddress){
this.hObject = hObject;
this.status = status;
this.postAddress = postAddress;
}
}
//Object to look at
PhysicalLinkWrapper rotor = new PhysicalLinkWrapper(null, HolonObjectStatus.NotSelected, "/rotor/");
//Because House is special
PhysicalLinkWrapper house = new PhysicalLinkWrapper(null, HolonObjectStatus.NotSelected, "notUsed");
String room1Address = "/room1/";
String room2Address = "/room2/";
//the keywords are for the sepreation in 2 rooms
String room1Keyword = "room1";
String room2Keyword = "room2";
//OnChange
int oldValueRotor = -1;
int oldValueRoom1 = -1;
int oldValueRoom2 = -1;
public static void main(String[] args)
{
JFrame newFrame = new JFrame("exampleWindow");
ConnectPhysical instance = new ConnectPhysical();
newFrame.setContentPane(instance.getPanel());
newFrame.pack();
newFrame.setVisible(true);
newFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public ConnectPhysical() {
content.setLayout(new BorderLayout());
console = new Console();
JScrollPane scrollPane = new JScrollPane(console);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
createOptionPanel() , scrollPane);
splitPane.setResizeWeight(0.0);
content.add(splitPane, BorderLayout.CENTER);
content.setPreferredSize(new Dimension(800,800));
}
private Component createOptionPanel() {
JPanel optionPanel = new JPanel(new BorderLayout());
JScrollPane scrollPane = new JScrollPane(createParameterPanel());
scrollPane.setBorder(BorderFactory.createTitledBorder("Settings"));
optionPanel.add(scrollPane, BorderLayout.CENTER);
optionPanel.add(createButtonPanel(), BorderLayout.PAGE_END);
return optionPanel;
}
private Component createParameterPanel() {
JPanel parameterPanel = new JPanel(null);
parameterPanel.setPreferredSize(new Dimension(510,300));
JLabel lessInformationLabel = new JLabel("Less information in Console:");
lessInformationLabel.setBounds(200, 180, 200, 20);
parameterPanel.add(lessInformationLabel);
JCheckBox lessInformationCheckBox = new JCheckBox();
lessInformationCheckBox.setSelected(false);
lessInformationCheckBox.setBounds(400, 180, 25, 20);
lessInformationCheckBox.addActionListener(actionEvent -> {
lessInformation = lessInformationCheckBox.isSelected();
});
parameterPanel.add(lessInformationCheckBox);
JLabel onlyOnChangeLabel = new JLabel("OnlyOnChange:");
onlyOnChangeLabel.setBounds(200, 240, 200, 20);
parameterPanel.add(onlyOnChangeLabel);
JCheckBox onlyOnChangeCheckBox = new JCheckBox();
onlyOnChangeCheckBox.setSelected(false);
onlyOnChangeCheckBox.setBounds(400, 240, 25, 20);
onlyOnChangeCheckBox.addActionListener(actionEvent -> {
onlyOnChange = onlyOnChangeCheckBox.isSelected();
});
parameterPanel.add(onlyOnChangeCheckBox);
JLabel delayLabel = new JLabel("Delay:");
delayLabel.setBounds(200, 210, 50, 20);
parameterPanel.add(delayLabel);
JLabel delayUnitLabel = new JLabel("[ms]");
delayUnitLabel.setBounds(300, 210, 50, 20);
parameterPanel.add(delayUnitLabel);
warningLabel = new JLabel(stringToHtml(stringWithColor("You need to Stop and Run again to affect delay change.", "red")));
warningLabel.setBounds(200, 280, 400, 20);
warningLabel.setVisible(false);
parameterPanel.add(warningLabel);
//Integer formatter
NumberFormat format = NumberFormat.getIntegerInstance();
format.setGroupingUsed(false);
format.setParseIntegerOnly(true);
NumberFormatter integerFormatter = new NumberFormatter(format);
integerFormatter.setMinimum(0);
integerFormatter.setCommitsOnValidEdit(true);
JFormattedTextField delayTextField = new JFormattedTextField(integerFormatter);
delayTextField.setValue(delay);
delayTextField.setToolTipText("Only positive Integer.");
delayTextField.addPropertyChangeListener(actionEvent -> {
delay = Integer.parseInt(delayTextField.getValue().toString());
if(future != null && !future.isCancelled()) {
console.println("You need to Stop and Run again to affect this change.");
warningLabel.setVisible(true);
}
});
delayTextField.setBounds(250, 210, 50, 20);
parameterPanel.add(delayTextField);
rotorLabel = new JLabel(stringToHtml("Rotor Status: " + statusToString(rotor.status)));
rotorLabel.setBounds(200, 60, 220, 30);
parameterPanel.add(rotorLabel);
houseLabel = new JLabel(stringToHtml("House Status: " + statusToString(house.status)));
houseLabel.setBounds(200, 90, 220, 30);
parameterPanel.add(houseLabel);
JLabel keywordsLabel = new JLabel("Room Seperation Keywords: " + room1Keyword + " " + room2Keyword);
keywordsLabel.setBounds(200, 120, 320, 30);
parameterPanel.add(keywordsLabel);
JLabel keywordsHintLabel = new JLabel("HolonElements with a name that contains the Keyword count.");
keywordsHintLabel.setBounds(200, 135, 450, 30);
parameterPanel.add(keywordsHintLabel);
JButton selectRotorButton = new JButton("Select");
selectRotorButton.setBounds(420,65, 90, 20);
selectRotorButton.addActionListener(actionEvent -> this.selectGroupNode(rotor));
parameterPanel.add(selectRotorButton);
JButton selectRoom1Button = new JButton("Select");
selectRoom1Button.setBounds(420,95, 90, 20);
selectRoom1Button.addActionListener(actionEvent -> this.selectGroupNode(house));
parameterPanel.add(selectRoom1Button);
return parameterPanel;
}
private String stringToHtml(String string) {
return "" + string + "";
}
private String statusToString(HolonObjectStatus status) {
switch(status) {
case Connected:
return stringWithColor("Connected", "green");
case NotSelected:
return stringWithColor("Not selected", "red");
case ObjectDeleted:
return stringWithColor("Object deleted", "red");
default:
return "";
}
}
private String stringWithColor(String string, String color) {
return "" + string + "";
}
private void updateStatusLabels() {
rotorLabel.setText(stringToHtml("Rotor Status: " + statusToString(rotor.status)));
houseLabel.setText(stringToHtml("House Status: " + statusToString(house.status)));
}
private Component createButtonPanel() {
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton clearButton = new JButton("Clear Console");
clearButton.addActionListener(actionEvent -> console.clear());
buttonPanel.add(clearButton);
JButton stopButton = new JButton("Stop");
stopButton.addActionListener(actionEvent -> stop());
buttonPanel.add(stopButton);
JButton runButton = new JButton("Run");
runButton.addActionListener(actionEvent -> initSchedule());
buttonPanel.add(runButton);
return buttonPanel;
}
private void stop() {
if(future!= null) {
if(future.isCancelled()) {
console.println("Is cancelled.");
}
else {
future.cancel(true);
console.println("Stopped sending Requests on localhost:2019 ...");
}
}
else {
console.println("Not started jet.");
}
}
private void initSchedule() {
if(future != null && !future.isCancelled()) {
console.println("Is running.");
return;
}
warningLabel.setVisible(false);
console.println("Starting sending Requests on localhost:2019");
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
final Runnable beeper = new Runnable() {
//RepeatedMethod
public void run() {
if(lessInformation)console.print(".");
checkWrapper(rotor);
checkWrapperHouseSpecial(house);
}
private void checkWrapper(PhysicalLinkWrapper wrapper) {
if(wrapper.status == HolonObjectStatus.Connected) checkConnected(wrapper);
else if(!lessInformation)console.println(wrapper.postAddress +" is not connected.");
}
private void checkConnected(PhysicalLinkWrapper wrapper) {
if(wrapper.hObject == null) {
wrapper.status = HolonObjectStatus.ObjectDeleted;
updateStatusLabels();
return;
}
if(wrapper.hObject.getNumberOfElements() > 0) {
//OnlyForRotor
int value = Math.round(((float)wrapper.hObject.getNumberOfActiveElements()/(float) wrapper.hObject.getNumberOfElements())*(float) 100);
if(onlyOnChange) {
if(oldValueRotor != value) {
sendRequest(wrapper.postAddress, value);
oldValueRotor = value;
}
}else {
sendRequest(wrapper.postAddress, value);
}
}else {
if(onlyOnChange) {
if(oldValueRotor != 0) {
sendRequest(wrapper.postAddress, 0);
oldValueRotor = 0;
}
}else {
sendRequest(wrapper.postAddress, 0);
}
}
}
private void sendRequest(String postAddress, int value) {
if(!lessInformation)console.println("Send " + "http://localhost:2019" + postAddress + value);
doHttpUrlConnectionAction("http://localhost:2019" + postAddress + value);
}
/**
* Send A Request to a URL.
*
* @param desiredUrl
* @return
*/
private void doHttpUrlConnectionAction(String desiredUrl)
{
URL url = null;
// create the HttpURLConnection
try {
url = new URL(desiredUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// just want to do an HTTP GET here
connection.setRequestMethod("GET");
connection.getResponseCode();
// give it 15 seconds to respond
connection.setReadTimeout(1000);
connection.connect();
} catch (MalformedURLException e) {
console.println("MalformedURLException");
e.printStackTrace();
} catch (IOException e) {
console.println("IOException: Connection refused");
e.printStackTrace();
}
}
private void checkWrapperHouseSpecial(PhysicalLinkWrapper house) {
if(!(house.status == HolonObjectStatus.Connected)) {
if(!lessInformation)console.println("House" + " is not connected.");
return;
}
//House is Connected
if(house.hObject == null) {
house.status = HolonObjectStatus.ObjectDeleted;
updateStatusLabels();
return;
}
//House exist
List elementsOfRoom1 = house.hObject.getElements().stream().filter(ele -> ele.getName().contains(room1Keyword)).collect(Collectors.toList());
List elementsOfRoom2 = house.hObject.getElements().stream().filter(ele -> ele.getName().contains(room2Keyword)).collect(Collectors.toList());
if(elementsOfRoom1.isEmpty()){
if(onlyOnChange) {
if(oldValueRoom1 != 0) {
sendRequest(room1Address, 0);
oldValueRoom1 = 0;
}
}else {
sendRequest(room1Address, 0);
}
}
else{
int value = Math.round(((float)elementsOfRoom1.stream().filter(ele -> ele.isActive()).count()/(float) elementsOfRoom1.size())*(float) 100);
if(onlyOnChange) {
if(oldValueRoom1 != value) {
sendRequest(room1Address, value);
oldValueRoom1 = value;
}
}else {
sendRequest(room1Address, value);
}
}
if(elementsOfRoom2.isEmpty()){
if(onlyOnChange) {
if(oldValueRoom2 != 0) {
sendRequest(room2Address, 0);
oldValueRoom2 = 0;
}
}else {
sendRequest(room2Address, 0);
}
}
else{
int value = Math.round(((float)elementsOfRoom2.stream().filter(ele -> ele.isActive()).count()/(float) elementsOfRoom2.size())*(float) 100);
if(onlyOnChange) {
if(oldValueRoom2 != value) {
sendRequest(room2Address, value);
oldValueRoom2 = value;
}
}else {
sendRequest(room2Address, value);
}
}
}
};
future = executorService.scheduleAtFixedRate(beeper, 0, delay, TimeUnit.MILLISECONDS);
}
private void addObjectToList(List listToSearch, List listToAdd){
for (AbstractCanvasObject aCps : listToSearch) {
if (aCps instanceof HolonObject) listToAdd.add((HolonObject) aCps);
else if(aCps instanceof GroupNode) {
addObjectToList(((GroupNode)aCps).getNodes(),listToAdd);
}
}
}
//SelectGroupNode
private void selectGroupNode(PhysicalLinkWrapper wrapper) {
List holonObjectList = new ArrayList();
addObjectToList(control.getModel().getObjectsOnCanvas(),holonObjectList);
Object[] possibilities = holonObjectList.stream().map(aCps -> new Handle(aCps)).toArray();
@SuppressWarnings("unchecked")
Handle selected = (Handle) JOptionPane.showInputDialog(content, "Select HolonObject:", "HolonObject?", JOptionPane.OK_OPTION,new ImageIcon(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)) , possibilities, "");
if(selected != null) {
console.println("Selected: " + selected);
wrapper.hObject = selected.object;
wrapper.status = HolonObjectStatus.Connected;
updateStatusLabels();
}
}
private class Handle{
public T object;
Handle(T object){
this.object = object;
}
public String toString() {
return object.toString();
}
}
@Override
public JPanel getPanel() {
return content;
}
@Override
public void setController(Control control) {
this.control = control;
}
}