/*******************************************************************************
 * Copyright (c) 2003, 2018 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.debug.internal.ui.sourcelookup;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.eclipse.debug.core.sourcelookup.ISourceContainer;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.actions.SelectionListenerAction;

/**
 * The abstract class for all source lookup actions.
 *
 * @since 3.0
 */
public abstract class SourceContainerAction extends SelectionListenerAction {
	//the viewer that the action is operating on
	private SourceContainerViewer fViewer;
	//the button that is used to invoke the action
	private Button fButton;
	//the shell used to realize this action's dialog (if any)
	private Shell fShell;

	/**
	 * The constructor for the action
	 * @param label the label for the action's button
	 */
	public SourceContainerAction(String label) {
		super(label);
	}

	/**
	 * Sets the viewer on which this action operates.
	 *
	 * @param viewer the viewer on which this action operates
	 */
	public void setViewer(SourceContainerViewer viewer) {
		if (fViewer != null) {
			fViewer.removeSelectionChangedListener(this);
		}
		fViewer = viewer;
		if (fViewer != null) {
			fViewer.addSelectionChangedListener(this);
			update();
		}
	}

	/**
	 * Returns the viewer on which this action operates.
	 *
	 * @return the viewer on which this action operates
	 */
	protected SourceContainerViewer getViewer() {
		return fViewer;
	}

	/**
	 * Returns the selected items in the list, in the order they are
	 * displayed.
	 *
	 * @return targets for an action
	 */
	protected List<ISourceContainer> getOrderedSelection() {
		List<ISourceContainer> targets = new ArrayList<>();
		List<Object> selection = getViewer().getStructuredSelection().toList();
		ISourceContainer[] entries = getViewer().getEntries();
		for (ISourceContainer target : entries) {
			if (selection.contains(target)) {
				targets.add(target);
			}
		}
		return targets;
	}

	/**
	 * Returns a list (copy) of the entries in the viewer
	 */
	protected List<ISourceContainer> getEntriesAsList() {
		ISourceContainer[] entries = getViewer().getEntries();
		List<ISourceContainer> list = new ArrayList<>(entries.length);
		Collections.addAll(list, entries);
		return list;
	}

	/**
	 * Updates the entries to the entries in the given list
	 */
	protected void setEntries(List<ISourceContainer> list) {
		getViewer().setEntries(list.toArray(new ISourceContainer[list.size()]));
		// update all selection listeners
		getViewer().setSelection(getViewer().getSelection());
	}

	/**
	 * Returns whether the item at the given index in the list
	 * (visually) is selected.
	 */
	protected boolean isIndexSelected(IStructuredSelection selection, int index) {
		if (selection.isEmpty()) {
			return false;
		}
		Iterator<Object> entries = selection.iterator();
		List<ISourceContainer> list = getEntriesAsList();
		while (entries.hasNext()) {
			Object next = entries.next();
			if (list.indexOf(next) == index) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Sets the button that invokes this action
	 */
	public void setButton(Button button) {
		fButton = button;
		button.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent evt) {
				run();
			}
		});
	}

	@Override
	public void setEnabled(boolean enabled) {
		super.setEnabled(enabled);
		if (fButton != null) {
			fButton.setEnabled(enabled);
		}
	}

	/**
	 * Updates the enabled state.
	 */
	protected void update() {
		selectionChanged(getViewer().getStructuredSelection());
	}

	/**
	 * Returns the shell used to realize this action's dialog (if any).
	 */
	protected Shell getShell() {
		if (fShell == null) {
			fShell = getViewer().getControl().getShell();
		}
		return fShell;
	}

	/**
	 * Sets the shell used to realize this action's dialog (if any).
	 */
	public void setShell(Shell shell) {
		fShell = shell;
	}

}
