/*******************************************************************************
 * Copyright (c) 2000, 2013 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jdt.internal.ui.dialogs;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import org.eclipse.swt.SWT;
import org.eclipse.swt.accessibility.AccessibleAdapter;
import org.eclipse.swt.accessibility.AccessibleEvent;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.DialogSettings;
import org.eclipse.jface.dialogs.IDialogSettings;

import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.WorkbenchException;
import org.eclipse.ui.XMLMemento;

import org.eclipse.jdt.core.search.IJavaSearchScope;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.core.search.TypeNameMatch;

import org.eclipse.jdt.internal.corext.util.Strings;

import org.eclipse.jdt.ui.dialogs.ITypeSelectionComponent;
import org.eclipse.jdt.ui.dialogs.TypeSelectionExtension;

import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.JavaUIMessages;
import org.eclipse.jdt.internal.ui.search.JavaSearchScopeFactory;
import org.eclipse.jdt.internal.ui.util.PixelConverter;
import org.eclipse.jdt.internal.ui.util.SWTUtil;
import org.eclipse.jdt.internal.ui.util.TypeNameMatchLabelProvider;
import org.eclipse.jdt.internal.ui.workingsets.WorkingSetFilterActionGroup;


/**
 * DO NOT REMOVE, used in a product.
 * @deprecated As of 3.5, replaced by {@link org.eclipse.ui.dialogs.FilteredItemsSelectionDialog}
 */
@Deprecated
@SuppressWarnings("all")
public class TypeSelectionComponent extends Composite implements ITypeSelectionComponent {

	private IDialogSettings fSettings;
	private boolean fMultipleSelection;
	private ITitleLabel fTitleLabel;

	private ToolBar fToolBar;
	private ToolItem fToolItem;
	private MenuManager fMenuManager;
	private WorkingSetFilterActionGroup fFilterActionGroup;

	private TypeSelectionExtension fTypeSelectionExtension;
	private Text fFilter;
	private String fInitialFilterText;
	private IJavaSearchScope fScope;
	private TypeInfoViewer fViewer;
	private ViewForm fForm;
	private CLabel fLabel;

	public static final int NONE= 0;
	public static final int CARET_BEGINNING= 1;
	public static final int FULL_SELECTION= 2;

	private static final String DIALOG_SETTINGS= "org.eclipse.jdt.internal.ui.dialogs.TypeSelectionComponent"; //$NON-NLS-1$
	private static final String SHOW_STATUS_LINE= "show_status_line"; //$NON-NLS-1$
	private static final String FULLY_QUALIFY_DUPLICATES= "fully_qualify_duplicates"; //$NON-NLS-1$
	private static final String WORKINGS_SET_SETTINGS= "workingset_settings"; //$NON-NLS-1$

	private class ToggleStatusLineAction extends Action {
		public ToggleStatusLineAction() {
			super(JavaUIMessages.TypeSelectionComponent_show_status_line_label, IAction.AS_CHECK_BOX);
		}
		@Override
		public void run() {
			if (fForm == null)
				return;
			GridData gd= (GridData)fForm.getLayoutData();
			boolean checked= isChecked();
			gd.exclude= !checked;
			fForm.setVisible(checked);
			fSettings.put(SHOW_STATUS_LINE, checked);
			TypeSelectionComponent.this.layout();
		}
	}

	private class FullyQualifyDuplicatesAction extends Action {
		public FullyQualifyDuplicatesAction() {
			super(JavaUIMessages.TypeSelectionComponent_fully_qualify_duplicates_label, IAction.AS_CHECK_BOX);
		}
		@Override
		public void run() {
			boolean checked= isChecked();
			fViewer.setFullyQualifyDuplicates(checked, true);
			fSettings.put(FULLY_QUALIFY_DUPLICATES, checked);
		}
	}

