/**
 * Copyright (C) 2004-2011 Jive Software. All rights reserved.
 *
 * 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 org.jivesoftware.sparkimpl.search.users;

import org.jivesoftware.resource.Res;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smackx.xdata.form.FillableForm;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.jivesoftware.smackx.search.ReportedData;
import org.jivesoftware.smackx.search.UserSearchManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.ui.DataFormUI;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.spark.util.log.Log;
import org.jxmpp.jid.DomainBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

public class SearchForm extends JPanel {
    private UserSearchResults searchResults;
    private DataFormUI questionForm;
    private UserSearchManager searchManager;
    private final DomainBareJid serviceName;
    private DataForm searchForm;

    // TODO: Constructor should use DomainBareJid type instead of String.
    public SearchForm(String serviceString) {
        this.serviceName = JidCreate.domainBareFromOrThrowUnchecked(serviceString);
        searchManager = UserSearchManager.getInstanceFor(SparkManager.getConnection());
        setLayout(new GridBagLayout());

        // Load searchForm
        try {
            searchForm = searchManager.getSearchForm(serviceName).getDataForm();
        }
        catch (XMPPException | SmackException | InterruptedException e) {
            Log.error("Unable to load search services.", e);
            JOptionPane.showMessageDialog(SparkManager.getMainWindow(), Res.getString("message.search.service.not.available"), Res.getString("title.notification"), JOptionPane.ERROR_MESSAGE);
            return;
        }

        questionForm = new DataFormUI(searchForm);
        questionForm.setBorder(BorderFactory.createTitledBorder(Res.getString("group.search.form")));

        add(questionForm, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));

        // Add User DataForm
        final JButton searchButton = new JButton();
        ResourceUtils.resButton(searchButton, Res.getString("button.search"));
        add(searchButton, new GridBagConstraints(0, 1, 3, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));

        searchButton.addActionListener( e -> performSearch() );

        KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
        String enterString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(enter);

        // Handle Left Arrow
        getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(enterString), "enter");

        getActionMap().put("enter", new AbstractAction("enter") {
	    @Override
		public void actionPerformed(ActionEvent evt) {
                performSearch();
            }
        });

        // Add searchResults
        searchResults = new UserSearchResults();
        searchResults.setBorder(BorderFactory.createTitledBorder(Res.getString("group.search.results")));
        add(searchResults, new GridBagConstraints(0, 2, 2, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
    }

    public DataFormUI getQuestionForm() {
        return questionForm;
    }

    public DataForm getSearchForm() {
        return searchForm;
    }

    /**
     * Starts a search based on the Answered form.
     */
    public void performSearch() {
        searchResults.clearTable();

        SwingWorker worker = new SwingWorker() {
            ReportedData data;

            @Override
			public Object construct() {
                try {
                    FillableForm filledForm = questionForm.getFilledForm();
                    data = searchManager.search(filledForm, serviceName);
                }
                catch (XMPPException | SmackException | InterruptedException e) {
                    Log.error("Unable to load search service.", e);
                }

                return data;
            }

            @Override
			public void finished() {
                if (data != null && !data.getRows().isEmpty() ) {
                    searchResults.showUsersFound(data);
                    searchResults.invalidate();
                    searchResults.validate();
                    searchResults.repaint();
                }
                else {
                    JOptionPane.showMessageDialog(searchResults, Res.getString("message.no.results.found"), Res.getString("title.notification"), JOptionPane.ERROR_MESSAGE);
                }
            }
        };
        worker.start();
    }
}
