/* 
 *  CallbackForm.java
 * 
 *  Copyright 2016 Avaya Inc. All Rights Reserved.
 * 
 *  Usage of this source is bound to the terms described
 *  in AvayaLicenseSDK.rtf.
 * 
 *  Avaya - Confidential & Proprietary. Use pursuant to your signed agreement
 *  or Avaya Policy
 * 
 */
package com.avaya.ccs.javafxrefclient;

import com.avaya.ccs.api.ContactNumberI;
import com.avaya.ccs.api.DestinationI;
import com.avaya.ccs.api.DestinationListI;
import java.time.LocalDate;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 * This form is used to display both the transfer and conference destinations.
 * In addition the form is used for free form dialing in both cases.
 */
public class CallbackForm {

    private final Stage callbackForm = new Stage();
    private static final Logger LOG = Logger.getLogger(CallbackForm.class);
    private final InteractionExecutor interactionExe;
    private final ObservableList<DestinationI> callbackDestinations = FXCollections.observableArrayList();
    private String currentInteractionID;
    private LocalDate startDate;
    private TextField startTimeField;
    private TextField endTimeField;

    public CallbackForm(InteractionExecutor interactionExe, String css) {
        this.interactionExe = interactionExe;
        BorderPane calbackBorder = new BorderPane();
        Scene callbackScene = new Scene(calbackBorder, 350, 400);
        callbackScene.getStylesheets().add(css);
        callbackForm.setScene(callbackScene);
        callbackForm.titleProperty().set("Schedule Callback");
    }

    public void show() {
        callbackForm.show();
    }

    public void updateDestinationList(String interactionID, DestinationListI list) {
        String methodName = "updateDestinationList() ";
        if (interactionID.equals(currentInteractionID)) {
            LOG.info(methodName + "Contact ID:" + interactionID + " updating list with " + list.getDestinations().size()
                    + " items");
            callbackDestinations.addAll(list.getDestinations());
        } else {
            LOG.error(methodName + "Contact ID:" + interactionID + " does not match current contactID: "
                    + currentInteractionID);
        }
    }

    public void initializeForm(InteractionData interaction) {
        currentInteractionID = interaction.getId();
        callbackDestinations.clear();

        BorderPane bp = (BorderPane) callbackForm.sceneProperty().get().getRoot();

        ListView<DestinationI> destinations = new ListView<>();
        destinations.setItems(callbackDestinations);

        Label customerContact = new Label("Customer: ");
        ObservableList<ContactNumberI> contacts = FXCollections.observableList(interaction.getContactNumbers());
        ComboBox<ContactNumberI> contactList = new ComboBox<ContactNumberI>(contacts);

        Label startDateLabel = new Label("Start Date (UTC): ");
        DatePicker startDatePicker = new DatePicker();

        Label startTimeLabel = new Label("Start Time (UTC): ");
        startTimeField = new TextField();
        startTimeField.setText("HH:MM");

        Label expiryLabel = new Label("Expiry Minutes");
        endTimeField = new TextField();

        TextField noteField = new TextField();
        Label noteLabel = new Label("Note:");

        TextField externalNumberField = new TextField();
        Button callbackToExternalButton = new Button("Callback External");

        Button callbackToContactNumberButton = new Button("Callback Contact");
        callbackToContactNumberButton.setDisable(true);

        Button cancelButton = new Button("Cancel");
        cancelButton.getStyleClass().add("callbackFormButtons");

        // Action listeners and code cell display methods
        // We want the list to display the name and code only
        destinations.setCellFactory(new Callback<ListView<DestinationI>, ListCell<DestinationI>>() {
            @Override
            public ListCell<DestinationI> call(ListView<DestinationI> list) {
                return new CallbackForm.CodeCell();
            }
        });

        destinations.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<DestinationI>() {
            @Override
            public void changed(ObservableValue<? extends DestinationI> observable, DestinationI oldValue,
                    DestinationI newValue) {
                if (newValue != null) {
                    callbackToContactNumberButton.setDisable(false);
                    // Also enable the call back external button if there is an
                    // external number
                    String val = externalNumberField.textProperty().getValue();
                    callbackToExternalButton.setDisable(val == null || val.isEmpty());
                }
            }
        });

        bp.setCenter(destinations);

        contactList.setCellFactory(new Callback<ListView<ContactNumberI>, ListCell<ContactNumberI>>() {
            @Override
            public ListCell<ContactNumberI> call(ListView<ContactNumberI> list) {
                return new CallbackForm.CustomerCodeCell();
            }
        });
        contactList.setButtonCell(new CallbackForm.CustomerCodeCell());

