<commit_before>/*
 * jPOS Project [http://jpos.org]
 * Copyright (C) 2000-2019 jPOS Software SRL
 *
 * 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 should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.jpos.qi;

import com.vaadin.data.*;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.ui.*;
import com.vaadin.ui.Grid;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
import com.vaadin.shared.ui.ContentMode;

import com.vaadin.event.ShortcutAction;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.shared.ui.MarginInfo;

import org.jdom2.Attribute;
import org.jdom2.Element;
import org.jpos.core.Configurable;
import org.jpos.core.Configuration;
import org.jpos.core.XmlConfigurable;
import org.jpos.ee.BLException;
import org.jpos.qi.util.FieldFactory;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

import static org.jpos.qi.util.QIUtils.getCaptionFromId;


public abstract class QIEntityView<T> extends VerticalLayout implements View, Configurable, XmlConfigurable {
    private QI app;
    private Class<T> clazz;
    private boolean generalView;
    private String name;
    private String title;
    private String generalRoute;
    private String[] visibleColumns;
    private String[] visibleFields;
    private String[] readOnlyFields;
    private Grid grid;
    private RevisionsPanel revisionsPanel;
    private QIHelper helper;
    private boolean showRevisionHistoryButton;
    private Button editBtn;
    private Button removeBtn;
    private Button saveBtn;
    private Button cancelBtn;
    private Binder<T> binder;
    private Label errorLabel;
    private boolean newView;
    private Configuration cfg;
    private ViewConfig viewConfig;
    private T bean;
    private FieldFactory fieldFactory;
    private List<Layout> fieldsLayouts;
    private Layout formLayout;

    public QIEntityView(Class<T> clazz, String name) {
        this(clazz);
        this.name = name;
        this.title = "<strong>" + app.getMessage(name) + "</strong>";
        generalRoute = "/" + name;
    }

    public QIEntityView (Class<T> clazz) {
        super();
        app = (QI) UI.getCurrent();
        this.clazz = clazz;
        setSizeFull();
        setMargin(new MarginInfo(false, false, false, false));
        setSpacing(false);
        showRevisionHistoryButton=true;
    }

    @Override
    public void enter (ViewChangeListener.ViewChangeEvent event) {
        helper = createHelper();
        helper.setConfiguration(cfg);
        if (event.getParameters() == null || event.getParameters().isEmpty()) {
            generalView = true;
            showGeneralView();
        } else {
            generalView = false;
            fieldsLayouts = new ArrayList<>();
            showSpecificView (event.getParameters());
        }
    }

    @Override
    public void attach() {
        super.attach();
    }

    public void showGeneralView () {
        try {
            Layout header = createHeader(title);
            addComponent(header);
            grid = createGrid();
            grid.setDataProvider(getHelper().getDataProvider());
            formatGrid();
            addComponent(grid);
            setExpandRatio(grid, 1);
        } catch (Exception e) {
            getApp().getLog().error(e);
            getApp().displayNotification(e.getMessage());
        }
    }

    public void showSpecificView (final String parameter) {
        Object o = null;
        String[] params = parameter.split("[/?]");
        if (params.length > 0) {
            if ("new".equals(params[0])) {
                if (canAdd())
                    o =  createNewEntity();
                newView = true;
            } else {
                o = getEntityByParam(params[0]);
            }
            if (parameter.contains("?")) {
                //Has query params.
                String[] queryParams= params[params.length-1].split(",");
                for (String queryParam : queryParams) {
                    String[] keyValue = queryParam.split("=");
                    if (keyValue.length > 0  && "back".equals(keyValue[0])) {
                        ((QINavigator)app.getNavigator()).setPreviousView("/" + keyValue[1].replace(".", "/"));
                    }
                }
            }
        }
        if (o == null) {
            getApp().getNavigator().navigateTo("");
            getApp().displayNotification(getApp().getMessage(
                    "errorMessage.notExists", "<strong>" + getEntityName().toUpperCase() + "</strong>: " + params[0]));
            return;
        }
        Layout header = createHeader(title + ": " + getHeaderSpecificTitle(o));
        addComponent(header);
        Panel panel = new Panel();
        panel.setSizeFull();
        addComponent(panel);
        formLayout = createForm(o, params, "new".equals(params[0]));
        panel.setContent(formLayout);
        setExpandRatio(panel, 1);
        if (!"new".equals(params[0]) && isShowRevisionHistoryButton()) {
            final Button showRevision = new Button(getApp().getMessage("showRevisionHistory"));
            showRevision.setStyleName(ValoTheme.BUTTON_LINK);
            showRevision.addClickListener(event -> {
                if (getApp().getMessage("showRevisionHistory").equals(event.getButton().getCaption())) {
                    event.getButton().setCaption(getApp().getMessage("hideRevisionHistory"));
                    loadRevisionHistory(formLayout, getEntityName().toLowerCase() + "." + params[0]);
                } else {
                    event.getButton().setCaption(getApp().getMessage("showRevisionHistory"));
                    formLayout.removeComponent(revisionsPanel);
                }
            });
            formLayout.addComponent(showRevision);
        }
    }

    protected HorizontalLayout createHeader (String title) {
        HorizontalLayout header = new HorizontalLayout();
        header.setWidth("100%");
        header.setSpacing(false);
        header.setMargin(new MarginInfo(false, true, false, true));
        Label lbl = new Label(title);
        lbl.addStyleName("h2");
        lbl.setSizeUndefined();
        lbl.setContentMode(ContentMode.HTML);
        header.addComponent(lbl);
        header.setComponentAlignment(lbl, Alignment.MIDDLE_LEFT);
        if (isGeneralView() && canAdd()) {
            Button addBtn = new Button(getApp().getMessage("add"));
            addBtn.addStyleName("borderless-colored");
            addBtn.setIcon(VaadinIcons.PLUS);
            addBtn.addClickListener(event -> navigateToNewRoute());
            header.addComponent(addBtn);
            header.setComponentAlignment(addBtn, Alignment.BOTTOM_RIGHT);
        }
        return header;
    }

    protected void navigateToNewRoute() {
        getApp().getNavigator().navigateTo(generalRoute + "/new");
    }

    public Grid createGrid() {
        Grid g = new Grid();
        g.setSizeFull();
        g.setSelectionMode(Grid.SelectionMode.SINGLE);
        g.setColumnReorderingAllowed(true);
        g.addItemClickListener(this::navigateToSpecificView);
        return g;
    }

    protected void navigateToSpecificView(Grid.ItemClick event) {
        String url = generalRoute + "/" + getHelper().getItemId(event.getItem());
        getApp().getNavigator().navigateTo(url);
    }


    public void formatGrid() {
        setGridGetters();

        //Delete not visible columns
        //Use columnId as caption
        //Set sorting for every column.
        DecimalFormat nf = new DecimalFormat();
        nf.setGroupingUsed(false);

        for (Grid.Column c : (Iterable<Grid.Column>) grid.getColumns()) {
            String columnId = c.getId();
            if (!Arrays.asList(getVisibleColumns()).contains(columnId)) {
                grid.removeColumn(columnId);
            } else {
                c.setCaption(getCaptionFromId("column." + columnId))
                        .setSortProperty(columnId)
                        .setSortable(true)
                        .setHidable(true);

                ViewConfig.FieldConfig config = viewConfig.getFields().get(c.getId());
                if (config != null) {
                    if (config.getExpandRatio() != -1)
                        c.setExpandRatio(config.getExpandRatio());
                }
                c.setStyleGenerator(obj -> {
                    Object value = c.getValueProvider().apply(obj);
                    if (value instanceof BigDecimal && !c.getId().equals("id")) {
                        return "align-right";
                    }
                    return null;
                });
            }

        }
        //fix for when a manual resize is done, the last column takes the empty space.
        grid.addColumnResizeListener(event -> {
            int lastColumnIndex = grid.getColumns().size()-1;
            ((Grid.Column)grid.getColumns().get(lastColumnIndex)).setWidth(1500);
        });
        grid.setSizeFull();
    }


    public abstract void setGridGetters();

    public Layout createForm (final Object entity, String[] params, boolean isNew) {
        VerticalLayout profileLayout = new VerticalLayout();
        profileLayout.setMargin(true);
        profileLayout.setSpacing(true);

        //Add Back Button
        if ((params.length <= 1 || !"profile".equals(params[1])) && ((QINavigator)app.getNavigator()).hasHistory()) {
            Button back = new Button(getApp().getMessage("back"));
            back.setStyleName(ValoTheme.BUTTON_LINK);
            back.setIcon(VaadinIcons.ARROW_LEFT);
            back.addClickListener(event -> ((QINavigator)app.getNavigator()).navigateBack());
            profileLayout.addComponent(back);
            profileLayout.setComponentAlignment(back, Alignment.MIDDLE_LEFT);<commit_msg>Set grid column order as specified in 00_qi<commit_after>/*
 * jPOS Project [http://jpos.org]
 * Copyright (C) 2000-2019 jPOS Software SRL
 *
 * 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 should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.jpos.qi;

import com.vaadin.data.*;
import com.vaadin.icons.VaadinIcons;
import com.vaadin.ui.*;
import com.vaadin.ui.Grid;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.ValoTheme;
import com.vaadin.shared.ui.ContentMode;

import com.vaadin.event.ShortcutAction;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.shared.ui.MarginInfo;

import org.jdom2.Attribute;
import org.jdom2.Element;
import org.jpos.core.Configurable;
import org.jpos.core.Configuration;
import org.jpos.core.XmlConfigurable;
import org.jpos.ee.BLException;
import org.jpos.qi.util.FieldFactory;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

import static org.jpos.qi.util.QIUtils.getCaptionFromId;


public abstract class QIEntityView<T> extends VerticalLayout implements View, Configurable, XmlConfigurable {
    private QI app;
    private Class<T> clazz;
    private boolean generalView;
    private String name;
    private String title;
    private String generalRoute;
    private String[] visibleColumns;
    private String[] visibleFields;
    private String[] readOnlyFields;
    private Grid grid;
    private RevisionsPanel revisionsPanel;
    private QIHelper helper;
    private boolean showRevisionHistoryButton;
    private Button editBtn;
    private Button removeBtn;
    private Button saveBtn;
    private Button cancelBtn;
    private Binder<T> binder;
    private Label errorLabel;
    private boolean newView;
    private Configuration cfg;
    private ViewConfig viewConfig;
    private T bean;
    private FieldFactory fieldFactory;
    private List<Layout> fieldsLayouts;
    private Layout formLayout;

    public QIEntityView(Class<T> clazz, String name) {
        this(clazz);
        this.name = name;
        this.title = "<strong>" + app.getMessage(name) + "</strong>";
        generalRoute = "/" + name;
    }

    public QIEntityView (Class<T> clazz) {
        super();
        app = (QI) UI.getCurrent();
        this.clazz = clazz;
        setSizeFull();
        setMargin(new MarginInfo(false, false, false, false));
        setSpacing(false);
        showRevisionHistoryButton=true;
    }

    @Override
    public void enter (ViewChangeListener.ViewChangeEvent event) {
        helper = createHelper();
        helper.setConfiguration(cfg);
        if (event.getParameters() == null || event.getParameters().isEmpty()) {
            generalView = true;
            showGeneralView();
        } else {
            generalView = false;
            fieldsLayouts = new ArrayList<>();
            showSpecificView (event.getParameters());
        }
    }

    @Override
    public void attach() {
        super.attach();
    }

    public void showGeneralView () {
        try {
            Layout header = createHeader(title);
            addComponent(header);
            grid = createGrid();
            grid.setDataProvider(getHelper().getDataProvider());
            formatGrid();
            addComponent(grid);
            setExpandRatio(grid, 1);
        } catch (Exception e) {
            getApp().getLog().error(e);
            getApp().displayNotification(e.getMessage());
        }
    }

    public void showSpecificView (final String parameter) {
        Object o = null;
        String[] params = parameter.split("[/?]");
        if (params.length > 0) {
            if ("new".equals(params[0])) {
                if (canAdd())
                    o =  createNewEntity();
                newView = true;
            } else {
                o = getEntityByParam(params[0]);
            }
            if (parameter.contains("?")) {
                //Has query params.
                String[] queryParams= params[params.length-1].split(",");
                for (String queryParam : queryParams) {
                    String[] keyValue = queryParam.split("=");
                    if (keyValue.length > 0  && "back".equals(keyValue[0])) {
                        ((QINavigator)app.getNavigator()).setPreviousView("/" + keyValue[1].replace(".", "/"));
                    }
                }
            }
        }
        if (o == null) {
            getApp().getNavigator().navigateTo("");
            getApp().displayNotification(getApp().getMessage(
                    "errorMessage.notExists", "<strong>" + getEntityName().toUpperCase() + "</strong>: " + params[0]));
            return;
        }
        Layout header = createHeader(title + ": " + getHeaderSpecificTitle(o));
        addComponent(header);
        Panel panel = new Panel();
        panel.setSizeFull();
        addComponent(panel);
        formLayout = createForm(o, params, "new".equals(params[0]));
        panel.setContent(formLayout);
        setExpandRatio(panel, 1);
        if (!"new".equals(params[0]) && isShowRevisionHistoryButton()) {
            final Button showRevision = new Button(getApp().getMessage("showRevisionHistory"));
            showRevision.setStyleName(ValoTheme.BUTTON_LINK);
            showRevision.addClickListener(event -> {
                if (getApp().getMessage("showRevisionHistory").equals(event.getButton().getCaption())) {
                    event.getButton().setCaption(getApp().getMessage("hideRevisionHistory"));
                    loadRevisionHistory(formLayout, getEntityName().toLowerCase() + "." + params[0]);
                } else {
                    event.getButton().setCaption(getApp().getMessage("showRevisionHistory"));
                    formLayout.removeComponent(revisionsPanel);
                }
            });
            formLayout.addComponent(showRevision);
        }
    }

    protected HorizontalLayout createHeader (String title) {
        HorizontalLayout header = new HorizontalLayout();
        header.setWidth("100%");
        header.setSpacing(false);
        header.setMargin(new MarginInfo(false, true, false, true));
        Label lbl = new Label(title);
        lbl.addStyleName("h2");
        lbl.setSizeUndefined();
        lbl.setContentMode(ContentMode.HTML);
        header.addComponent(lbl);
        header.setComponentAlignment(lbl, Alignment.MIDDLE_LEFT);
        if (isGeneralView() && canAdd()) {
            Button addBtn = new Button(getApp().getMessage("add"));
            addBtn.addStyleName("borderless-colored");
            addBtn.setIcon(VaadinIcons.PLUS);
            addBtn.addClickListener(event -> navigateToNewRoute());
            header.addComponent(addBtn);
            header.setComponentAlignment(addBtn, Alignment.BOTTOM_RIGHT);
        }
        return header;
    }

    protected void navigateToNewRoute() {
        getApp().getNavigator().navigateTo(generalRoute + "/new");
    }

    public Grid createGrid() {
        Grid g = new Grid();
        g.setSizeFull();
        g.setSelectionMode(Grid.SelectionMode.SINGLE);
        g.setColumnReorderingAllowed(true);
        g.addItemClickListener(this::navigateToSpecificView);
        return g;
    }

    protected void navigateToSpecificView(Grid.ItemClick event) {
        String url = generalRoute + "/" + getHelper().getItemId(event.getItem());
        getApp().getNavigator().navigateTo(url);
    }


    public void formatGrid() {
        setGridGetters();

        //Delete not visible columns
        //Use columnId as caption
        //Set sorting for every column.
        DecimalFormat nf = new DecimalFormat();
        nf.setGroupingUsed(false);

        for (Grid.Column c : (Iterable<Grid.Column>) grid.getColumns()) {
            String columnId = c.getId();
            if (!Arrays.asList(getVisibleColumns()).contains(columnId)) {
                grid.removeColumn(columnId);
            } else {
                c.setCaption(getCaptionFromId("column." + columnId))
                        .setSortProperty(columnId)
                        .setSortable(true)
                        .setHidable(true);

                ViewConfig.FieldConfig config = viewConfig.getFields().get(c.getId());
                if (config != null) {
                    if (config.getExpandRatio() != -1)
                        c.setExpandRatio(config.getExpandRatio());
                }
                c.setStyleGenerator(obj -> {
                    Object value = c.getValueProvider().apply(obj);
                    if (value instanceof BigDecimal && !c.getId().equals("id")) {
                        return "align-right";
                    }
                    return null;
                });
            }

        }
        grid.setColumnOrder(getVisibleColumns());
        //fix for when a manual resize is done, the last column takes the empty space.
        grid.addColumnResizeListener(event -> {
            int lastColumnIndex = grid.getColumns().size()-1;
            ((Grid.Column)grid.getColumns().get(lastColumnIndex)).setWidth(1500);
        });
        grid.setSizeFull();
    }


    public abstract void setGridGetters();

    public Layout createForm (final Object entity, String[] params, boolean isNew) {
        VerticalLayout profileLayout = new VerticalLayout();
        profileLayout.setMargin(true);
        profileLayout.setSpacing(true);

        //Add Back Button
        if ((params.length <= 1 || !"profile".equals(params[1])) && ((QINavigator)app.getNavigator()).hasHistory()) {
            Button back = new Button(getApp().getMessage("back"));
            back.setStyleName(ValoTheme.BUTTON_LINK);
            back.setIcon(VaadinIcons.ARROW_LEFT);
            back.addClickListener(event -> ((QINavigator)app.getNavigator()).navigateBack());
            profileLayout.addComponent(back);
            profileLayout.setComponentAlignment(back, Alignment.MIDDLE_LEFT);
{'fraction_non_alphanumeric': 0.1155855256909488, 'fraction_numerical': 0.0035141039035046064, 'mean_word_length': 2.3437599237853286, 'pattern_counts': {'":': 2, '<': 31, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4439370', 'n_tokens_mistral': 5737, 'n_tokens_neox': 5515, 'n_words': 1245}