/******************************************************************************
* Copyright 2013-2016 LASIGE                                                  *
*                                                                             *
* 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.                                              *
*                                                                             *
*******************************************************************************
* Alignment search dialog box for the GUI.                                    *
*                                                                             *
* @author Daniel Faria, Catarina Martins                                      *
******************************************************************************/
package aml.ui;

import java.awt.CardLayout;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JDialog;
import javax.swing.KeyStroke;
import javax.swing.border.EmptyBorder;

import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;

import aml.AML;
import aml.match.Alignment;
import aml.match.Mapping;
import aml.util.MapSorter;

public class SearchAlignment extends JDialog implements ActionListener
{
	
//Attributes
	
	private static final long serialVersionUID = -3901206021275961468L;
	private AML aml;
	private JPanel dialogPanel, searchPanel, resultsPanel;
	private CardLayout cl;
	private JButton cancel, find, back, select, quit;
	private JTextArea searchField;
	private JComboBox<String> mappingSelector;
	private ArrayList<String> mappings;
	private String[] results;
	private Font boldFont;
	
//Constructor
	
	public SearchAlignment()
	{
		super();
		
		this.setTitle("Search Alignment");
		this.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
		this.setPreferredSize(new Dimension(700,140));
		
		aml = AML.getInstance();
		
		//The containing panel
        dialogPanel = new JPanel();
        cl = new CardLayout();
        dialogPanel.setLayout(cl);
		
        //The search panel
		JLabel desc = new JLabel("Enter Search Term: (min 3 characters)");
		Font font = desc.getFont();
		boldFont = new Font(font.getFontName(), Font.BOLD, font.getSize());
		desc.setFont(boldFont);
		JPanel labelPanel = new JPanel();
		labelPanel.add(desc);
		Alignment a = AML.getInstance().getAlignment();
		int total = a.size();
		mappings = new ArrayList<String>(total);
		for(int i = 0; i < total; i++)
		{
			Mapping m = a.get(i);
			String map = aml.getSource().getName(m.getSourceId());
			map += " = ";
			map += aml.getTarget().getName(m.getTargetId());
			mappings.add(map);
		}
		searchField = new JTextArea(1,60);
		searchField.setEditable(true);    
	    KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
        Object actionKey = searchField.getInputMap(
                JComponent.WHEN_FOCUSED).get(keyStroke);
		searchField.getActionMap().put(actionKey, wrapper);
        AutoCompleteDecorator.decorate(searchField,mappings,false);
		JPanel selectionPanel = new JPanel();
		selectionPanel.add(searchField);
		cancel = new JButton("Cancel");
		cancel.setPreferredSize(new Dimension(70,28));
		cancel.addActionListener(this);
		find = new JButton("Find");
		find.setPreferredSize(new Dimension(70,28));
		find.addActionListener(this);
		JPanel buttonPanel = new JPanel();
		buttonPanel.add(cancel);
		buttonPanel.add(find);
		
		searchPanel = new JPanel();
		searchPanel.setLayout(new BoxLayout(searchPanel, BoxLayout.PAGE_AXIS));
		searchPanel.add(labelPanel);
		searchPanel.add(selectionPanel);
		searchPanel.add(buttonPanel);
		
       	dialogPanel.add(searchPanel, "Search");
        cl.show(dialogPanel, "Search");

		this.add(dialogPanel);
		
        this.pack();
		GraphicsEnvironment g = GraphicsEnvironment.getLocalGraphicsEnvironment();
		int left = g.getCenterPoint().x - (int)(this.getPreferredSize().width / 2);
		this.setLocation(left, 0);
        this.setVisible(true);
	}
	
//Public Methods
	
	@Override	
	public void actionPerformed(ActionEvent e)
	{
		Object o = e.getSource();
		if(o == cancel || o == quit)
		{
			this.dispose();
		}
		else if(o == back)
		{
			cl.show(dialogPanel, "Search");
		}
		else if(o == select)
		{
			this.dispose();
			aml.goTo(mappings.indexOf(results[mappingSelector.getSelectedIndex()]));
			new ViewMapping();
		}
		else if(o == find)
		{
			find();
		}
	}
	