        startDatePicker.setOnAction(t -> startDate = startDatePicker.getValue());

        callbackToContactNumberButton.getStyleClass().add("callbackFormButtons");
        callbackToContactNumberButton.setOnAction((ActionEvent t) -> {
            String methodName = "callbackToContactNumberButton";
            DestinationI callbackDestination = destinations.getSelectionModel().getSelectedItem();
            ContactNumberI contactNumber = contactList.getValue();
            String callbackTime = startDateTime();
            String callbackExpiryTime = expiryMinutes();
            String callbackNote = noteField.getText();
            if (callbackDestination != null) {
                LOG.info("CallbackToContactNumberButton() interactionID:" + currentInteractionID);
                this.interactionExe.createCallbackToContactNumber(currentInteractionID, callbackDestination,
                        contactNumber, callbackTime, callbackExpiryTime, callbackNote);
            } else {
                LOG.error(methodName + "Selected destination is null");
            }
            callbackForm.close();
        });

        cancelButton.setOnAction((ActionEvent t) -> {
            LOG.info("CancelButton()");
            callbackForm.close();
        });

        // External number handling
        callbackToExternalButton.getStyleClass().add("callbackFormButtons");
        callbackToExternalButton.setOnAction((ActionEvent t) -> {
            String methodName = "callbackToExternalButton";
            DestinationI callbackDestination = destinations.getSelectionModel().getSelectedItem();
            String callbackTime = startDateTime();
            String callbackExpiryTime = expiryMinutes();
            String callbackNote = noteField.getText();
            String externalNumber = externalNumberField.getText();
            if (callbackDestination != null) {
                LOG.info("CallbackToExternalNumberButton() interactionID:" + currentInteractionID);
                this.interactionExe.createCallbackToExternalNumber(currentInteractionID, callbackDestination,
                        externalNumber, callbackTime, callbackExpiryTime, callbackNote);
            } else {
                LOG.error(methodName + "Selected destination is null");
            }
            callbackForm.close();
        });

        // Disable the call back external button until there is a number entered
        callbackToExternalButton.setDisable(true);
        externalNumberField.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                // Only enable the button is there is also a destination
                // selected
                if (!destinations.getSelectionModel().isEmpty()) {
                    callbackToExternalButton.setDisable(newValue.isEmpty());
                }
            }
        });

        // Layout buttons and labels in grid
        GridPane gp = new GridPane();
        gp.getStyleClass().add("dialog");

        gp.add(customerContact, 0, 0);
        gp.add(contactList, 1, 0);

        gp.add(startDateLabel, 0, 1);
        gp.add(startDatePicker, 1, 1);

        gp.add(startTimeLabel, 0, 2);
        gp.add(startTimeField, 1, 2);

        gp.add(expiryLabel, 0, 3);
        gp.add(endTimeField, 1, 3);

        gp.add(noteLabel, 0, 4);
        gp.add(noteField, 1, 4);

        gp.add(externalNumberField, 0, 5);
        gp.add(callbackToExternalButton, 1, 5);

        gp.add(cancelButton, 0, 6);
        gp.add(callbackToContactNumberButton, 1, 6);

        bp.setBottom(gp);
    }

    private String startDateTime() {
        // The start datetime required by POM should be in the following format:
        // "2016/7/16 11:50"

        if (startDate != null) {
            return startDate.getYear() + "/" + startDate.getMonthValue() + "/" + startDate.getDayOfMonth() + " "
                    + startTimeField.getText();
        }
        return "";
    }

    private String expiryMinutes() {
        // The expiry time expected by pom is the number of minutes for which
        // the call back should be valid
        return endTimeField.getText();
    }

    private static class CodeCell extends ListCell<DestinationI> {

        @Override
        public void updateItem(DestinationI item, boolean empty) {
            super.updateItem(item, empty);
            if (item != null) {
                String toDisplay = item.getName() + ":";
                // In some cases, ie Standard, there will be no number
                if (item.getNumber() != null)
                    toDisplay += item.getNumber() + ":";
                toDisplay += item.getDestinationType().name();
                setText(toDisplay);
            }
        }
    }

    private static class CustomerCodeCell extends ListCell<ContactNumberI> {

        @Override
        public void updateItem(ContactNumberI item, boolean empty) {
            super.updateItem(item, empty);
            if (item != null) {
                setText(item.getName() + ":" + item.getNumber());
            } else {
                setText(null);
            }
        }
    }
}
