<commit_before>/*
 * Copyright 2015 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package annis.gui;

import annis.CommonHelper;
import annis.QueryGenerator;
import annis.VersionInfo;
import annis.gui.controlpanel.ControlPanel;
import annis.gui.docbrowser.DocBrowserController;
import annis.gui.frequency.FrequencyQueryPanel;
import annis.gui.resultview.ResultViewPanel;
import annis.libgui.Background;
import annis.libgui.Helper;
import annis.libgui.InstanceConfig;
import annis.libgui.media.MediaController;
import annis.libgui.media.MediaControllerImpl;
import annis.libgui.media.MimeTypeErrorListener;
import annis.libgui.media.PDFController;
import annis.libgui.media.PDFControllerImpl;
import annis.model.DisplayedResultQuery;
import annis.model.PagedResultQuery;
import annis.model.Query;
import annis.service.objects.AnnisCorpus;
import annis.service.objects.QueryLanguage;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.vaadin.event.ShortcutListener;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.Page;
import com.vaadin.server.RequestHandler;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.WebBrowser;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Notification;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

/**
 * The view which shows the search interface.
 *
 * @author <NAME> {@literal <<EMAIL>>}
 */
public class SearchView extends GridLayout
        implements View, MimeTypeErrorListener, Page.UriFragmentChangedListener,
        TabSheet.CloseHandler, LoginListener, Sidebar, TabSheet.SelectedTabChangeListener {

    private static class AnnisCorpusListType extends GenericType<List<AnnisCorpus>> {

        public AnnisCorpusListType() {}
    }

    private class CitationRequestHandler implements RequestHandler {

        /**
         * 
         */
        private static final long serialVersionUID = -5700172209282345278L;

        @Override
        public boolean handleRequest(VaadinSession session, VaadinRequest request,
                VaadinResponse response) throws IOException {
            checkCitation();
            return false;
        }
    }

    private class VersionChecker implements Runnable {

        @Override
        public void run() {
            try {
                WebResource resRelease =
                        Helper.getAnnisWebResource(ui).path("version").path("release");
                final String releaseService = resRelease.get(String.class);
                final String releaseGUI = VersionInfo.getReleaseName();

                WebResource resRevision =
                        Helper.getAnnisWebResource(ui).path("version").path("revision");
                final String revisionService = resRevision.get(String.class);
                final String revisionGUI = VersionInfo.getBuildRevision();

                // GUI update
                ui.access(() -> {
                    // check if the release version differs and show a big warning
                    if (!releaseGUI.equals(releaseService)) {
                        Notification.show("Different service version",
                                "The service uses version " + releaseService
                                        + " but the user interface is using version  " + releaseGUI
                                        + ". This can produce unwanted errors.",
                                Notification.Type.WARNING_MESSAGE);
                    } else {
                        // show a smaller warning if the revisions are not the same

                        if (!revisionService.equals(revisionGUI)) {
                            // shorten the strings
                            String commonPrefix =
                                    Strings.commonPrefix(revisionService, revisionGUI);
                            int outputLength = Math.max(6, commonPrefix.length() + 2);
                            String revisionServiceShort = revisionService.substring(0,
                                    Math.min(revisionService.length() - 1, outputLength));
                            String revisionGUIShort = revisionGUI.substring(0,
                                    Math.min(revisionGUI.length() - 1, outputLength));

                            Notification n = new Notification("Different service revision",
                                    "The service uses revision <code title=\"" + revisionGUI + "\">"
                                            + revisionServiceShort
                                            + "</code> but the user interface is using revision  <code title=\""
                                            + revisionGUI + "\">" + revisionGUIShort + "</code>.",
                                    Notification.Type.TRAY_NOTIFICATION);
                            n.setHtmlContentAllowed(true);
                            n.setDelayMsec(3000);
                            n.show(Page.getCurrent());
                        }
                    }
                });

            } catch (UniformInterfaceException ex) {
                log.warn("Could not get the version of the service", ex);
            } catch (ClientHandlerException ex) {
                log.warn("Could not get the version of the service because service is not running",
                        ex);
            }

        }

    }

    /**
     * 
     */
    private static final long serialVersionUID = 4726183716126582129L;

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(SearchView.class);

    public static final String NAME = "";

    private final static Escaper urlPathEscape = UrlEscapers.urlPathSegmentEscaper();

    public final static int CONTROL_PANEL_WIDTH = 360;

    // regular expression matching, CLEFT and CRIGHT are optional
    // indexes: AQL=1, CIDS=2, CLEFT=4, CRIGHT=6
    private final Pattern citationPattern = Pattern.compile(
            "AQL\\((.*)\\),CIDS\\(([^)]*)\\)(,CLEFT\\(([^)]*)\\),)?(CRIGHT\\(([^)]*)\\))?",
            Pattern.MULTILINE | Pattern.DOTALL);

    private ControlPanel controlPanel;

    private TabSheet mainTab;

    private String lastEvaluatedFragment;

    private DocBrowserController docBrowserController;

    private Set<Component> selectedTabHistory;

    private final AnnisUI ui;

    private MainToolbar toolbar;

    public SearchView(AnnisUI ui) {
        super(2, 2);
        this.ui = ui;
        this.selectedTabHistory = new LinkedHashSet<>();

        // init a doc browser controller
        this.docBrowserController = new DocBrowserController(ui);

        setSizeFull();
        setMargin(false);
        setRowExpandRatio(1, 1.0f);
        setColumnExpandRatio(1, 1.0f);

        final HelpPanel help = new HelpPanel(ui);

        mainTab = new TabSheet();
        mainTab.setSizeFull();
        mainTab.setCloseHandler(SearchView.this);
        mainTab.addStyleName(ValoTheme.TABSHEET_FRAMED);
        mainTab.addSelectedTabChangeListener(SearchView.this);

        TabSheet.Tab helpTab = mainTab.addTab(help, "Help/Examples");
        helpTab.setIcon(FontAwesome.QUESTION_CIRCLE);
        helpTab.setClosable(false);

        controlPanel = new ControlPanel(ui.getInstanceConfig(), help.getExamples(), ui);

        controlPanel.setWidth(CONTROL_PANEL_WIDTH, Layout.Unit.PIXELS);
        controlPanel.setHeight(100f, Layout.Unit.PERCENTAGE);

        ui.addAction(new ShortcutListener("Tutor^eial") {
            /**
             * 
             */
            private static final long serialVersionUID = 4230090114473234656L;

            @Override
            public void handleAction(Object sender, Object target) {
                mainTab.setSelectedTab(help);
            }
        });

        addComponent(controlPanel, 0, 1);
        addComponent(mainTab, 1, 1);
    }

    public void checkCitation() {
        if (VaadinSession.getCurrent() == null || VaadinSession.getCurrent().getSession() == null) {
            return;
        }
        Object origURLRaw = VaadinSession.getCurrent().getSession().getAttribute("citation");
        if (origURLRaw == null || !(origURLRaw instanceof String)) {
            return;
        }
        String origURL = (String) origURLRaw;
        String parameters = origURL.replaceAll(".*?/Cite(/)?", "");
        if (!"".equals(parameters) && !origURL.equals(parameters)) {
            try {
                String decoded = URLDecoder.decode(parameters, "UTF-8");
                evaluateCitation(decoded);
            } catch (UnsupportedEncodingException ex) {
                log.error(null, ex);
            }
        }

    }

    public void closeTab(Component c) {
        selectedTabHistory.remove(c);
        mainTab.removeComponent(c);
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        if (event.getOldView() == event.getNewView()) {
            return;
        }

        InstanceConfig config = ui.getInstanceConfig();

        Page.getCurrent().setTitle(config.getInstanceDisplayName() + " (ANNIS Corpus Search)");

        Page.getCurrent().addUriFragmentChangedListener(this);

        getSession().addRequestHandler(new CitationRequestHandler());

        getSession().setAttribute(MediaController.class, new MediaControllerImpl());

        getSession().setAttribute(PDFController.class, new PDFControllerImpl());

        // the following shoul
        checkCitation();
        lastEvaluatedFragment = "";
        Background.run(new VersionChecker());
        evaluateFragment(Page.getCurrent().getUriFragment());

        if (config.isLoginOnStart() && toolbar != null && Helper.getUser(ui) == null) {
            toolbar.showLoginWindow(false);
        }

    }

    public void evaluateCitation(String relativeUri) {
        Matcher m = citationPattern.matcher(relativeUri);
        if (m.matches()) {
            // AQL
            String aql = "";
            if (m.group(1) != null) {
                aql = m.group(1);
            }

            // CIDS
            Set<String> selectedCorpora = new HashSet<>();
            if (m.group(2) != null) {
                String[] cids = m.group(2).split(",");<commit_msg>Don't check the version of the service, this is not implemented in the new REST API<commit_after>/*
 * Copyright 2015 Corpuslinguistic working group Humboldt University Berlin.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package annis.gui;

import annis.CommonHelper;
import annis.QueryGenerator;
import annis.gui.controlpanel.ControlPanel;
import annis.gui.docbrowser.DocBrowserController;
import annis.gui.frequency.FrequencyQueryPanel;
import annis.gui.resultview.ResultViewPanel;
import annis.libgui.Helper;
import annis.libgui.InstanceConfig;
import annis.libgui.media.MediaController;
import annis.libgui.media.MediaControllerImpl;
import annis.libgui.media.MimeTypeErrorListener;
import annis.libgui.media.PDFController;
import annis.libgui.media.PDFControllerImpl;
import annis.model.DisplayedResultQuery;
import annis.model.PagedResultQuery;
import annis.model.Query;
import annis.service.objects.AnnisCorpus;
import annis.service.objects.QueryLanguage;
import com.google.common.base.Splitter;
import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
import com.vaadin.event.ShortcutListener;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.Page;
import com.vaadin.server.RequestHandler;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinResponse;
import com.vaadin.server.VaadinSession;
import com.vaadin.server.WebBrowser;
import com.vaadin.ui.Component;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Notification;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
import com.vaadin.ui.themes.ValoTheme;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

/**
 * The view which shows the search interface.
 *
 * @author <NAME> {@literal <<EMAIL>>}
 */
public class SearchView extends GridLayout
        implements View, MimeTypeErrorListener, Page.UriFragmentChangedListener,
        TabSheet.CloseHandler, LoginListener, Sidebar, TabSheet.SelectedTabChangeListener {

    private static class AnnisCorpusListType extends GenericType<List<AnnisCorpus>> {

        public AnnisCorpusListType() {}
    }

    private class CitationRequestHandler implements RequestHandler {

        /**
         * 
         */
        private static final long serialVersionUID = -5700172209282345278L;

        @Override
        public boolean handleRequest(VaadinSession session, VaadinRequest request,
                VaadinResponse response) throws IOException {
            checkCitation();
            return false;
        }
    }

    /**
     * 
     */
    private static final long serialVersionUID = 4726183716126582129L;

    private static final org.slf4j.Logger log = LoggerFactory.getLogger(SearchView.class);

    public static final String NAME = "";

    private final static Escaper urlPathEscape = UrlEscapers.urlPathSegmentEscaper();

    public final static int CONTROL_PANEL_WIDTH = 360;

    // regular expression matching, CLEFT and CRIGHT are optional
    // indexes: AQL=1, CIDS=2, CLEFT=4, CRIGHT=6
    private final Pattern citationPattern = Pattern.compile(
            "AQL\\((.*)\\),CIDS\\(([^)]*)\\)(,CLEFT\\(([^)]*)\\),)?(CRIGHT\\(([^)]*)\\))?",
            Pattern.MULTILINE | Pattern.DOTALL);

    private ControlPanel controlPanel;

    private TabSheet mainTab;

    private String lastEvaluatedFragment;

    private DocBrowserController docBrowserController;

    private Set<Component> selectedTabHistory;

    private final AnnisUI ui;

    private MainToolbar toolbar;

    public SearchView(AnnisUI ui) {
        super(2, 2);
        this.ui = ui;
        this.selectedTabHistory = new LinkedHashSet<>();

        // init a doc browser controller
        this.docBrowserController = new DocBrowserController(ui);

        setSizeFull();
        setMargin(false);
        setRowExpandRatio(1, 1.0f);
        setColumnExpandRatio(1, 1.0f);

        final HelpPanel help = new HelpPanel(ui);

        mainTab = new TabSheet();
        mainTab.setSizeFull();
        mainTab.setCloseHandler(SearchView.this);
        mainTab.addStyleName(ValoTheme.TABSHEET_FRAMED);
        mainTab.addSelectedTabChangeListener(SearchView.this);

        TabSheet.Tab helpTab = mainTab.addTab(help, "Help/Examples");
        helpTab.setIcon(FontAwesome.QUESTION_CIRCLE);
        helpTab.setClosable(false);

        controlPanel = new ControlPanel(ui.getInstanceConfig(), help.getExamples(), ui);

        controlPanel.setWidth(CONTROL_PANEL_WIDTH, Layout.Unit.PIXELS);
        controlPanel.setHeight(100f, Layout.Unit.PERCENTAGE);

        ui.addAction(new ShortcutListener("Tutor^eial") {
            /**
             * 
             */
            private static final long serialVersionUID = 4230090114473234656L;

            @Override
            public void handleAction(Object sender, Object target) {
                mainTab.setSelectedTab(help);
            }
        });

        addComponent(controlPanel, 0, 1);
        addComponent(mainTab, 1, 1);
    }

    public void checkCitation() {
        if (VaadinSession.getCurrent() == null || VaadinSession.getCurrent().getSession() == null) {
            return;
        }
        Object origURLRaw = VaadinSession.getCurrent().getSession().getAttribute("citation");
        if (origURLRaw == null || !(origURLRaw instanceof String)) {
            return;
        }
        String origURL = (String) origURLRaw;
        String parameters = origURL.replaceAll(".*?/Cite(/)?", "");
        if (!"".equals(parameters) && !origURL.equals(parameters)) {
            try {
                String decoded = URLDecoder.decode(parameters, "UTF-8");
                evaluateCitation(decoded);
            } catch (UnsupportedEncodingException ex) {
                log.error(null, ex);
            }
        }

    }

    public void closeTab(Component c) {
        selectedTabHistory.remove(c);
        mainTab.removeComponent(c);
    }

    @Override
    public void enter(ViewChangeListener.ViewChangeEvent event) {
        if (event.getOldView() == event.getNewView()) {
            return;
        }

        InstanceConfig config = ui.getInstanceConfig();

        Page.getCurrent().setTitle(config.getInstanceDisplayName() + " (ANNIS Corpus Search)");

        Page.getCurrent().addUriFragmentChangedListener(this);

        getSession().addRequestHandler(new CitationRequestHandler());

        getSession().setAttribute(MediaController.class, new MediaControllerImpl());

        getSession().setAttribute(PDFController.class, new PDFControllerImpl());

        checkCitation();
        lastEvaluatedFragment = "";
        evaluateFragment(Page.getCurrent().getUriFragment());

        if (config.isLoginOnStart() && toolbar != null && Helper.getUser(ui) == null) {
            toolbar.showLoginWindow(false);
        }

    }

    public void evaluateCitation(String relativeUri) {
        Matcher m = citationPattern.matcher(relativeUri);
        if (m.matches()) {
            // AQL
            String aql = "";
            if (m.group(1) != null) {
                aql = m.group(1);
            }

            // CIDS
            Set<String> selectedCorpora = new HashSet<>();
            if (m.group(2) != null) {
                String[] cids = m.group(2).split(",");
{'fraction_non_alphanumeric': 0.10194969489507368, 'fraction_numerical': 0.009922111425311306, 'mean_word_length': 2.5977155095484563, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7551362', 'n_tokens_mistral': 5673, 'n_tokens_neox': 5306, 'n_words': 1221}