# PrintPreviewPresenter.java

    /*
    ** Module   : PrintPreviewPresenter.java
    ** Abstract : PrintPreviewPresenter is a controller that implements business methods to work
    **            with print preview.
    **
    ** Copyright (c) 2017, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ----------------Description----------------------
    ** 001 SBI 20170601 Created initial version.
    */
    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.admin.client.application.home.print;

    import java.util.Collections;
    import java.util.HashMap;
    import java.util.LinkedHashSet;
    import java.util.Map;
    import java.util.function.Consumer;
    import java.util.logging.Level;

    import com.goldencode.p2j.admin.client.*;
    import com.goldencode.p2j.admin.client.application.Alarm;
    import com.goldencode.p2j.admin.client.application.home.AsyncAction;
    import com.goldencode.p2j.admin.client.application.home.BasePresenter;
    import com.goldencode.p2j.admin.client.application.home.HomePresenter;
    import com.goldencode.p2j.admin.client.widget.dialog.ModalDialogs;
    import com.goldencode.p2j.admin.shared.AdminServiceAsync;
    import com.goldencode.p2j.admin.shared.PaperFormat;
    import com.goldencode.p2j.admin.shared.PaperOrientation;
    import com.goldencode.p2j.admin.shared.ReportParameters;
    import com.goldencode.p2j.admin.shared.ReportPreview;
    import com.goldencode.p2j.admin.shared.ReportRequest;
    import com.google.gwt.core.client.GWT;
    import com.google.gwt.user.client.Window;
    import com.google.gwt.user.client.rpc.AsyncCallback;
    import com.google.gwt.view.client.Range;
    import com.google.inject.Inject;
    import com.google.web.bindery.event.shared.EventBus;
    import com.gwtplatform.mvp.client.HasUiHandlers;
    import com.gwtplatform.mvp.client.View;
    import com.gwtplatform.mvp.client.annotations.NameToken;
    import com.gwtplatform.mvp.client.annotations.ProxyStandard;
    import com.gwtplatform.mvp.client.presenter.slots.NestedSlot;
    import com.gwtplatform.mvp.client.proxy.PlaceManager;
    import com.gwtplatform.mvp.client.proxy.ProxyPlace;
    import com.gwtplatform.mvp.shared.proxy.PlaceRequest;

    /**
     * PrintPreviewPresenter is a controller that implements business methods to work with
     * print preview.
     */
    public class PrintPreviewPresenter
    extends BasePresenter<PrintPreviewPresenter.MyView, PrintPreviewPresenter.MyProxy>
    implements PrintPreviewUiHandlers
    {
       /** The attachment point for dependent modal dialogs on this view */
       public static final NestedSlot MODAL_CONTENT = new NestedSlot();

       /**
        * Defines the proxy place for GWTP framework. Binds /print/preview url to this presenter.
        */
       @ProxyStandard
       @NameToken(NameTokens.PRINT_PREVIEW)
       public interface MyProxy
       extends ProxyPlace<PrintPreviewPresenter>
       {}

       /**
        * This view interface that must be implemented by the concrete view according to GWTP
        * framework. Defines the exposed business methods.
        */
       interface MyView
       extends View, HasUiHandlers<PrintPreviewUiHandlers>, Consumer<ReportPreview>
       {
          /**
           * Sets the preview title.
           *
           * @param    title
           *           The title text
           */
          void setPreviewTitle(String title);

          /**
           * This is called when presenter has all the information to render the preview.
           */
          void onReportReady();

          /**
           * Gets the current preview range that is defined by the start page and the page count.
           *
           * @return   The current preview range
           */
          Range getCurrentRange();

          /**
           * The view callback method that is invoked by its presenter executing onHide()
           * lifecycle method.
           */
          void onHide();

          /**
           * Sets the requested paper format. The server supports the paper format defined by
           * PaperFormat enumeration.
           *
           * @param    value
           *           The paper format string
           */
          void setPaperFormat(String value);

          /**
           * Sets the requested paper orientation. The server supports the paper orientation defined
           * by PaperOrientation enumeration.
           *
           * @param    value
           *           The paper orientation well-known string, LANDSCAPE or PORTRAIT.
           */
          void setPaperOrientation(String value);

          /**
           * Requests the extended detailed report or the short form report.
           *
           * @param    b
           *           The true value means to display the extended detailed report, otherwise
           *           the short form report.
           */
          void checkDisplayDetails(boolean b);

          /**
           * Shows or hides the Display All Details check box.
           *
           * @param    visible
           *           The boolean value that defines the visibility of the Display All Details
           *           check box
           */
          void setDisplayDetailsVisible(boolean visible);
       }

       /**
        * Defines the account extension
        */
       private AccountExtension acctExtension;

       /** Administration server interface */
       private final AdminServiceAsync adminService;

       /** The common modal dialogs manager */
       private final ModalDialogs modalDialogsManager;

       /** The server alarms manager */
       private final Alarm serverAlarmsManager;

       /** The report parameters, key to its value map */
       private final HashMap<String, String> reportParameters;

       /** The report id */
       private String report;

       /** The selected data for the selected rows report. It holds the array of account names. */
       private String[] selectedRows;

       /** The relative URL path to the view from which this view has been displayed */
       private String pathToParentView;

       /**
        * Defines the Print Preview presenter.
        *
        * @param    eventBus
        *           The event bus
        * @param    view
        *           The associated view
        * @param    proxy
        *           The proxy place
        * @param    placeManager
        *           The place manager
        * @param    adminService
        *           The administration service
        * @param    modalDialogsManager
        *           The common modal dialogs manager
        * @param    serverAlarmsManager
        *           The server alarms
        * @param    acctExtension
        *           The account extension holder
        */
       @Inject
       public PrintPreviewPresenter(EventBus eventBus,
                                    MyView view,
                                    MyProxy proxy,
                                    PlaceManager placeManager,
                                    AdminServiceAsync adminService,
                                    ModalDialogs modalDialogsManager,
                                    Alarm serverAlarmsManager,
                                    AccountExtensionHolder acctExtension)
       {
          super(eventBus, view, proxy, HomePresenter.SLOT_CONTENT, placeManager);
          this.adminService = adminService;
          this.modalDialogsManager = modalDialogsManager;
          this.serverAlarmsManager = serverAlarmsManager;
          this.reportParameters = new HashMap<String, String>();
          this.acctExtension = acctExtension.value;

          MyView v = getView();
          v.setUiHandlers(this);
          v.setDisplayDetailsVisible(this.acctExtension != null);
       }

       /**
        * Loads the data before the associated view will be displayed.
        *
        * @param    request
        *           The current request
        */
       @Override
       public void prepareFromRequest(PlaceRequest request)
       {
          super.prepareFromRequest(request);
          getReportParametersMapFromServer(map ->
          {
             reportParameters.clear();

             LinkedHashSet<String> selectedRowsList = new LinkedHashSet<String>();

             request.getParameterNames().forEach(name ->
             {
                // Gets the default server value and overwrites this value with the client value
                Object defaultValue = map != null ? map.get(name) : "";

                String value = request.getParameter(name,
                                                    defaultValue != null ? defaultValue.toString() : "");

                boolean addToReportParameters = false;

                if (ReportParameters.TITLE.getParameter().equals(name))
                {
                   getView().setPreviewTitle("Print preview:" + value);
                   addToReportParameters = true;
                }
                else if (ReportParameters.REPORT_ID.getParameter().equals(name))
                {
                   setReport(value);
                   addToReportParameters = true;
                }
                else if (ReportParameters.FILTER.getParameter().equals(name))
                {
                   setFilter(value);
                   addToReportParameters = true;
                }
                else if (ReportParameters.PAPER_FORMAT.getParameter().equals(name))
                {
                   getView().setPaperFormat(value);
                   addToReportParameters = true;
                }
                else if (ReportParameters.PAPER_ORIENT.getParameter().equals(name))
                {
                   getView().setPaperOrientation(value);
                   addToReportParameters = true;
                }
                else if (ReportParameters.DETAILS.getParameter().equals(name))
                {
                   getView().checkDisplayDetails(!value.isEmpty());
                   addToReportParameters = true;
                }
                else if (NameTokens.getTokenParameter().equals(name))
                {
                   pathToParentView = value;
                }
                else if (name.startsWith(ReportParameters.SELECTION.getParameter()))
                {
                   if (!value.isEmpty())
                   {
                      selectedRowsList.add(value);
                   }
                }
                else if (name.startsWith(ReportParameters.EXTENSION.getParameter())
                         || ReportParameters.REPORT_TYPE.getParameter().equals(name))
                {
                   addToReportParameters = true;
                }

                if (addToReportParameters)
                {
                   setReportParameter(name, value, false);
                }
             });

             getView().onReportReady();
             setSelectedRows(selectedRowsList.toArray(new String[selectedRowsList.size()]));
          });
       }

       /**
        * Retrieves the report parameters map from the server and delivers it to the given consumer.
        *
        * @param    overwriteReportSettings
        *           The given consumer
        */
       private void getReportParametersMapFromServer(Consumer<Map<String,Object>> overwriteReportSettings)
       {
          this.adminService.getReportParametersMap(new AsyncCallback<Map<String,Object>>()
          {
             @Override
             public void onSuccess(Map<String, Object> result)
             {
                overwriteReportSettings.accept(result);
             }

             @Override
             public void onFailure(Throwable caught)
             {
                logger.log(Level.INFO, "Failed to get the report parameters map from the server.");
                overwriteReportSettings.accept(Collections.<String, Object>emptyMap());
             }
          });
       }

       /**
        * Lifecycle method called whenever this presenter is about to be hidden.
        */
       @Override
       protected void onHide()
       {
          super.onHide();
          getView().onHide();
       }

       /**
        * Asks its controller to update this preview according to the provided range of pages.
        *
        * @param    range
        *           The given range of pages.
        */
       @Override
       public void updatePreview(Range range)
       {
          clearRequestParameter(ReportParameters.ACTION.getParameter());

          AsyncAction<Range, ReportPreview> action = new AsyncAction<Range, ReportPreview>()
          {

             @Override
             public void onFailure(Throwable caught)
             {
                logger.log(Level.SEVERE, "Failed to call getPreviewImages", caught);
             }

             @Override
             public void accept(Range t)
             {
                ReportRequest req = new ReportRequest(
                         getReport(),
                         getSelectedRows(),
                         getCurrentFilter(),
                         getReportParameters());
                adminService.getPreviewImages(req, t, delegate);
             }

          };

          action.then(getView());
          action.accept(range);
       }

       /**
        * Gets the selected rows data.
        *
        * @return   The array of account names
        */
       private String[] getSelectedRows()
       {
          return selectedRows;
       }

       /**
        * Gets the requested report parameters map.
        *
        * @return   The requested report parameters map
        */
       private HashMap<String, String> getReportParameters()
       {
          return reportParameters;
       }

       /**
        * Sets the new value for the known report parameter.
        *
        * @param    name
        *           The known report parameter name
        * @param    value
        *           The new value
        * @param    updateUrl
        *           The true value forces to update the current URL and the Browser history, and
        *           otherwise the false value doesn't affect them.
        */
       private void setReportParameter(String name, String value, boolean updateUrl)
       {
          this.reportParameters.put(name, value);
          if (updateUrl)
          {
             updateBrowserHistory(name, value);
          }
       }

       /**
        * Gets the report id.
        *
        * @return   The report id
        */
       private String getReport()
       {
          return report;
       }

       /**
        * Sets the report id.
        *
        * @param    reportId
        *           The report id
        */
       private void setReport(String reportId)
       {
          this.report = reportId;
       }

       /**
        * Sets the selected rows report parameter
        *
        * @param    selectedRows
        *           The selected rows
        */
       private void setSelectedRows(String[] selectedRows)
       {
          this.selectedRows = selectedRows;
       }

       /**
        * Asks its controller to print the current report to the client side.
        */
       @Override
       public void printReport()
       {
          setReportParameter(ReportParameters.ACTION.getParameter(), "true", true);
          String url = GWT.getModuleBaseURL() + "ReportService?" + getQueryString();
          Window.open( url, "_blank", "status=0,toolbar=0,menubar=0,location=0");
       }

       /**
        * Sets the current search string used as a filter to display the target results.
        *
        * @param    filter
        *           The new search string used as a filter.
        */
       @Override
       public void setDataSelectionFilter(String filter)
       {
          setFilter(filter);
          updatePreview(getView().getCurrentRange());
       }

       /**
        * Asks its controller to close this print preview and opens its parent screen.
        */
       @Override
       public void cancel()
       {
          Map<String, String> parametersMap = getQueryParametersMap(
                   getPlaceManager().getCurrentPlaceRequest());

          backTo(NameTokens.getReportParentPlaceRequest(pathToParentView, parametersMap));
       }

       /**
        * Sets new page format setting for this preview and asks to update this preview accordingly.
        *
        * @param    format
        *           New paper format, the default one is A4
        * @param    orient
        *           New page orientation, the default one is a portrait.
        */
       @Override
       public void setNewPrintSettings(PaperFormat format, PaperOrientation orient)
       {
          setReportParameter(ReportParameters.PAPER_FORMAT.getParameter(), format.name(), true);
          setReportParameter(ReportParameters.PAPER_ORIENT.getParameter(), orient.name(), true);
          updatePreview(getView().getCurrentRange());
       }

       /**
        * Asks a controller to display all detailed report if it is available.
        *
        * @param    value
        *           True indicates to display all details data.
        */
       @Override
       public void displayAllDetails(Boolean value)
       {
          if (value != null && value.booleanValue())
          {
             setReportParameter(ReportParameters.DETAILS.getParameter(), "true", true);
          }
          else
          {
             this.reportParameters.remove(ReportParameters.DETAILS.getParameter());
             clearRequestParameter(ReportParameters.DETAILS.getParameter());
          }

          updatePreview(getView().getCurrentRange());
       }

       /**
        * Asks its controller to download the current report to the client side.
        */
       @Override
       public void downloadReport()
       {
          clearRequestParameter(ReportParameters.ACTION.getParameter());
          String url = GWT.getModuleBaseURL() + "ReportService?" + getQueryString();
          Window.open( url, "_blank", "status=0,toolbar=0,menubar=0,location=0");
       }
    }