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

import be.iminds.ilabt.jfed.experimenter_gui.config.JFedGuiConfig;
import be.iminds.ilabt.jfed.experimenter_gui.editor.ModelRspecEditor;
import be.iminds.ilabt.jfed.experimenter_gui.util.StringConverters;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.Server;
import be.iminds.ilabt.jfed.fedmon.webapi.service.json.ServerGlimpse;
import be.iminds.ilabt.jfed.lowlevel.TestbedInfoSource;
import be.iminds.ilabt.jfed.rspec.model.javafx_impl.FXAddressPool;
import be.iminds.ilabt.jfed.ui.javafx.FXMLUtil;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;
import java.util.function.Predicate;

/**
 * User: twalcari
 * Date: 4/23/2015
 * Time: 16:46
 */
public class AddressPoolPropertiesDialog extends BorderPane {
    private static final Logger LOG = LoggerFactory.getLogger(AddressPoolPropertiesDialog.class);

    private final FXAddressPool addressPool;
    private final ValidationSupport validationSupport;

    @FXML
    private TextField nameTextField;
    @FXML
    private ComboBox<Server> serverComboBox;
    @FXML
    private TextField countTextField;

    @FXML
    private HBox ipFreeHBox;
    @FXML
    private Label ipFreeLabel;

    @FXML
    private Button saveButton;
    @FXML
    private Button cancelButton;
    private boolean success = false;

    AddressPoolPropertiesDialog(FXAddressPool addressPool, JFedGuiConfig config,
                                TestbedInfoSource testbedInfoSource) {
        this.addressPool = addressPool;


        //initialize the Scene
        FXMLUtil.injectFXML(this);

        assert serverComboBox != null;

        serverComboBox.getSelectionModel().selectedItemProperty().addListener(observable -> {
            Server server = serverComboBox.getSelectionModel().getSelectedItem();

            final ServerGlimpse serverGlimpse = config.getServerGlimpse(server);
            if(serverGlimpse != null
                    && serverGlimpse.getAdvertisementInfo() != null
                    && serverGlimpse.getAdvertisementInfo().getCount(ServerGlimpse.AdvertisementInfo.CountedObject.IPV4, ServerGlimpse.AdvertisementInfo.CountScope.ALL) != null
                    && serverGlimpse.getAdvertisementInfo().getCount(ServerGlimpse.AdvertisementInfo.CountedObject.IPV4, ServerGlimpse.AdvertisementInfo.CountScope.ALL) > 0){
                ipFreeLabel.setText(serverGlimpse.getAdvertisementInfo().getCount(ServerGlimpse.AdvertisementInfo.CountedObject.IPV4, ServerGlimpse.AdvertisementInfo.CountScope.AVAILABLE) +
                        " of " + serverGlimpse.getAdvertisementInfo().getCount(ServerGlimpse.AdvertisementInfo.CountedObject.IPV4, ServerGlimpse.AdvertisementInfo.CountScope.ALL));
                ipFreeHBox.setVisible(true);

            }   else{
                ipFreeHBox.setVisible(false);
            }

        });

        testbedInfoSource.getServers().stream()
                .filter(server -> server.hasFlag(Server.Flag.featureIPv4AddressPool))
                .sorted(Comparator.comparing(server -> server.getName().toLowerCase().trim()))
                .forEach(serverComboBox.getItems()::add);

        serverComboBox.setConverter(StringConverters.SERVER_STRING_CONVERTER);


        //load values from the provided channel
        nameTextField.setText(addressPool.getClientId());

        if (addressPool.getComponentManagerId() != null) {
            Server server  = testbedInfoSource.getByUrnExact(addressPool.getComponentManagerId());
            if (server != null)
                serverComboBox.getSelectionModel().select(server);
            else
                LOG.warn("Could not find CMI with URN {}", addressPool.getComponentManagerId());
        } else {
            serverComboBox.getSelectionModel().clearSelection();
        }
        countTextField.setText(addressPool.getCount() != null ? Integer.toString(addressPool.getCount()) : "0");


        //initialize validationSupport
        validationSupport = new ValidationSupport();
        validationSupport.registerValidator(nameTextField, Validator.createPredicateValidator(ModelRspecEditor::isValidNodeName, "You must provide a client ID"));
        validationSupport.registerValidator(serverComboBox, Validator.createEmptyValidator("You must choose a testbed"));
        validationSupport.registerValidator(countTextField, Validator.createPredicateValidator((Predicate<String>) s -> {
            try {
                return Integer.parseInt(s) > 0;
            } catch (NumberFormatException ex) {
                return false;
            }
        }, "You must provide a positive number of IPs to request"));

        saveButton.disableProperty().bind(validationSupport.invalidProperty());
    }


    @FXML
    public void onSaveAction(ActionEvent actionEvent) {
        addressPool.setClientId(nameTextField.getText());
        addressPool.setComponentManagerId(serverComboBox.getSelectionModel().getSelectedItem().getDefaultComponentManagerAsGeniUrn());
        addressPool.setCount(Integer.parseInt(countTextField.getText()));

        success = true;

        Stage stage = (Stage) saveButton.getScene().getWindow();
        stage.close();

    }

    public boolean isSuccess() {
        return success;
    }

    @FXML
    public void onCancelAction(ActionEvent actionEvent) {
        Stage stage = (Stage) cancelButton.getScene().getWindow();
        stage.close();
    }

}
