package be.iminds.ilabt.jfed.rspec.model.javafx_impl;

import be.iminds.ilabt.jfed.rspec.model.LinkSetting;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;

import java.util.Objects;

/**
 * With capacity of 0, latency of 0 and loss of 0.0, a LinkSetting will not be written to XML (as they are default)
 */
public final class FXLinkSetting implements LinkSetting, Comparable<FXLinkSetting> {
    private final FXRspecInterface fromIface;
    private final FXRspecInterface toIface;
    private final LongProperty capacity_Kbps = new SimpleLongProperty(0);
    private final IntegerProperty latency_ms = new SimpleIntegerProperty(0);
    private final DoubleProperty packetLoss = new SimpleDoubleProperty(0.0); /*  [0.0, 1.0]  */
    private final ReadOnlyBooleanWrapper active = new ReadOnlyBooleanWrapper();

    {
        active.bind(Bindings.or(
                Bindings.notEqual(capacity_Kbps, 0),
                Bindings.or(
                        Bindings.notEqual(latency_ms, 0),
                        Bindings.notEqual(packetLoss, 0))
        ));
    }

    private boolean shownIfNotActive;

    FXLinkSetting(FXRspecInterface fromIface, FXRspecInterface toIface) {
        this.fromIface = fromIface;
        this.toIface = toIface;
        this.shownIfNotActive = false;
    }

    //////////////////////////////////////////////////////

    @Override
    public FXRspecInterface getFromIface() {
        return fromIface;
    }

    @Override
    public FXRspecInterface getToIface() {
        return toIface;
    }

    //////////////////////////////////////////////////////

    @Override
    public void setSameAs(LinkSetting o) {
        assert Objects.equals(o.getFromIface().getClientId(), getFromIface().getClientId()) : "o.from="+o.getFromIface().getClientId()+" from="+getFromIface().getClientId();
        assert Objects.equals(o.getToIface().getClientId(), getToIface().getClientId()) : "o.to="+o.getToIface().getClientId()+" to="+getToIface().getClientId();

        if (o.isCapacitySet())
            setCapacity_Kbps(o.getCapacity_Kbps());
        else
            setCapacity_Kbps(null);

        if (o.isLatencySet())
            setLatency_ms(o.getLatency_ms());
        else
            setLatency_ms(null);

        if (o.isPacketLossSet())
            setPacketLoss(o.getPacketLoss());
        else
            setPacketLoss(null);

        this.shownIfNotActive = o.isShownIfNotActive();
    }

    //////////////////////////////////////////////////////

    @Override
    public long getCapacity_Kbps() {
        return capacity_Kbps.get();
    }

    @Override
    public void setCapacity_Kbps(Long value) {
        if (value == null)
            capacity_Kbps.set(0);
        else
            capacity_Kbps.set(value);
    }

    public LongProperty capacity_KbpsProperty() {
        return capacity_Kbps;
    }

    @Override
    public boolean isCapacitySet() {
        return capacity_Kbps.get() > 0;
    }
    //////////////////////////////////////////////////////

    @Override
    public int getLatency_ms() {
        return latency_ms.get();
    }

    @Override
    public void setLatency_ms(Integer value) {
        if (value == null)
            latency_ms.set(0);
        else
            latency_ms.set(value);
    }

    public IntegerProperty latency_msProperty() {
        return latency_ms;
    }

    @Override
    public boolean isLatencySet() {
        return latency_ms.get() > 0;
    }
    //////////////////////////////////////////////////////

    @Override
    public double getPacketLoss() {
        return packetLoss.get();
    }

    @Override
    public void setPacketLoss(Double value) {
        if (value == null)
            packetLoss.set(0.0);
        else
            packetLoss.set(value);
    }

    public DoubleProperty packetLossProperty() {
        return packetLoss;
    }

    @Override
    public boolean isPacketLossSet() {
        return packetLoss.get() > 0.0;
    }

    @Override
    public boolean isActive() {
        return active.get();
    }

    @Override
    public boolean isShownIfNotActive() {
        return shownIfNotActive;
    }

    @Override
    public void setShownIfNotActive(boolean shownIfNotActive) {
        this.shownIfNotActive = shownIfNotActive;
    }

    public ReadOnlyBooleanProperty activeProperty() {
        return active.getReadOnlyProperty();
    }

    @Override
    public String toString() {
        return "LinkSetting{" +
                "toIface=" + toIface.toString() +
                ", fromIface=" + fromIface.toString() +
                '}';
    }

    @Override
    public int compareTo(FXLinkSetting o) {
        int result = getFromIface().getClientId().compareTo(o.getFromIface().getClientId());
        if(result == 0)
            result = getToIface().getClientId().compareTo(o.getToIface().getClientId());

        return result;
    }
}
