package eu.dnetlib.client.adminpanel;

import com.github.gwtbootstrap.client.ui.*;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
import com.github.gwtbootstrap.client.ui.constants.BackdropType;
import com.github.gwtbootstrap.client.ui.constants.ButtonType;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.query.client.Function;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget;
import eu.dnetlib.client.Admin;
import eu.dnetlib.client.AdminWidget;
import eu.dnetlib.espas.gui.client.UserService;
import eu.dnetlib.espas.gui.client.UserServiceAsync;
import eu.dnetlib.espas.gui.client.user.DataProviderAccessService;
import eu.dnetlib.espas.gui.client.user.DataProviderAccessServiceAsync;
import eu.dnetlib.espas.gui.shared.DataProvider;
import eu.dnetlib.espas.gui.shared.User;

import java.util.*;

import static com.google.gwt.query.client.GQuery.$;

public class ManageDataProviderWidget implements AdminWidget {
	
	private static ManageDataProviderWidget instance = null;

    private FlowPanel manageDataProvidersPanel = new FlowPanel();

    private Alert errorAlert = new Alert();
    private Alert successAlert = new Alert();
    private Alert warningAlert = new Alert();

    private FlowPanel pageControlsPanel = new FlowPanel();
    private FlowPanel dataProvidersPanel = new FlowPanel();

    private TextBox search = new TextBox();

	private DataProviderAccessServiceAsync dataProviderAccessService = GWT.create(DataProviderAccessService.class);
	private UserServiceAsync userAccessService = GWT.create(UserService.class);

	private List<DataProvider> dataProviders = new ArrayList<DataProvider>();
    private List<DataProvider> matchingDataProviders = new ArrayList<DataProvider>();
    private List<User> administrators = new ArrayList<User>();

    private Map<String, DataProvider> dataProviderMap = new HashMap<String, DataProvider>();

	private ManageDataProviderWidget() {

        manageDataProvidersPanel.addStyleName("contentPanel");

        errorAlert.setType(AlertType.ERROR);
        errorAlert.setVisible(false);
        errorAlert.setClose(false);
        manageDataProvidersPanel.add(errorAlert);

        successAlert.setType(AlertType.SUCCESS);
        successAlert.setVisible(false);
        successAlert.setClose(false);
        manageDataProvidersPanel.add(successAlert);

        warningAlert.setType(AlertType.WARNING);
        warningAlert.setVisible(false);
        warningAlert.setClose(false);
        manageDataProvidersPanel.add(warningAlert);

        manageDataProvidersPanel.add(pageControlsPanel);
        manageDataProvidersPanel.add(dataProvidersPanel);

        pageControlsPanel.addStyleName("row");
        pageControlsPanel.addStyleName("page-controls");
	}
	
	public static final ManageDataProviderWidget getInstance() {
		
		if(instance==null)
			instance = new ManageDataProviderWidget();
		
		return instance;
	}

    @Override
    public void clear() {

        errorAlert.setVisible(false);
        successAlert.setVisible(false);
        warningAlert.setVisible(false);

        dataProvidersPanel.clear();
        pageControlsPanel.clear();

        dataProviders.clear();
        administrators.clear();
    }