	public void keyPressed(KeyEvent e)
	{
	    int key = e.getKeyCode();

	    if(key == KeyEvent.VK_ENTER)
	    {
	    	find();
	    }
	}

//Private Methods
	
	private void find()
	{
		//Get the entered text
		String text = searchField.getText();
		//Check that the user entered a valid input (at least 3 consecutive characters)
		if(text.matches(".*[a-zA-Z0-9]{3,}.*"))
		{
			//If so, clean the input
			text = text.toLowerCase().trim();
			text = text.replaceAll("\t\n\f\r", " ");
			//If the input is a listed mapping go there
			int index = mappings.indexOf(text);
			if(index > -1)
			{
				this.dispose();
				aml.goTo(index);
				new ViewMapping();
			}
			//Otherwise, search for it
			else
			{
				search(text);
				buildResultsPanel();
		       	dialogPanel.add(resultsPanel, "Results");
		        cl.show(dialogPanel, "Results");
			}
		}
		else
		{
			JOptionPane.showMessageDialog(this, "Invalid input!\n" + 
					"Please enter a word with at least three characters!",
					"Error", JOptionPane.ERROR_MESSAGE); 
		}
	}
	
	private void search(String query)
	{
		HashMap<String,Double> hits = new HashMap<String,Double>();
		for(String m : mappings)
		{
			if(m.contains(query))
				hits.put(m, similarity(m,query));
		}
		Set<String> orderedHits = MapSorter.sortDescending(hits).keySet();
		results = new String[hits.size()];
		results = orderedHits.toArray(results);
	}

	private Double similarity(String mapping, String query)
	{
		return 1.0*query.length()/mapping.length();
	}
	
	private void buildResultsPanel()
	{
		if(results.length == 0)
		{
			JLabel desc = new JLabel("No Results Found!");
			desc.setFont(boldFont);
			JPanel labelPanel = new JPanel();
			labelPanel.setBorder(new EmptyBorder(20,0,18,0));
			labelPanel.add(desc);
			
			back = new JButton("Back");
			back.setPreferredSize(new Dimension(70,28));
			back.addActionListener(this);
			quit = new JButton("Quit");
			quit.setPreferredSize(new Dimension(70,28));
			quit.addActionListener(this);
			JPanel buttonPanel = new JPanel();
			buttonPanel.add(back);
			buttonPanel.add(quit);
			
			resultsPanel = new JPanel();
			resultsPanel.setLayout(new BoxLayout(resultsPanel, BoxLayout.PAGE_AXIS));
			resultsPanel.add(labelPanel);
			resultsPanel.add(buttonPanel);
		}
		else
		{
			JLabel desc = new JLabel("Select a Mapping from the Search Results:");
			desc.setFont(boldFont);
			JPanel labelPanel = new JPanel();
			labelPanel.add(desc);
			
			mappingSelector = new JComboBox<String>(results);
			mappingSelector.setPreferredSize(new Dimension(650,28));
			mappingSelector.setSelectedIndex(0);
			JPanel selectionPanel = new JPanel();
			selectionPanel.add(mappingSelector);
			
			back = new JButton("Back");
			back.setPreferredSize(new Dimension(70,28));
			back.addActionListener(this);
			select = new JButton("Select");
			select.setPreferredSize(new Dimension(70,28));
			select.addActionListener(this);
			JPanel buttonPanel = new JPanel();
			buttonPanel.add(back);
			buttonPanel.add(select);
			
			resultsPanel = new JPanel();
			resultsPanel.setLayout(new BoxLayout(resultsPanel, BoxLayout.PAGE_AXIS));
			resultsPanel.add(labelPanel);
			resultsPanel.add(selectionPanel);
			resultsPanel.add(buttonPanel);
		}
	}
	
	private Action wrapper = new AbstractAction()
	{
		private static final long serialVersionUID = 424525650588931780L;

		@Override
        public void actionPerformed(ActionEvent ae)
        {
            find.doClick();
        }
    };
}