package lu.tudor.santec.gecamed.core.gui.widgets.autocompletion;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

import lu.tudor.santec.gecamed.core.ejb.entity.beans.Autocompletion;
import lu.tudor.santec.gecamed.core.ejb.session.beans.AutocompletionBean;
import lu.tudor.santec.gecamed.core.ejb.session.interfaces.AutocompletionInterface;
import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.MainFrame;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.core.gui.widgets.KeepSelectionHandler;
import lu.tudor.santec.gecamed.core.utils.ManagerFactory;
import lu.tudor.santec.i18n.Translatrix;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.layout.Sizes;
import com.l2fprod.common.swing.JLinkButton;

public class AutoCompletionImportDialog extends GECAMedBaseDialogImpl implements ListSelectionListener
{
	/* ======================================== */
	// 		CONSTANTS
	/* ======================================== */
	
	private static final long serialVersionUID = 1L;
	
	private static final String COLUMN_FORMAT 		= "5px, f:200px, 10px, f:200px:g, 5px";
	private static final String ROW_FORMAT 			= " 5px, f:p," +
													  "10px, f:p," +
													  " 5px, f:150px:g," +
													  " 0px, f:p," +
													  " 5px";
	private static final String BUTTON_PANEL_FORMAT = "l:p:g,0px,r:p:g";
	
	/* ======================================== */
	// 		MEMBERS
	/* ======================================== */
	
	private static JFileChooser fileChooser = new JFileChooser();
	static 
	{
		fileChooser.setFileFilter(new FileFilter()
		{
			@Override
			public String getDescription()
			{
				return ".xml";
			}
			
			@Override
			public boolean accept(File f)
			{
				return f.isDirectory() || f.getName().endsWith(".xml");
			}
		});
	}
	
	private List<String> existingContexts = new LinkedList<String>();
	
	private CellRenderer cellRenderer = new CellRenderer();
	
	private HashMap<String, List<Autocompletion>> completionMap;
	
	private boolean[] duplicateContextsInList;
	private boolean[] duplicateContextsInTable;
	
	// COMPONENTS
	private DefaultListModel 	contextListModel;
	private JList 				contextList;
	private DefaultTableModel 	completionTableModel;
	private JTable 				completionTable;
	private Vector<String> 		completionTableHeader;
	private JPopupMenu 			contextMenu;
	private int 				lastRightclickedIndex;
	
	
	
	/* ======================================== */
	// 		CONSTRUCTOR
	/* ======================================== */
	
	public AutoCompletionImportDialog()
	{
		super(MainFrame.getInstance(), 
				Translatrix.getTranslationString("MultiWordAutoCompletion.IO.importAutocompletions"), 
				OK_CANCEL_BUTTON_MODE);

		CellConstraints cc = new CellConstraints();
		
		/* ---------------------------------------- */
		// 		DESCRIPTION
		/* ---------------------------------------- */
		
		JLabel description = new JLabel(
				Translatrix.getTranslationString("MultiWordAutoCompletion.IO.importDescription"));
		description.setOpaque(false);
		
		
		/* ---------------------------------------- */
		// 		LOAD FILE BUTTON
		/* ---------------------------------------- */
		
		JButton loadFileButton = new JButton(new AbstractAction(
				Translatrix.getTranslationString("MultiWordAutoCompletion.IO.loadFile"),
				GECAMedModule.getMediumIcon(GECAMedIconNames.OPEN))
		{
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e)
			{
				loadFile ();
			}
		});
		this.addButton(loadFileButton);
		
		/* ---------------------------------------- */
		// 		CONTEXT LIST
		/* ---------------------------------------- */
		
		JLabel contextListLabel = new JLabel(
				Translatrix.getTranslationString("MultiWordAutoCompletion.IO.contextToImport"));
		contextListModel = new DefaultListModel();
		contextList 	 = new JList(contextListModel);
		contextList.setCellRenderer(cellRenderer);
		contextList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		KeepSelectionHandler.keepSelection(contextList);
		contextList.addListSelectionListener(this);
		contextList.addMouseListener(new MouseListener()
		{
			public void mouseReleased(MouseEvent e)
			{
				if (e.isPopupTrigger())
					showContextMenu(e);
					
			}
			
			public void mousePressed(MouseEvent e)
			{
				if (e.isPopupTrigger())
					showContextMenu(e);
			}
			
			public void mouseExited(MouseEvent e) {}
			public void mouseEntered(MouseEvent e) {}
			public void mouseClicked(MouseEvent e) {}
		});
		