    @Override
    public void reload() {

        Admin.menuBar.clear();

        Admin.menuBar.add(new HTML("<div class=\"sidebar-toggler visible-xs\"><i class=\"ion-navicon\"></i></div>"));
        Admin.menuBar.add(new HTML("<div class=\"page-title\" id=\"pageTitle\">Data Providers</div>"));

        Form searchForm = new Form();
        searchForm.addStyleName("search");

        search.setPlaceholder("Search data providers (name, namespace)...");
        searchForm.add(search);

        SubmitButton submitSearchButton = new SubmitButton();
        searchForm.add(submitSearchButton);

        searchForm.addSubmitHandler(new Form.SubmitHandler() {
            @Override
            public void onSubmit(Form.SubmitEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                ManageDataProviderWidget.this.matchingDataProviders.clear();

                if(search.getValue()!=null && !search.getValue().trim().equals("")) {

                    for(DataProvider dataProvider : dataProviders) {
                        if(dataProvider.getName().toLowerCase().contains(search.getValue().trim().toLowerCase())
                                || dataProvider.getNamespace().toLowerCase().contains(search.getValue().trim().toLowerCase())) {
                            matchingDataProviders.add(dataProvider);
                        }
                    }

                } else {
                    matchingDataProviders.addAll(dataProviders);
                }

                updateContents(matchingDataProviders);
            }
        });

        Admin.menuBar.add(searchForm);

        Button addNewAnnouncement = new Button();
        addNewAnnouncement.setText("New Data Provider");
        addNewAnnouncement.setType(ButtonType.SUCCESS);
        addNewAnnouncement.addStyleName("pull-right");
        addNewAnnouncement.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                DataProviderFormModal dataProviderFormModal = new DataProviderFormModal(null);
                DataProviderFormModal.DataProviderFormListener dataProviderFormListener =
                        new DataProviderFormModal.DataProviderFormListener() {
                    @Override
                    public void onSaved() {
                        updateDataProviders(false, "Data Provider saved successfully");
                    }
                };
                dataProviderFormModal.setDataProviderFormListener(dataProviderFormListener);
                dataProviderFormModal.show();
            }
        });

        Admin.menuBar.add(addNewAnnouncement);

        updateDataProviders(true, null);
    }

    private void updateDataProviders(final boolean clearAlerts, final String successMessage) {

        final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
        manageDataProvidersPanel.addStyleName("loading-big");
        manageDataProvidersPanel.add(loadingWheel);

        dataProviderAccessService.getDataProviders(new AsyncCallback<List<DataProvider>>() {

            @Override
            public void onSuccess(final List<DataProvider> dataProviders) {

                dataProviderMap.clear();
                for (DataProvider dataProvider : dataProviders)
                    dataProviderMap.put(dataProvider.getNamespace(), dataProvider);

                ManageDataProviderWidget.this.dataProviders.clear();
                ManageDataProviderWidget.this.dataProviders.addAll(dataProviders);

                ManageDataProviderWidget.this.matchingDataProviders.clear();

                if(search.getValue()!=null && !search.getValue().trim().equals("")) {

                    for(DataProvider dataProvider : dataProviders) {
                        if(dataProvider.getName().toLowerCase().contains(search.getValue().trim().toLowerCase())
                                || dataProvider.getNamespace().toLowerCase().contains(search.getValue().trim().toLowerCase())) {
                            matchingDataProviders.add(dataProvider);
                        }
                    }

                } else {
                    matchingDataProviders.addAll(dataProviders);
                }

                userAccessService.getDataProviderUsers(new AsyncCallback<List<User>>() {

                    @Override
                    public void onFailure(Throwable caught) {

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        successAlert.setVisible(false);
                        warningAlert.setVisible(false);

                        errorAlert.setText("System error retrieving data provider administrators");
                        errorAlert.setVisible(true);
                    }

                    @Override
                    public void onSuccess(List<User> administrators) {

                        if (clearAlerts) {
                            errorAlert.setVisible(false);
                            successAlert.setVisible(false);
                            warningAlert.setVisible(false);
                        }

                        if (successMessage != null) {
                            successAlert.setText(successMessage);
                            successAlert.setVisible(true);
                        }

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        ManageDataProviderWidget.this.administrators.addAll(administrators);

                        updateContents(matchingDataProviders);
                    }
                });
            }

            @Override
            public void onFailure(Throwable arg0) {

                manageDataProvidersPanel.removeStyleName("loading-big");
                manageDataProvidersPanel.remove(loadingWheel);

                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                errorAlert.setText("System error retrieving data providers");
                errorAlert.setVisible(true);
            }
        });
    }

    @Override
    public void setToken(String token) {

    }

    @Override
    public void afterAdditionToRootPanel() {

    }
	
	public void updateContents(List<DataProvider> dataProviders) {

        dataProvidersPanel.clear();

        String contents = "<div class=\"row dataProviders-list\">";
        contents += "<div class=\"col-md-12\">";

        contents += "<div class=\"row headers\">" +
                "<div class=\"col-sm-1 header select-users\">" +
                "<label><a href=\"#\">Namespace</a></label>" +
                "</div>" +
                "<div class=\"col-sm-2 header hidden-xs\">" +
                "<label><a href=\"#\">Name</a></label>" +
                "</div>" +
                "<div class=\"col-sm-3 header hidden-xs\">" +
                "<label><a href=\"#\">Wrapper URL</a></label>" +
                "</div>" +
                "<div class=\"col-sm-3 header hidden-xs\">" +
                "<label><a href=\"#\">SOS URL</a></label>" +
                "</div>" +
                "<div class=\"col-sm-2 header hidden-xs\">" +
                "<label><a href=\"#\">Administrators</a></label>" +
                "</div>" +
                "<div class=\"col-sm-1 header hidden-xs\">" +
                "<label><a href=\"#\">Actions</a></label>" +
                "</div>" +
                "</div>";

        if(dataProviders.size()==0) {

            contents += "<div class=\"row user\">" +
                    "<div class=\"col-md-12\"><div class=\"alert alert-warning\">No data providers found</div></div>" +
                    "</div>";

        } else {

            for(DataProvider dataProvider : dataProviders) {

                contents += "<div class=\"row user\">" +
                        "<div class=\"col-sm-1\"><div class=\"namespace\" href=\"#\">" + dataProvider.getNamespace() + "</div></div>" +
                        "<div class=\"col-sm-2\"><div class=\"name\" href=\"#\">" + dataProvider.getName() + "</div></div>";

                if(dataProvider.getWrapperURL()==null || dataProvider.getWrapperURL().trim().equals(""))
                    contents += "<div class=\"col-sm-3\"><div class=\"wrapperURL\" href=\"#\">-- none available --</div></div>";
                else
                    contents += "<div class=\"col-sm-3\"><a class=\"wrapperURL\" href=\"#\">" + dataProvider.getWrapperURL() + "</a></div>";

                if(dataProvider.getSosServiceURL()==null || dataProvider.getSosServiceURL().trim().equals(""))
                    contents += "<div class=\"col-sm-3\"><div class=\"sosURL\" href=\"#\">-- none available --</div></div>";
                else
                    contents += "<div class=\"col-sm-3\"><a class=\"sosURL\" href=\"#\">" + dataProvider.getSosServiceURL() + "</a></div>";

                String admins = "";
                for(int i=0; i<dataProvider.getAdministratorEmails().size(); i++) {
                    if(i!=0)
                        admins += ", ";
                    admins += dataProvider.getAdministratorEmails().get(i);
                }

                contents += "<div class=\"col-sm-2\"><div class=\"admins\" href=\"#\">" + admins + "</div></div>" +
                        "<div class=\"col-sm-1\"><div class=\"actions\" href=\"#\"><input id=\"" + dataProvider.getNamespace() + "#edit\" type=\"image\" title=\"Edit\" src=\"imgs/icn_edit.png\" class=\"edit\">" +
                        "<input id=\"" + dataProvider.getNamespace() + "#delete\" type=\"image\" title=\"Delete\" src=\"imgs/icn_trash.png\" class=\"delete\"></div></div>" +
                        "</div>";
            }
        }

        contents += "</div>";
        contents += "</div>";

        HTML usersList = new HTML();
        usersList.setHTML(contents);

        dataProvidersPanel.add(usersList);

        addWidgetHandlers();
	}

	@Override
	public Widget asWidget() {
		return manageDataProvidersPanel;
	}
	
	public void addWidgetHandlers() {

        $(".edit").click(new Function() {

            public boolean f(Event e) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                String[] idParts = $(e).get(0).getId().split("#");

                DataProviderFormModal dataProviderFormModal = new DataProviderFormModal(dataProviderMap.get(idParts[0]));
                DataProviderFormModal.DataProviderFormListener dataProviderFormListener =
                        new DataProviderFormModal.DataProviderFormListener() {
                    @Override
                    public void onSaved() {
                        updateDataProviders(false, "Data Provider updated successfully");
                    }
                };
                dataProviderFormModal.setDataProviderFormListener(dataProviderFormListener);
                dataProviderFormModal.show();

                return true;
            }
        });

        $(".delete").click(new Function() {

            public boolean f(Event e) {

                errorAlert.setVisible(false);
                successAlert.setVisible(false);
                warningAlert.setVisible(false);

                String[] idParts = $(e).get(0).getId().split("#");
                final String dataProviderId = idParts[0];

                final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
                manageDataProvidersPanel.addStyleName("loading-big");
                manageDataProvidersPanel.add(loadingWheel);

                dataProviderAccessService.getEntriesCount(dataProviderId, new AsyncCallback<Map<String, Integer>>() {

                    @Override
                    public void onFailure(Throwable caught) {

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        successAlert.setVisible(false);
                        warningAlert.setVisible(false);

                        errorAlert.setText("System error retrieving data provider entries count");
                        errorAlert.setVisible(true);
                    }

                    @Override
                    public void onSuccess(Map<String, Integer> entriesCount) {

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        deleteDataProvider(dataProviderId, entriesCount);
                    }
                });

                return true;
            }
        });
	}

    private void deleteDataProvider(final String dataProviderId, Map<String, Integer> entriesCount) {

        final Modal deleteConfirmationPopup = new Modal();

        deleteConfirmationPopup.addStyleName("confirmationModal");
        deleteConfirmationPopup.setAnimation(true);
        deleteConfirmationPopup.setBackdrop(BackdropType.STATIC);

        deleteConfirmationPopup.setTitle("Delete Confirmation");

        HTML entriesInfo = new HTML();
        entriesInfo.addStyleName("entriesInfo");

        String entriesInfoContent = "";
        if(entriesCount.get("all")==0) {
            entriesInfoContent = "There are no entries associated with this data provider";
        } else {

            entriesInfoContent = "There are " + entriesCount.get("all") + " entries associated with this data provider";

            if(entriesCount.get("observation")!=0)
                entriesInfoContent += "<br><strong>Observations: </strong>" + entriesCount.get("observation");

            if(entriesCount.get("observationCollection")!=0)
                entriesInfoContent += "<br><strong>Observation Collections: </strong>" + entriesCount.get("observationCollection");

            if(entriesCount.get("platform")!=0)
                entriesInfoContent += "<br><strong>Platforms: </strong>" + entriesCount.get("platform");

            if(entriesCount.get("operation")!=0)
                entriesInfoContent += "<br><strong>Operations: </strong>" + entriesCount.get("operation");

            if(entriesCount.get("instrument")!=0)
                entriesInfoContent += "<br><strong>Instruments: </strong>" + entriesCount.get("instrument");

            if(entriesCount.get("computation")!=0)
                entriesInfoContent += "<br><strong>Computations: </strong>" + entriesCount.get("computation");

            if(entriesCount.get("acquisition")!=0)
                entriesInfoContent += "<br><strong>Acquisitions: </strong>" + entriesCount.get("acquisition");

            if(entriesCount.get("compositeProcess")!=0)
                entriesInfoContent += "<br><strong>Composite Processes: </strong>" + entriesCount.get("compositeProcess");

            if(entriesCount.get("project")!=0)
                entriesInfoContent += "<br><strong>Projects: </strong>" + entriesCount.get("project");

            if(entriesCount.get("organization")!=0)
                entriesInfoContent += "<br><strong>Organisations: </strong>" + entriesCount.get("organization");

            if(entriesCount.get("individual")!=0)
                entriesInfoContent += "<br><strong>Individuals: </strong>" + entriesCount.get("individual");
        }

        entriesInfo.setHTML(entriesInfoContent);
        deleteConfirmationPopup.add(entriesInfo);

        HTML message = new HTML("Are you sure you want to delete the selected data provider?");
        deleteConfirmationPopup.add(message);

        FlowPanel actionButtons = new FlowPanel();
        actionButtons.addStyleName("confirmationModalButtons");

        ModalFooter modalFooter = new ModalFooter();
        modalFooter.add(actionButtons);
        deleteConfirmationPopup.add(modalFooter);

        Button no = new Button("Cancel");
        no.setType(ButtonType.DEFAULT);
        no.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                deleteConfirmationPopup.hide();
                deleteConfirmationPopup.removeFromParent();
            }
        });
        actionButtons.add(no);

        Button yes = new Button("Yes, delete it");
        yes.setType(ButtonType.DANGER);
        yes.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {

                deleteConfirmationPopup.hide();
                deleteConfirmationPopup.removeFromParent();

                final HTML loadingWheel = new HTML("<div class=\"loader-big\"></div><div class=\"whiteFilm\"></div>");
                manageDataProvidersPanel.addStyleName("loading-big");
                manageDataProvidersPanel.add(loadingWheel);

                dataProviderAccessService.deleteDataProvider(dataProviderId, new AsyncCallback<Void>() {

                    @Override
                    public void onFailure(Throwable caught) {

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        errorAlert.setText("Failed to delete the selected data provider");
                        errorAlert.setVisible(true);
                    }

                    @Override
                    public void onSuccess(Void result) {

                        manageDataProvidersPanel.removeStyleName("loading-big");
                        manageDataProvidersPanel.remove(loadingWheel);

                        updateDataProviders(false, "Data provider deleted successfully");
                    }
                });
            }
        });
        actionButtons.add(yes);

        deleteConfirmationPopup.show();
    }
}
