package be.iminds.ilabt.jfed.experimenter_gui.editor.properties;

import be.iminds.ilabt.jfed.experimenter_gui.editor.ModelRspecEditor;
import be.iminds.ilabt.jfed.experimenter_gui.util.InetAddressUtil;
import be.iminds.ilabt.jfed.experimenter_gui.util.ui.UIUtils;
import be.iminds.ilabt.jfed.rspec.model.RspecInterface;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecInterface;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecLink;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXRspecNode;
import be.iminds.ilabt.jfed.ui.javafx.FXMLUtil;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.ToggleGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;

/**
 * User: twalcari
 * Date: 9/1/2014
 * Time: 11:04
 */
public class InterfacePropertiesTab extends PropertiesTab {
    private static final Logger LOG = LoggerFactory.getLogger(InterfacePropertiesTab.class);
    private final ModelRspecEditor modelRspecEditor;
    private final FXRspecNode rspecNode;
    private final FXRspecLink rspecLink;
    private final FXRspecInterface rspecInterface;
    private final RspecInterface.IpAddress ipAddress;

    private final ReadOnlyStringProperty newNodeNameProperty;

    @FXML
    private TextField idInputField;

    @FXML
    private ToggleGroup ipToggleGroup;
    @FXML
    private RadioButton autoConfigRadioButton;
    @FXML
    private RadioButton ipv4RadioButton;
    @FXML
    private RadioButton ipv6RadioButton;

    @FXML
    private TitledPane ipv4Pane;
    @FXML
    private TitledPane ipv6Pane;

    @FXML
    private TextField ipv4Address;
    @FXML
    private TextField ipv4NetMask;

    @FXML
    private TextField ipv6Address;
    @FXML
    private TextField ipv6NetMask;


    public InterfacePropertiesTab(final ModelRspecEditor modelRspecEditor, FXRspecNode rspecNode,
                                  final FXRspecInterface rspecInterface, ReadOnlyStringProperty newNodeNameProperty) {
        this.modelRspecEditor = modelRspecEditor;
        this.rspecNode = rspecNode;
        this.rspecInterface = rspecInterface;
        this.newNodeNameProperty = newNodeNameProperty;
        this.rspecLink = rspecInterface.isLinkBound() ? rspecInterface.getLink() : null;
        this.ipAddress = !rspecInterface.getIpAddresses().isEmpty() ? rspecInterface.getIpAddresses().get(0) : null;

        setContent(FXMLUtil.createFromFXML(this));

        //wire properties together
        ipv4Pane.disableProperty().bind(ipv4RadioButton.selectedProperty().not());
        ipv6Pane.disableProperty().bind(ipv6RadioButton.selectedProperty().not());


        ipv4RadioButton.selectedProperty().addListener(observable -> {
            if (!ipv4RadioButton.isSelected()) {
                ipv4Address.clear();
                ipv4NetMask.clear();
            }
        });

        ipv6RadioButton.selectedProperty().addListener(observable -> {
            if (!ipv6RadioButton.isSelected()) {
                ipv6Address.clear();
                ipv6NetMask.clear();
            }
        });

        ipToggleGroup.selectedToggleProperty().addListener(observable -> {
            if (ipToggleGroup.getSelectedToggle() == ipv4RadioButton) {
                ipv6Address.clear();
                ipv6NetMask.clear();

                if(ipAddress != null &&
                        (RspecInterface.IpAddress.TYPE_IPV4.equalsIgnoreCase(ipAddress.getType())
                                || ipAddress.getType() == null)){
                    ipv4Address.setText(ipAddress.getAddress());
                    ipv4NetMask.setText(ipAddress.getNetmask());
                }   else{
                    ipv4NetMask.setText(ModelRspecEditor.DEFAULT_IPV4_NETMASK);
                }

            } else {
                ipv4Address.clear();
                ipv4NetMask.clear();

                if(ipAddress != null && RspecInterface.IpAddress.TYPE_IPV6.equalsIgnoreCase(ipAddress.getType())){
                    ipv6Address.setText(ipAddress.getAddress());
                    ipv6NetMask.setText(ipAddress.getNetmask());
                }      else{
                    ipv6NetMask.setText(ModelRspecEditor.DEFAULT_IPV6_NETMASK);
                }
            }
        });

        idInputField.setText(rspecInterface.getClientId());
        UIUtils.setTextLimit(idInputField, ModelRspecEditor.MAX_IFACE_NAME_LENGTH);

        textProperty().bind(Bindings.concat("Interface ").concat(idInputField.textProperty()));


        //initialize ip-address, this will happen automatically because of the event on the ipToggleGroup
        if (this.ipAddress != null) {
            if (RspecInterface.IpAddress.TYPE_IPV6.equalsIgnoreCase(ipAddress.getType())) {
                ipv6RadioButton.setSelected(true);
            } else {
                //assume it is an ipv4 address
                ipv4RadioButton.setSelected(true);
            }
        }

        newNodeNameProperty.addListener((observable, oldValue, newValue) -> idInputField.setText(idInputField.getText().replace(oldValue,newValue)));
    }

    @Override
    public void save() {
        rspecInterface.setClientId(idInputField.getText());

        rspecInterface.getIpAddresses().clear();
        if (ipv4RadioButton.isSelected()) {
            rspecInterface.getIpAddresses().add(
                    new RspecInterface.IpAddress(ipv4Address.getText(), ipv4NetMask.getText(),
                            RspecInterface.IpAddress.TYPE_IPV4));
        } else if (ipv6RadioButton.isSelected()) {
            rspecInterface.getIpAddresses().add(
                    new RspecInterface.IpAddress(ipv6Address.getText(), ipv6NetMask.getText(),
                            RspecInterface.IpAddress.TYPE_IPV6));
        }
    }

    @Override
    public String validateConfiguration() {
        if(idInputField.getText() == null || !isValidInterfaceName(idInputField.getText())){
            return String.format("'%s' is not a valid interface name.", idInputField.getText());
        }

        if (ipv4RadioButton.isSelected() &&
                (!InetAddressUtil.isValidInet4Address(ipv4Address.getText()))) {
            return "The entered IPv4-address for interface " + rspecInterface.getClientId() + " is not valid.";
        }


        if (ipv4RadioButton.isSelected() &&
                (!InetAddressUtil.isValidInet4Address(ipv4NetMask.getText()))) {
            return "The entered IPv4-netmask for interface " + rspecInterface.getClientId() + " is not valid.";
        }


        if (ipv6RadioButton.isSelected() &&
                (!InetAddressUtil.isValidInet6Address(ipv6Address.getText()))) {
            return "The entered IPv6-address for interface " + rspecInterface.getClientId() + " is not valid.";
        }


        if (ipv6RadioButton.isSelected() &&
                (!InetAddressUtil.isValidInet6Netmask(ipv6NetMask.getText()))) {
            return "The entered IPv6-prefix length for interface " + rspecInterface.getClientId() + " is not valid.";
        }

        return null;
    }

    private static boolean isValidInterfaceName(@Nonnull String text) {
        if (text.trim().isEmpty())
            return false;

        for (char c : text.toCharArray()) {
            boolean validChar = (c >= 'a' && c <= 'z')
                    || (c >= 'A' && c <= 'Z')
                    || (c >= '0' && c <= '9')
                    || c == ':' || c == '_' || c == '-';

            if (!validChar) {
                return false;
            }
        }

        return true;
    }
}
