/* 
 *  CustomerDataPane.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.CustomerDetailsI;
import com.avaya.ccs.api.EmailListEntryI;
import com.avaya.ccs.api.PhoneListEntryI;
import com.avaya.ccs.api.PostalAddressListEntryI;
import java.util.List;
import java.util.Optional;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.util.Callback;

public class CustomerDataPane {

    private final BorderPane pane = new BorderPane();
    private TableView<CustomerDataElement> dataTable = new TableView<CustomerDataElement>();
    private final ObservableList<CustomerDataElement> dataList = FXCollections.observableArrayList();
    private Button edit;
    private final InteractionExecutor interactionExe;
    private final InteractionDataGUI gui;
    private static String BLANKCUSTOMERDATA = "No customer data to display";
    private static final Logger LOG = Logger.getLogger(CustomerDataPane.class);
    
    public CustomerDataPane(InteractionExecutor interactionExe, InteractionDataGUI gui) {
        this.gui = gui;
        this.interactionExe = interactionExe;
        pane.getStyleClass().add("customerData");
        pane.setCenter(dataTable);
        createCustomerDataTable();

        edit = new Button("Edit");
        edit.setDisable(true);
        edit.getStyleClass().add("intrinsicButton");
        edit.setOnAction((ActionEvent t) -> {
            //Get data from current table selection
            CustomerDataElement element = (CustomerDataElement) dataTable.getSelectionModel().getSelectedItem();

            if (element != null) {
                if (element.data instanceof CustomerName) {
                    LOG.info("EditButton() CustomerName");
                    CustomerName n = (CustomerName) element.data;
                    editCustomerNameDialog(n.title, n.firstName, n.lastName);
                } else if (element.data instanceof EmailListEntryI) {
                    LOG.info("EditButton() CustomerEmail");
                    EmailListEntryI email = (EmailListEntryI) element.data;
                    editEmailDialog(email);
                } else if (element.data instanceof PhoneListEntryI) {
                    LOG.info("EditButton() CustomerPhone");
                    PhoneListEntryI phone = (PhoneListEntryI) element.data;
                    editPhoneDialog(phone);
                } else if (element.data instanceof PostalAddressListEntryI) {
                    LOG.info("EditButton() CustomerAddress");
                    PostalAddressListEntryI postalAddress = (PostalAddressListEntryI) element.data;
                    editPostalAddressDialog(postalAddress);
                }
            }
        });

        // Edit button should only be enabled if the currently selected item supports editing
        dataTable.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
            if (newSelection != null) {
                CustomerDataElement d = (CustomerDataElement) newSelection;
                edit.setDisable(!d.editable);
            } else {
                edit.setDisable(true);
            }
        });

        HBox buttonHolder = new HBox();
        buttonHolder.getChildren().addAll(edit);
        pane.setBottom(buttonHolder);
    }
    
    public BorderPane getPane() {
        return pane;
    }

    private void createCustomerDataTable() {
        dataTable.setEditable(true);
        dataTable.setPlaceholder(new Label(BLANKCUSTOMERDATA));
        TableColumn<CustomerDataElement, String> name = new TableColumn<CustomerDataElement, String>("Name");
        name.getStyleClass().add("customerDataTableNameRows");

        name.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomerDataElement, String>, ObservableValue<String>>() {
            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<CustomerDataElement, String> p) {
                return new ReadOnlyObjectWrapper<String>(p.getValue().name);
            }
        });

        TableColumn<CustomerDataElement, String> value = new TableColumn<CustomerDataElement, String>("Value");
        value.getStyleClass().add("customerDataTableValueRows");
        value.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomerDataElement, String>, ObservableValue<String>>() {
            @Override
            public ObservableValue<String> call(TableColumn.CellDataFeatures<CustomerDataElement, String> p) {
                return new ReadOnlyObjectWrapper<String>(p.getValue().value);
            }
        });

        dataTable.setItems(dataList);
        dataTable.getColumns().add(name);
        dataTable.getColumns().add(value);
    }

    void update(InteractionDataI data) {
        this.pane.setDisable(!data.canGetCustomerDetails());

        dataList.clear();

        CustomerDetailsI custdetails = data.getCustomerDetails();
        if (custdetails == null) {
            return;
        }

        //Get name data
        CustomerName n = new CustomerName(custdetails.getTitle(), custdetails.getFirstName(), custdetails.getLastName());
        dataList.add(new CustomerDataElement("Title", n.title, data.canUpdateCustomerName(), n));
        dataList.add(new CustomerDataElement("First Name", n.firstName, data.canUpdateCustomerName(), n));
        dataList.add(new CustomerDataElement("Last Name", n.lastName, data.canUpdateCustomerName(), n));

        // Get the list of emails, typically there is only one
        List<EmailListEntryI> emails = custdetails.getEmailList();
        int count = 1;
        for (EmailListEntryI email : emails) {
            dataList.add(new CustomerDataElement("Email-" + count, email.getEmailAddress(), data.canUpdateCustomerEmail(), email));
            count++;
        }

        // Get list of phone numbers
        List<PhoneListEntryI> phones = custdetails.getPhoneList();
        count = 1;
        for (PhoneListEntryI phone : phones) {
            dataList.add(new CustomerDataElement("CountryCode-" + count, phone.getCountryCode(), data.canUpdateCustomerPhone(), phone));
            dataList.add(new CustomerDataElement("PhoneNumber-" + count, phone.getPhoneNumber(), data.canUpdateCustomerPhone(), phone));
            dataList.add(new CustomerDataElement("TimeZone-" + count, phone.getTimezone(), data.canUpdateCustomerPhone(), phone));
            count++;
        }

        // Get list of addresses
        List<PostalAddressListEntryI> addresses = custdetails.getPostalAddressList();
        count = 1;
        for (PostalAddressListEntryI address : addresses) {
            dataList.add(new CustomerDataElement("Address-" + count + "-Line1", address.getLine1(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Line2", address.getLine2(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Line3", address.getLine3(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Line4", address.getLine4(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Line5", address.getLine5(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Country", address.getCountry(), data.canUpdateCustomerAddress(), address));
            dataList.add(new CustomerDataElement("Address-" + count + "-Zip", address.getZipcode(), data.canUpdateCustomerAddress(), address));
            count++;
        }

    }

    private void editCustomerNameDialog(String title, String firstName, String lastName) {
        Dialog<CustomerName> dialog = new Dialog<>();
        dialog.setTitle("Edit Customer Name");

        ButtonType okButtonType = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);

        GridPane grid = new GridPane();
        grid.getStyleClass().add("dialog");

        TextField titleTextField = new TextField();
        titleTextField.setText(title);
        TextField firstNameTextField = new TextField();
        firstNameTextField.setText(firstName);
        TextField lastNameTextField = new TextField();
        lastNameTextField.setText(lastName);

        grid.add(new Label("Title:"), 0, 0);
        grid.add(titleTextField, 1, 0);
        grid.add(new Label("First Name:"), 0, 1);
        grid.add(firstNameTextField, 1, 1);
        grid.add(new Label("Last Name:"), 0, 2);
        grid.add(lastNameTextField, 1, 2);

        dialog.getDialogPane().setContent(grid);

        Platform.runLater(() -> titleTextField.requestFocus());

        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == okButtonType) {
                return new CustomerName(titleTextField.getText(), firstNameTextField.getText(), lastNameTextField.getText());
            }
            return null;
        });

        Optional<CustomerName> result = dialog.showAndWait();

        result.ifPresent(name -> {
            interactionExe.updateCustomerName(gui.getCurrentItemSelection().getId(), name.title, name.firstName, name.lastName);
        });
    }

    private void editEmailDialog(EmailListEntryI email) {
        Dialog<String> dialog = new Dialog<>();
        dialog.setTitle("Edit Customer Email");

        ButtonType signinButtonType = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(signinButtonType, ButtonType.CANCEL);

        GridPane grid = new GridPane();
        grid.getStyleClass().add("dialog");

        TextField emailTextField = new TextField();
        emailTextField.setText(email.getEmailAddress());
        emailTextField.setEditable(true);

        grid.add(new Label("Name:"), 0, 0);
        grid.add(emailTextField, 1, 0);

        dialog.getDialogPane().setContent(grid);

        Platform.runLater(() -> emailTextField.requestFocus());

        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == signinButtonType) {
                return emailTextField.getText();
            }
            return null;
        });

        Optional<String> result = dialog.showAndWait();

        result.ifPresent(emailValue -> {
            email.setEmailAddress(emailValue);
            interactionExe.updateCustomerEmail(gui.getCurrentItemSelection().getId(), email);
        });
    }

    private void editPhoneDialog(PhoneListEntryI phone) {
        Dialog<Phone> dialog = new Dialog<>();
        dialog.setTitle("Edit Customer Phone");

        ButtonType okButtonType = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);

        GridPane grid = new GridPane();
        grid.getStyleClass().add("dialog");

        TextField countryTextField = new TextField();
        countryTextField.setText(phone.getCountryCode());
        countryTextField.setEditable(true);
        TextField numberTextField = new TextField();
        numberTextField.setText(phone.getPhoneNumber());
        numberTextField.setEditable(true);
        TextField timezoneTextField = new TextField();
        timezoneTextField.setText(phone.getTimezone());
        timezoneTextField.setEditable(true);

        grid.add(new Label("Country:"), 0, 0);
        grid.add(countryTextField, 1, 0);
        grid.add(new Label("Phone Number:"), 0, 1);
        grid.add(numberTextField, 1, 1);

        // The valid list of timezones can be obtained from POM manager
        // Since this list is not available through the SDK no validation is performed here
        grid.add(new Label("Time Zone:"), 0, 2);
        grid.add(timezoneTextField, 1, 2);

        dialog.getDialogPane().setContent(grid);

        Platform.runLater(() -> countryTextField.requestFocus());

        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == okButtonType) {
                return new Phone(countryTextField.getText(), numberTextField.getText(), timezoneTextField.getText());
            }
            return null;
        });

        Optional<Phone> result = dialog.showAndWait();

        result.ifPresent(phoneresult -> {
            phone.setCountryCode(phoneresult.countryCode);
            phone.setPhoneNumber(phoneresult.phoneNumber);
            phone.setTimezone(phoneresult.timeZone);
            interactionExe.updateCustomerPhone(gui.getCurrentItemSelection().getId(), phone);
        });
    }

    private void editPostalAddressDialog(PostalAddressListEntryI address) {
        Dialog<Address> dialog = new Dialog<>();
        dialog.setTitle("Edit Customer Address");

        ButtonType okButtonType = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
        dialog.getDialogPane().getButtonTypes().addAll(okButtonType, ButtonType.CANCEL);

        GridPane grid = new GridPane();
        grid.getStyleClass().add("dialog");

        TextField line1TextField = new TextField();
        line1TextField.setText(address.getLine1());
        line1TextField.setEditable(true);
        TextField line2TextField = new TextField();
        line2TextField.setText(address.getLine2());
        line2TextField.setEditable(true);
        TextField line3TextField = new TextField();
        line3TextField.setText(address.getLine3());
        line3TextField.setEditable(true);
        TextField line4TextField = new TextField();
        line4TextField.setText(address.getLine4());
        line4TextField.setEditable(true);
        TextField line5TextField = new TextField();
        line5TextField.setText(address.getLine5());
        line5TextField.setEditable(true);
        TextField countryTextField = new TextField();
        countryTextField.setText(address.getCountry());
        countryTextField.setEditable(true);
        TextField zipCodeTextField = new TextField();
        zipCodeTextField.setText(address.getZipcode());
        zipCodeTextField.setEditable(true);

        grid.add(new Label("Line1:"), 0, 0);
        grid.add(line1TextField, 1, 0);
        grid.add(new Label("Line2:"), 0, 1);
        grid.add(line2TextField, 1, 1);
        grid.add(new Label("Line3:"), 0, 2);
        grid.add(line3TextField, 1, 2);
        grid.add(new Label("Line4:"), 0, 3);
        grid.add(line4TextField, 1, 3);
        grid.add(new Label("Line5:"), 0, 4);
        grid.add(line5TextField, 1, 4);
        grid.add(new Label("Country:"), 0, 5);
        grid.add(countryTextField, 1, 5);
        grid.add(new Label("Zip Code:"), 0, 6);
        grid.add(zipCodeTextField, 1, 6);

        dialog.getDialogPane().setContent(grid);

        Platform.runLater(() -> line1TextField.requestFocus());

        dialog.setResultConverter(dialogButton -> {
            if (dialogButton == okButtonType) {
                return new Address(line1TextField.getText(), line2TextField.getText(), line3TextField.getText(), line4TextField.getText(), line5TextField.getText(), countryTextField.getText(), zipCodeTextField.getText());
            }
            return null;
        });

        Optional<Address> result = dialog.showAndWait();

        result.ifPresent(addressResult -> {
            address.setLine1(addressResult.line1);
            address.setLine2(addressResult.line2);
            address.setLine3(addressResult.line3);
            address.setLine4(addressResult.line4);
            address.setLine5(addressResult.line5);
            address.setCountry(addressResult.country);
            address.setZipcode(addressResult.zipCode);
            interactionExe.updateCustomerAddress(gui.getCurrentItemSelection().getId(), address);
        });
    }

    private class CustomerDataElement {

        public String name;
        public String value;
        public boolean editable;
        public Object data;

        public CustomerDataElement(String n, String v, boolean edit, Object data) {
            this.name = n;
            this.value = v;
            this.editable = edit;
            this.data = data;
        }
    }

    private class CustomerName {

        public String title;
        public String firstName;
        public String lastName;

        public CustomerName(String t, String fN, String lN) {
            this.title = t;
            this.firstName = fN;
            this.lastName = lN;
        }
    }

    private class Phone {

        public String countryCode;
        public String phoneNumber;
        public String timeZone;

        public Phone(String countryCode, String phoneNumber, String timeZone) {
            this.countryCode = countryCode;
            this.phoneNumber = phoneNumber;
            this.timeZone = timeZone;
        }
    }

    private class Address {

        public String line1;
        public String line2;
        public String line3;
        public String line4;
        public String line5;
        public String country;
        public String zipCode;

        public Address(String line1,
                String line2,
                String line3,
                String line4,
                String line5,
                String country,
                String zipCode) {
            this.line1 = line1;
            this.line2 = line2;
            this.line3 = line3;
            this.line4 = line4;
            this.line5 = line5;
            this.country = country;
            this.zipCode = zipCode;
        }
    }
}