		contextMenu = new JPopupMenu();
		Action renameAction = new AbstractAction(
				Translatrix.getTranslationString("core.rename"),
				GECAMedModule.getMiniIcon(GECAMedIconNames.RENAME))
		{
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e)
			{
				renameContext();
			}
		};
		contextMenu.add(renameAction);
		
		JScrollPane contextListScroller = new JScrollPane(contextList);
		contextListScroller.setOpaque(false);
		contextListScroller.getViewport().setOpaque(false);
		
		JLinkButton selectAllButton = new JLinkButton(new AbstractAction(
				Translatrix.getTranslationString("core.selectAll"))
		{
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e)
			{
				int size = contextList.getModel().getSize();
				if (size > 0)
					contextList.setSelectionInterval(0, size-1);
			}
		});
		selectAllButton.setOpaque(false);
		
		JLinkButton deselectAllButton = new JLinkButton(new AbstractAction(
				Translatrix.getTranslationString("core.selectNone"))
		{
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e)
			{
				contextList.clearSelection();
			}
		});
		deselectAllButton.setOpaque(false);
		deselectAllButton.setAlignmentY(1.0f);
		deselectAllButton.setAlignmentX(1.0f);
		
		FormLayout 	selectButtonsLayout = new FormLayout(BUTTON_PANEL_FORMAT);
		JPanel 		selectButtonsPanel 	= new JPanel(selectButtonsLayout);
		selectButtonsLayout.appendRow(new RowSpec(Sizes.PREFERRED));
		selectButtonsPanel.setOpaque(false);
		
		
		/* ---------------------------------------- */
		// 		COMPLETION TABLE
		/* ---------------------------------------- */

		JLabel completionTableLabel = new JLabel(
				Translatrix.getTranslationString("MultiWordAutoCompletion.IO.contentOfContext"));
		completionTableModel 	= new DefaultTableModel();
		completionTableHeader 	= new Vector<String>();
		completionTable 	 	= new JTable(completionTableModel);
		
		completionTableHeader.add(Translatrix.getTranslationString("MultiWordAutoCompletion.IO.context"));
		completionTableHeader.add(Translatrix.getTranslationString("MultiWordAutoCompletion.IO.insertText"));
		completionTableHeader.add(Translatrix.getTranslationString("MultiWordAutoCompletion.IO.replacementText"));
		
		
		JScrollPane completionTableScroller = new JScrollPane(completionTable);
		completionTableScroller.setOpaque(false);
		completionTableScroller.getViewport().setOpaque(false);
		
		
		/* ---------------------------------------- */
		// 		MAIN PANEL
		/* ---------------------------------------- */
		
		mainPanel.setLayout(new FormLayout(COLUMN_FORMAT, ROW_FORMAT));
		
		int row = 0;
		mainPanel.add(description, 				cc.xyw (2, row+=2, 3));
		mainPanel.add(contextListLabel, 		cc.xy  (2, row+=2));
		mainPanel.add(completionTableLabel, 	cc.xy  (4, row));
		mainPanel.add(contextListScroller, 		cc.xy  (2, row+=2));
		mainPanel.add(completionTableScroller, 	cc.xywh(4, row, 1, 3));
		mainPanel.add(selectButtonsPanel, 		cc.xy  (2, row+=2));
	}
	
	
	
	/* ======================================== */
	// 		OVERRIDDEN METHODS
	/* ======================================== */
	
	
	@Override
	public void setVisible(boolean b)
	{
		refresh();
		super.setVisible(b);
	}
	
	
	@Override
	public void okActionCalled()
	{
		storeAutocompletions();
		
		super.okActionCalled();
	}
	
	
	
	/* ======================================== */
	// 		LIST SELECTION EVENTS
	/* ======================================== */
	
	public void valueChanged(ListSelectionEvent e)
	{
		if (e.getValueIsAdjusting())
			return;
		
		Vector<Vector<String>> 	tableData 	= new Vector<Vector<String>>();
		Vector<String> 			rowData 	= new Vector<String>();
		List<Autocompletion> 	completions;
		boolean isDuplicate;
		int i = 0;
		
		for (List<Autocompletion> list : completionMap.values())
		{
			i += list.size();
		}
		duplicateContextsInTable = new boolean[i];
		
		i = 0;
		int[] selection = contextList.getSelectedIndices();
		okButton.setEnabled(selection.length > 0);
		for (int index : selection)
		{
			String context 	= (String) contextListModel.get(index);
			completions 	= completionMap.get(context);
			isDuplicate 	= duplicateContextsInList[index];
			
			for (Autocompletion ac : completions)
			{
				rowData 	= new Vector<String>();
				rowData.add(ac.getContext());
				rowData.add(ac.getInputText());
				rowData.add(ac.getReplacementText());
				tableData.add(rowData);
				duplicateContextsInTable[i++] = isDuplicate;
			}
		}
		setTableData(tableData);
		
	}
	
	
	
	/* ======================================== */
	// 		HELP METHODS
	/* ======================================== */
	
	
	private void refresh ()
	{
		contextListModel.clear();
		setTableData(null);
		okButton.setEnabled(false);
		
		AutocompletionInterface manager = (AutocompletionInterface) ManagerFactory.getRemote(AutocompletionBean.class);
		existingContexts = manager.getContexts();
		
		this.setSize(500, 520);
		this.setLocationRelativeTo(getOwner());
	}
	
	private void loadFile ()
	{
		contextListModel.clear();
		if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
		{
			File file = fileChooser.getSelectedFile();
			completionMap = AutoCompletionIOManager.importCompletions(file);
			
			if (completionMap != null)
			{
				Set<String> keys = new TreeSet<String>(completionMap.keySet());
				duplicateContextsInList = new boolean[keys.size()];
				int index = 0;
				for (String context : keys)
				{
					contextListModel.addElement(context);
					duplicateContextsInList[index++] = existingContexts.contains(context);
				}
				
				int size = contextListModel.getSize();
				if (size > 0)
					contextList.setSelectionInterval(0, size - 1);
			}
		}
	}
	
	
	private void setTableData (Vector<Vector<String>> data)
	{
		if (data == null)
			data = new Vector<Vector<String>>();
		completionTableModel.setDataVector(data, completionTableHeader);
		TableColumnModel columnModel = completionTable.getColumnModel();
		for (int col = 0; col < columnModel.getColumnCount(); col++)
			columnModel.getColumn(col).setCellRenderer(cellRenderer);
	}
	
	
	private void storeAutocompletions ()
	{
		List<Autocompletion> 	completions = new LinkedList<Autocompletion>();
		List<String> 			contexts 	= new LinkedList<String>();
		AutocompletionInterface manager;
		
		int[] selection = contextList.getSelectedIndices();
		for (int index : selection)
		{
			String context 	= (String) contextListModel.get(index);
			contexts.add(context);
			completions.addAll(completionMap.get(context));
		}
		
		manager = (AutocompletionInterface) ManagerFactory.getRemote(AutocompletionBean.class);
		manager.updateCompletions(completions);
		
		GECAMedAutoCompletionHandler.reloadProvider(contexts);
	}
	
	
	private void showContextMenu (MouseEvent e)
	{
		lastRightclickedIndex = contextList.locationToIndex(e.getPoint());
		contextMenu.setVisible(true);
		contextMenu.show((Component) e.getSource(), e.getX(), e.getY());
	}
	
	
	private void renameContext ()
	{
		List<Autocompletion> list;
		boolean selected;
		int 	index = lastRightclickedIndex;
		String 	oldContext = (String) contextListModel.get(index);
		String 	newContext = GECAMedBaseDialogImpl.showInputMessageDialog(this, 
					Translatrix.getTranslationString("MultiWordAutoCompletion.IO.renameContext_title"), 
					Translatrix.getTranslationString("MultiWordAutoCompletion.IO.renameContext_message"), 
					oldContext);
		
		if (newContext == null
				|| newContext.equals(oldContext))
			return;
		
		if (completionMap.get(newContext) != null)
		{
			int option = GECAMedBaseDialogImpl.showMessageDialog(this, 
					Translatrix.getTranslationString("MultiWordAutoCompletion.IO.identicalContext_title"), 
					Translatrix.getTranslationString("MultiWordAutoCompletion.IO.identicalContext_message"), 
					YES_NO_BUTTON_MODE, 
					GECAMedModule.getMediumIcon(GECAMedIconNames.WARNING));
			if (option == YES_OPTION)
			{
				// join the completions of this context and the existing one
				list = completionMap.remove(oldContext);
				for (Autocompletion ac : list)
				{
					ac.setContext(newContext);
				}
				completionMap.get(newContext).addAll(list);
				contextListModel.remove(index);
				return;
			}
			else // if (option == NO_BUTTON || option == RED_CROSS_BUTTON)
			{
				return;
			}
		}
		
		list = completionMap.remove(oldContext);
		for (Autocompletion ac : list)
		{
			ac.setContext(newContext);
		}
		completionMap.put(newContext, list);
		
		this.duplicateContextsInList[index] = existingContexts.contains(newContext);
		
		selected = contextList.isSelectedIndex(index);
		contextListModel.remove(index);
		contextListModel.add(index, newContext);
		if (selected)
			contextList.addSelectionInterval(index, index);
		else
			contextList.removeSelectionInterval(index, index);
		
//		completionTable.validate();
	}
	
	
	
	/* ======================================== */
	// 		CELL RENDERER
	/* ======================================== */
	
	private class CellRenderer implements ListCellRenderer, TableCellRenderer
	{
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus)
		{
			JLabel cell = new JLabel((String) value);
			cell.setOpaque(true);
			
			// set the background
			Color bg;
			if (isSelected)
				bg = list.getSelectionBackground();
			else if (index % 2 == 0)
				bg = GECAMedColors.c_EvenLineBackground;
			else
				bg = GECAMedColors.c_OddLineBackground;
			cell.setBackground(bg);
			
			if (duplicateContextsInList[index])
			{
				cell.setForeground(Color.ORANGE);
				cell.setToolTipText(
						Translatrix.getTranslationString("MultiWordAutoCompletion.IO.contextAlreadyExistsToolTip"));
			}
			
			return cell;
		}

		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column)
		{
			JLabel cell = new JLabel((String) value);
			cell.setOpaque(true);
			
			// set the background
			Color bg;
//			if (isSelected)
//				bg = table.getSelectionBackground();
//			else 
			if (row % 2 == 0)
				bg = GECAMedColors.c_EvenLineBackground;
			else
				bg = GECAMedColors.c_OddLineBackground;
			cell.setBackground(bg);
			
			if (column == 0 && duplicateContextsInTable[row])
				cell.setForeground(Color.ORANGE);
			
			return cell;
		}
	}
}
