package eu.dnetlib.client.adminpanel;

import com.github.gwtbootstrap.client.ui.Alert;
import com.github.gwtbootstrap.client.ui.Button;
import com.github.gwtbootstrap.client.ui.constants.AlertType;
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.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.TimeZone;
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.shared.dashboard.DashboardData;
import eu.dnetlib.shared.dashboard.Tuple;
import eu.dnetlib.shared.dashboard.UserGraph;
import org.moxieapps.gwt.highcharts.client.*;
import org.moxieapps.gwt.highcharts.client.labels.*;
import org.moxieapps.gwt.highcharts.client.plotOptions.*;

import java.util.*;

/**
 * Created by stefania on 10/2/15.
 */
public class DashboardWidget implements AdminWidget {

    private static DashboardWidget instance = null;

    private FlowPanel dashboardPanel = new FlowPanel();

    private Alert errorAlert = new Alert();

    private FlowPanel dashboardContentPanel = new FlowPanel();

    private DashboardDataServiceAsync dashboardDataService = GWT.create(DashboardDataService.class);

    private DashboardWidget() {

        dashboardPanel.addStyleName("contentPanel");

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

        dashboardPanel.add(dashboardContentPanel);
    }

    public static final DashboardWidget getInstance() {

        if(instance==null)
            instance = new DashboardWidget();

        return instance;
    }

    @Override
    public Widget asWidget() {
        return dashboardPanel;
    }