	/**
	 * Special interface to access a title lable in
	 * a generic fashion.
	 */
	public interface ITitleLabel {
		/**
		 * Sets the title to the given text
		 *
		 * @param text the title text
		 */
		void setText(String text);
	}

	public TypeSelectionComponent(Composite parent, int style, String message, boolean multi,
			IJavaSearchScope scope, int elementKind, String initialFilter, ITitleLabel titleLabel,
			TypeSelectionExtension extension) {
		super(parent, style);
		setFont(parent.getFont());
		fMultipleSelection= multi;
		fScope= scope;
		fInitialFilterText= initialFilter;
		fTitleLabel= titleLabel;
		fTypeSelectionExtension= extension;
		IDialogSettings settings= JavaPlugin.getDefault().getDialogSettings();
		fSettings= settings.getSection(DIALOG_SETTINGS);
		if (fSettings == null) {
			fSettings= new DialogSettings(DIALOG_SETTINGS);
			settings.addSection(fSettings);
		}
		if (fSettings.get(SHOW_STATUS_LINE) == null) {
			fSettings.put(SHOW_STATUS_LINE, true);
		}
		createContent(message, elementKind);
	}

	@Override
	public void triggerSearch() {
		fViewer.forceSearch();
	}

	public TypeNameMatch[] getSelection() {
		return fViewer.getSelection();
	}

	public IJavaSearchScope getScope() {
		return fScope;
	}

	private void createContent(final String message, int elementKind) {
		GridLayout layout= new GridLayout();
		layout.numColumns= 2;
		layout.marginWidth= 0; layout.marginHeight= 0;
		setLayout(layout);
		Font font= getFont();

		Control header= createHeader(this, font, message);
		GridData gd= new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan= 2;
		header.setLayoutData(gd);

		fFilter= new Text(this, SWT.BORDER | SWT.FLAT);
		fFilter.setFont(font);
		if (fInitialFilterText != null) {
			fFilter.setText(fInitialFilterText);
		}
		gd= new GridData(GridData.FILL_HORIZONTAL);
		gd.horizontalSpan= 2;
		fFilter.setLayoutData(gd);
		fFilter.addModifyListener(event -> patternChanged((Text)event.widget));
		fFilter.addKeyListener(new KeyListener() {
			@Override
			public void keyReleased(KeyEvent e) {
			}
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.keyCode == SWT.ARROW_DOWN) {
					fViewer.setFocus();
				}
			}
		});
		fFilter.getAccessible().addAccessibleListener(new AccessibleAdapter() {
			@Override
			public void getName(AccessibleEvent e) {
				e.result= Strings.removeMnemonicIndicator(message);
			}
		});
		TextFieldNavigationHandler.install(fFilter);

		Label label= new Label(this, SWT.NONE);
		label.setFont(font);
		label.setText(JavaUIMessages.TypeSelectionComponent_label);
		label.addTraverseListener(event -> {
			if (event.detail == SWT.TRAVERSE_MNEMONIC && event.doit) {
				event.detail= SWT.TRAVERSE_NONE;
				fViewer.setFocus();
			}
		});
		label= new Label(this, SWT.RIGHT);
		label.setFont(font);
		gd= new GridData(GridData.FILL_HORIZONTAL);
		label.setLayoutData(gd);
		fViewer= new TypeInfoViewer(this, fMultipleSelection ? SWT.MULTI : SWT.NONE, label,
			fScope, elementKind, fInitialFilterText,
			fTypeSelectionExtension != null ? fTypeSelectionExtension.getFilterExtension() : null,
			fTypeSelectionExtension != null ? fTypeSelectionExtension.getImageProvider() : null);
		gd= new GridData(GridData.FILL_BOTH);
		final Table table= fViewer.getTable();
		PixelConverter converter= new PixelConverter(table);
		gd.widthHint= converter.convertWidthInCharsToPixels(70);
		gd.heightHint= SWTUtil.getTableHeightHint(table, 10);
		gd.horizontalSpan= 2;
		table.setLayoutData(gd);
		table.getAccessible().addAccessibleListener(new AccessibleAdapter() {
			@Override
			public void getName(AccessibleEvent e) {
				if (table.getSelectionCount() == 0) {
					e.result= Strings.removeMnemonicIndicator(JavaUIMessages.TypeSelectionComponent_label);
				}
			}
		});
		fViewer.setFullyQualifyDuplicates(fSettings.getBoolean(FULLY_QUALIFY_DUPLICATES), false);
		if (fTypeSelectionExtension != null) {
			Control addition= fTypeSelectionExtension.createContentArea(this);
			if (addition != null) {
				addition.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
			}
		}
		if (!fMultipleSelection) {
			fForm= new ViewForm(this, SWT.BORDER | SWT.FLAT);
			fForm.setFont(font);
			gd= new GridData(GridData.FILL_HORIZONTAL);
			gd.horizontalSpan= 2;
			boolean showStatusLine= fSettings.getBoolean(SHOW_STATUS_LINE);
			gd.exclude= !showStatusLine;
			fForm.setVisible(showStatusLine);
			fForm.setLayoutData(gd);
			fLabel= new CLabel(fForm, SWT.FLAT);
			fLabel.setFont(fForm.getFont());
			fForm.setContent(fLabel);
			table.addSelectionListener(new SelectionAdapter() {
				private TypeNameMatchLabelProvider fLabelProvider= new TypeNameMatchLabelProvider(
					TypeNameMatchLabelProvider.SHOW_TYPE_CONTAINER_ONLY + TypeNameMatchLabelProvider.SHOW_ROOT_POSTFIX);
				@Override
				public void widgetSelected(SelectionEvent event) {
					TypeNameMatch[] selection= fViewer.getSelection();
					if (selection.length != 1) {
						fLabel.setText(""); //$NON-NLS-1$
						fLabel.setImage(null);
					} else {
						TypeNameMatch type= selection[0];
						fLabel.setText(fViewer.getLabelProvider().getQualificationText(type));
						fLabel.setImage(fLabelProvider.getImage(type));
					}
				}
			});
		}
		addDisposeListener(event -> disposeComponent());
		if (fTypeSelectionExtension != null) {
			fTypeSelectionExtension.initialize(this);
		}
	}

	public void addSelectionListener(SelectionListener listener) {
		fViewer.getTable().addSelectionListener(listener);
	}

	public void populate(int selectionMode) {
		if (fInitialFilterText != null) {
			switch(selectionMode) {
				case CARET_BEGINNING:
					fFilter.setSelection(0, 0);
					break;
				case FULL_SELECTION:
					fFilter.setSelection(0, fInitialFilterText.length());
					break;
			}
		}
		fFilter.setFocus();
		fViewer.startup();
	}

	private void patternChanged(Text text) {
		fViewer.setSearchPattern(text.getText());
	}

	private Control createHeader(Composite parent, Font font, String message) {
		Composite header= new Composite(parent, SWT.NONE);
		GridLayout layout= new GridLayout();
		layout.numColumns= 2;
		layout.marginWidth= 0; layout.marginHeight= 0;
		header.setLayout(layout);
		header.setFont(font);
		Label label= new Label(header, SWT.NONE);
		label.setText(message);
		label.setFont(font);
		label.addTraverseListener(event -> {
			if (event.detail == SWT.TRAVERSE_MNEMONIC && event.doit) {
				event.detail= SWT.TRAVERSE_NONE;
				fFilter.setFocus();
			}
		});
		GridData gd= new GridData(GridData.FILL_HORIZONTAL);
		label.setLayoutData(gd);

		createViewMenu(header);
		return header;
	}

	private void createViewMenu(Composite parent) {
		fToolBar= new ToolBar(parent, SWT.FLAT);
		fToolItem= new ToolItem(fToolBar, SWT.PUSH, 0);

		GridData data= new GridData();
		data.horizontalAlignment= GridData.END;
		fToolBar.setLayoutData(data);

		fToolItem.setImage(JavaPluginImages.get(JavaPluginImages.IMG_ELCL_VIEW_MENU));
		fToolItem.setDisabledImage(JavaPluginImages.get(JavaPluginImages.IMG_DLCL_VIEW_MENU));
		fToolItem.setToolTipText(JavaUIMessages.TypeSelectionComponent_menu);
		fToolItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				showViewMenu();
			}
		});

		fMenuManager= new MenuManager();
		fillViewMenu(fMenuManager);

		// ICommandService commandService= (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class);
		// IHandlerService handlerService= (IHandlerService)PlatformUI.getWorkbench().getAdapter(IHandlerService.class);
	}

	private void showViewMenu() {
		Menu menu = fMenuManager.createContextMenu(getShell());
		Rectangle bounds = fToolItem.getBounds();
		Point topLeft = new Point(bounds.x, bounds.y + bounds.height);
		topLeft = fToolBar.toDisplay(topLeft);
		menu.setLocation(topLeft.x, topLeft.y);
		menu.setVisible(true);
	}

	private void fillViewMenu(IMenuManager viewMenu) {
		if (!fMultipleSelection) {
			ToggleStatusLineAction showStatusLineAction= new ToggleStatusLineAction();
			showStatusLineAction.setChecked(fSettings.getBoolean(SHOW_STATUS_LINE));
			viewMenu.add(showStatusLineAction);
		}
		FullyQualifyDuplicatesAction fullyQualifyDuplicatesAction= new FullyQualifyDuplicatesAction();
		fullyQualifyDuplicatesAction.setChecked(fSettings.getBoolean(FULLY_QUALIFY_DUPLICATES));
		viewMenu.add(fullyQualifyDuplicatesAction);
		if (fScope == null) {
			fFilterActionGroup= new WorkingSetFilterActionGroup(getShell(),
				JavaPlugin.getActivePage(),
				event -> {
					IWorkingSet ws= (IWorkingSet)event.getNewValue();
					if (ws == null || (ws.isAggregateWorkingSet() && ws.isEmpty())) {
						fScope= SearchEngine.createWorkspaceScope();
						fTitleLabel.setText(null);
					} else {
						fScope= JavaSearchScopeFactory.getInstance().createJavaSearchScope(ws, true);
						fTitleLabel.setText(ws.getLabel());
					}
					fViewer.setSearchScope(fScope, true);
				});
			String setting= fSettings.get(WORKINGS_SET_SETTINGS);
			if (setting != null) {
				try {
					IMemento memento= XMLMemento.createReadRoot(new StringReader(setting));
					fFilterActionGroup.restoreState(memento);
				} catch (WorkbenchException e) {
				}
			}
			IWorkingSet ws= fFilterActionGroup.getWorkingSet();
			if (ws == null || (ws.isAggregateWorkingSet() && ws.isEmpty())) {
				fScope= SearchEngine.createWorkspaceScope();
				fTitleLabel.setText(null);
			} else {
				fScope= JavaSearchScopeFactory.getInstance().createJavaSearchScope(ws, true);
				fTitleLabel.setText(ws.getLabel());
			}
			fFilterActionGroup.fillViewMenu(viewMenu);
		}
	}

	private void disposeComponent() {
		if (fFilterActionGroup != null) {
			XMLMemento memento= XMLMemento.createWriteRoot("workingSet"); //$NON-NLS-1$
			fFilterActionGroup.saveState(memento);
			fFilterActionGroup.dispose();
			StringWriter writer= new StringWriter();
			try {
				memento.save(writer);
				fSettings.put(WORKINGS_SET_SETTINGS, writer.getBuffer().toString());
			} catch (IOException e) {
				// don't do anything. Simply don't store the settings
			}
		}
	}
}