    @Override
    public void clear() {
        errorAlert.setVisible(false);
        dashboardContentPanel.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\">Dashboard</div>"));

        Button viewESPASPortal = new Button();
        viewESPASPortal.setText("View ESPAS Portal");
        viewESPASPortal.setTarget("_blank");
        viewESPASPortal.setType(ButtonType.INFO);
        viewESPASPortal.addStyleName("pull-right");
        viewESPASPortal.setHref("https://www.espas-fp7.eu/portal/");
        Admin.menuBar.add(viewESPASPortal);

        updateDashboardData();
    }

    private void updateDashboardData() {

    }

    @Override
    public void setToken(String token) {

    }

    @Override
    public void afterAdditionToRootPanel() {

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

        dashboardDataService.getDashboardData(new AsyncCallback<DashboardData>() {

            @Override
            public void onFailure(Throwable caught) {

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

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

            @Override
            public void onSuccess(DashboardData dashboardData) {

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

                if(dashboardData!=null)
                    updateContents(dashboardData);
            }
        });
    }

    public void updateContents(DashboardData dashboardData) {

        dashboardContentPanel.add(createDashboardNumbers(dashboardData));
        dashboardContentPanel.add(createUserLoginsGraph(dashboardData.getDailyLogins()));
        dashboardContentPanel.add(createUserRegistrationsGraph(dashboardData.getUserGraph()));
        dashboardContentPanel.add(createRequestsGraph(dashboardData.getRequestGraph()));
        dashboardContentPanel.add(createDownloadStatusDonut(dashboardData.getRequestStatusGraph()));
        dashboardContentPanel.add(createUserSectorPie(dashboardData.getUsersPerSector()));
    }

    private HTML createDashboardNumbers(DashboardData dashboardData) {

        String content = "<div class=\"metrics clearfix\"><div class=\"metric\"><span class=\"field\">Total users</span>" +
                "<span class=\"data\">" + dashboardData.getTotalUsers() + "</span></div><div class=\"metric\">" +
                "<span class=\"field\">Total Data Providers</span><span class=\"data\">" + dashboardData.getTotalDataProviders() +
                "</span></div><div class=\"metric\"><span class=\"field\">Data Providers with Data</span><span class=\"data\">" +
                dashboardData.getTotalDataProvidersWithData() + "</span></div><div class=\"metric\"><span class=\"field\">" +
                "Total number of Observations</span><span class=\"data\">" + dashboardData.getTotalObservations() + "</span></div></div>";

        HTML dashboardNumbersContents = new HTML();
        dashboardNumbersContents.setHTML(content);

        return dashboardNumbersContents;
    }

    private FlowPanel createUserLoginsGraph(List<Tuple<Date, Integer>> dailyLogins) {

        FlowPanel userGraphPanel = new FlowPanel();
        userGraphPanel.addStyleName("chart");
        userGraphPanel.addStyleName("usersGraphPanel");

        final TimeZone tz = TimeZone.createTimeZone(0);

        final Chart chart = new Chart()
                .setType(Series.Type.LINE)
                .setChartTitleText("User Logins Statistics")
                .setChartSubtitleText("for the last 30 days")
                .setZoomType(Chart.ZoomType.X_AND_Y)
                .setToolTip(new ToolTip()
                                .setFormatter(new ToolTipFormatter() {
                                    public String format(ToolTipData toolTipData) {

                                        return DateTimeFormat.getFormat("yyyy-MM-dd").format(
                                                new Date(toolTipData.getXAsLong()), tz)
                                                + ": " + toolTipData.getYAsDouble();
                                    }
                                })
                )
                .setCredits(new Credits()
                        .setText("from ESPAS via Highcharts (date: " + DateTimeFormat.getFormat("yyyy-MM-dd").format(new Date()) + ")")
                        .setStyle(new Style().setMargin("10px"))
                        .setX(-10)
                        .setY(-2)
                        .setVerticalAlign(Credits.VerticalAlign.BOTTOM));

        chart.getXAxis()
                .setType(Axis.Type.DATE_TIME)
                .setStartOnTick(true)
                .setEndOnTick(true)
                .setShowLastLabel(true);

        chart.getYAxis()
                .setAxisTitleText("Number of Users");

        Number[][] totalRegisteredUsersParams = new Number[dailyLogins.size()][2];
        for(int j=0; j<dailyLogins.size(); j++) {
            totalRegisteredUsersParams[j][0] = dailyLogins.get(j).getFirst().getTime();
            totalRegisteredUsersParams[j][1] = dailyLogins.get(j).getSecond();
        }

        chart.addSeries(chart.createSeries()
                .setName("User Logins")
                .setPlotOptions(
                        new LinePlotOptions()
                                .setColor("#89A54E")
                )
                .setPoints(totalRegisteredUsersParams));

        chart.setWidth("100%");
        chart.setHeight("100%");

        userGraphPanel.add(chart);

        return userGraphPanel;
    }

    private FlowPanel createUserRegistrationsGraph(UserGraph userGraph) {

        FlowPanel userGraphPanel = new FlowPanel();
        userGraphPanel.addStyleName("chart");
        userGraphPanel.addStyleName("usersGraphPanel");

        final TimeZone tz = TimeZone.createTimeZone(0);

        final Chart chart = new Chart()
                .setType(Series.Type.LINE)
                .setChartTitleText("User Registrations Statistics")
                .setZoomType(Chart.ZoomType.X_AND_Y)
                .setToolTip(new ToolTip()
                                .setFormatter(new ToolTipFormatter() {
                                    public String format(ToolTipData toolTipData) {

                                        return DateTimeFormat.getFormat("yyyy-MM").format(
                                                new Date(toolTipData.getXAsLong()), tz)
                                                + ": " + toolTipData.getYAsDouble();
                                    }
                                })
                )
                .setCredits(new Credits()
                        .setText("from ESPAS via Highcharts (date: " + DateTimeFormat.getFormat("yyyy-MM-dd").format(new Date()) + ")")
                        .setStyle(new Style().setMargin("10px"))
                        .setX(-10)
                        .setY(-2)
                        .setVerticalAlign(Credits.VerticalAlign.BOTTOM));

        chart.getXAxis()
                .setType(Axis.Type.DATE_TIME)
                .setStartOnTick(true)
                .setEndOnTick(true)
                .setShowLastLabel(true)
                .setOption("ordinal", false)
                .setDateTimeLabelFormats(new DateTimeLabelFormats()
                                .setMonth("%b '%Y")
                );

        chart.getYAxis()
                .setAxisTitleText("Number of Users");

        Number[][] totalRegisteredUsersParams = new Number[userGraph.getRegisteredPerMonth().size()][2];
        for(int j=0; j<userGraph.getRegisteredPerMonth().size(); j++) {
            totalRegisteredUsersParams[j][0] = userGraph.getRegisteredPerMonth().get(j).getFirst().getTime();
            totalRegisteredUsersParams[j][1] = userGraph.getRegisteredPerMonth().get(j).getSecond();
        }

        chart.addSeries(chart.createSeries()
                .setName("Total number of registered users")
                .setPlotOptions(
                        new LinePlotOptions()
                                .setColor("#DB843D")
                )
                .setPoints(totalRegisteredUsersParams));

        Number[][] registeredUsersPerMonthParams = new Number[userGraph.getRegistrationsPerMonth().size()][2];
        for(int j=0; j<userGraph.getRegistrationsPerMonth().size(); j++) {
            registeredUsersPerMonthParams[j][0] = userGraph.getRegistrationsPerMonth().get(j).getFirst().getTime();
            registeredUsersPerMonthParams[j][1] = userGraph.getRegistrationsPerMonth().get(j).getSecond();
        }

        chart.addSeries(chart.createSeries()
                .setName("New registered users")
                .setPlotOptions(
                        new LinePlotOptions()
                                .setColor("#2B908F")
                )
                .setPoints(registeredUsersPerMonthParams));

        chart.setWidth("100%");
        chart.setHeight("100%");

        userGraphPanel.add(chart);

        return userGraphPanel;
    }

    private FlowPanel createRequestsGraph(Map<String, Tuple<Integer, Integer>> requestsGraph) {

        FlowPanel requestsGraphPanel = new FlowPanel();
        requestsGraphPanel.addStyleName("chart");
        requestsGraphPanel.addStyleName("requestsGraphPanel");

        final Chart chart = new Chart()
                .setType(Series.Type.COLUMN)
                .setChartTitleText("Download Requests Statistics")
                .setColumnPlotOptions(new ColumnPlotOptions()
                                .setStacking(PlotOptions.Stacking.NORMAL)
                                .setDataLabels(new DataLabels()
                                                .setEnabled(false)
                                                .setColor("#FFFFFF")
                                )
                )
                .setCredits(new Credits()
                        .setText("from ESPAS via Highcharts (date: " + DateTimeFormat.getFormat("yyyy-MM-dd").format(new Date()) + ")")
                        .setStyle(new Style().setMargin("10px"))
                        .setX(-10)
                        .setY(-2)
                        .setVerticalAlign(Credits.VerticalAlign.BOTTOM))
                .setToolTip(new ToolTip()
                                .setFormatter(new ToolTipFormatter() {
                                    public String format(ToolTipData toolTipData) {
                                        return "<b>" + toolTipData.getXAsString() + "</b><br/>" +
                                                toolTipData.getSeriesName() + ": " + toolTipData.getYAsLong() + "<br/>" +
                                                "Total: " + toolTipData.getTotal();
                                    }
                                })
                );

        String[] dataProviders = new String[requestsGraph.size()];
        Integer[] fileDownloadRequests = new Integer[requestsGraph.size()];
        Integer[] dataDownloadRequests = new Integer[requestsGraph.size()];

        int i=0;
        for(String dataProviderName : requestsGraph.keySet()) {

            dataProviders[i] = dataProviderName;
            fileDownloadRequests[i] = requestsGraph.get(dataProviderName).getFirst();
            dataDownloadRequests[i] = requestsGraph.get(dataProviderName).getSecond();

            i++;
        }

        chart.getXAxis()
                .setCategories(dataProviders);

        chart.getYAxis()
                .setMin(0)
                .setAxisTitleText("Number of Download requests")
                .setStackLabels(new StackLabels()
                                .setEnabled(true)
                                .setStyle(new Style()
                                                .setFontWeight("bold")
                                                .setColor("gray")
                                )
                );

        chart.addSeries(chart.createSeries()
                        .setName("File Download requests")
                        .setPlotOptions(
                                new LinePlotOptions()
                                        .setColor("#80699B")
                        )
                        .setPoints(fileDownloadRequests)
        );
        chart.addSeries(chart.createSeries()
                        .setName("Data Download requests")
                        .setPlotOptions(
                                new LinePlotOptions()
                                        .setColor("#3D96AE")
                        )
                        .setPoints(dataDownloadRequests)
        );

        chart.setWidth("100%");
        chart.setHeight("100%");

        requestsGraphPanel.add(chart);

        return requestsGraphPanel;
    }

    private FlowPanel createUserSectorPie(List<Tuple<String, Integer>> usersPerSector) {

        FlowPanel userSectorPiePanel = new FlowPanel();
        userSectorPiePanel.addStyleName("chart");
        userSectorPiePanel.addStyleName("userSectorPiePanel");

        final Chart chart = new Chart()
                .setType(Series.Type.PIE)
                .setChartTitleText("Academic / Commercial sector users")
                .setPlotBackgroundColor((String) null)
                .setPlotBorderWidth(null)
                .setPlotShadow(false)
                .setPiePlotOptions(new PiePlotOptions()
                                .setAllowPointSelect(true)
                                .setCursor(PlotOptions.Cursor.POINTER)
                                .setPieDataLabels(new PieDataLabels()
                                                .setConnectorColor("#000000")
                                                .setEnabled(true)
                                                .setColor("#000000")
                                                .setFormatter(new DataLabelsFormatter() {
                                                    public String format(DataLabelsData dataLabelsData) {
                                                        return "<b>" + dataLabelsData.getPointName() + "</b>: " + dataLabelsData.getYAsDouble();
                                                    }
                                                })
                                )
                )
                .setToolTip(new ToolTip()
                                .setFormatter(new ToolTipFormatter() {
                                    public String format(ToolTipData toolTipData) {
                                        return "<b>" + toolTipData.getPointName() + "</b>: " + toolTipData.getYAsDouble();
                                    }
                                })
                );

        String[] colorPalette = new String[] {"#4572A7", "#FF7599"};

        Point[] sectorPoints = new Point[usersPerSector.size()];
        for(int i=0; i<usersPerSector.size(); i++) {
            sectorPoints[i] = new Point(usersPerSector.get(i).getFirst(), usersPerSector.get(i).getSecond())
                                .setColor(colorPalette[i]);
        }

        chart.addSeries(chart.createSeries()
                        .setName("Intended Use")
                        .setPoints(sectorPoints)
        );

        chart.setWidth("100%");
        chart.setHeight("100%");

        userSectorPiePanel.add(chart);

        return userSectorPiePanel;
    }

    private FlowPanel createDownloadStatusDonut(Map<String, Tuple<Integer, Integer>> requestStatusGraph) {

        FlowPanel userSectorPiePanel = new FlowPanel();
        userSectorPiePanel.addStyleName("chart");
        userSectorPiePanel.addStyleName("requestStatusDonutPanel");

        final Chart chart = new Chart()
                .setType(Series.Type.PIE)
                .setMargin(50, 0, 0, 0)
                .setChartTitleText("Request status shares for download requests")
                .setChartSubtitleText("Inner circle: File Download requests - Outer circle: Data Download requests")
                .setPlotBackgroundColor("none")
                .setPlotBorderWidth(0)
                .setPlotShadow(false)
                .setToolTip(new ToolTip()
                                .setFormatter(new ToolTipFormatter() {
                                    public String format(ToolTipData toolTipData) {
                                        return "<b>" + toolTipData.getSeriesName() + "</b><br/>" +
                                                toolTipData.getPointName() + ": " + toolTipData.getYAsDouble();
                                    }
                                })
                );

        String[] colorPalette = new String[]{"#89A54E", "#80699B", "#3D96AE", "#DB843D", "#FF7599", "#4572A7", "#AA4643", "#2B908F"};

        Point[] fileDownloadStatuses = new Point[requestStatusGraph.size()];
        Point[] dataDownloadStatuses = new Point[requestStatusGraph.size()];

        int i=0;
        for(String downloadStatus : requestStatusGraph.keySet()) {

            fileDownloadStatuses[i] = new Point(downloadStatus, requestStatusGraph.get(downloadStatus).getFirst()).setColor(colorPalette[i]);
            dataDownloadStatuses[i] = new Point(downloadStatus, requestStatusGraph.get(downloadStatus).getSecond()).setColor(colorPalette[i]);

            i++;
        }

        chart.addSeries(chart.createSeries()
                        .setName("File Download requests")
                        .setPlotOptions(new PiePlotOptions()
                                        .setCenter(.5, .5)
                                        .setSize(.45)
                                        .setInnerSize(.20)
                                        .setDataLabels(new DataLabels()
                                                        .setEnabled(false)
                                        )
                        )
                        .setPoints(fileDownloadStatuses)
        );

        chart.addSeries(chart.createSeries()
                        .setName("Data Download requests")
                        .setPlotOptions(new PiePlotOptions()
                                        .setCenter(.5, .5)
                                        .setInnerSize(.45)
                                        .setPieDataLabels(new PieDataLabels()
                                                        .setEnabled(true)
                                                        .setColor("#000000")
                                                        .setConnectorColor("#000000")
                                        )
                        )
                        .setPoints(dataDownloadStatuses)
        );

        chart.setWidth("100%");
        chart.setHeight("100%");

        userSectorPiePanel.add(chart);

        return userSectorPiePanel;
    }
}
