/*******************************************************************************
 * Copyright (c) 2000, 2009 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
 *     Tom Eicher (Avaloq Evolution AG) - block selection mode
 *******************************************************************************/

package org.eclipse.ui.texteditor;


import java.util.ResourceBundle;

import org.eclipse.core.runtime.Assert;

import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextSelection;

/**
 * An action to delete a whole line, the fraction of the line that is left from the cursor
 * or the fraction that is right from the cursor.
 *
 * @since 2.0
 */
public class DeleteLineAction extends TextEditorAction {

	/**
	 * Delete the whole line.
	 */
	public static final int WHOLE= 0;
	/**
	 * Delete to the beginning of line.
	 */
	public static final int TO_BEGINNING= 1;
	/**
	 * Delete to the end of line.
	 */
	public static final int TO_END= 2;

	/**
	 * The type of deletion.
	 */
	private final int fType;
	/**
	 * Should the deleted line be copied to the clipboard.
	 * @since 2.1
	 */
	private final boolean fCopyToClipboard;
	/** The deletion target.
	 * @since 2.1
	 */
	private IDeleteLineTarget fTarget;

	/**
	 * Creates a line deletion action.
	 *
	 * @param bundle the resource bundle for UI strings
	 * @param prefix the prefix for the property keys into <code>bundle</code>
	 * @param editor the editor
	 * @param type the line deletion type, must be one of <code>WHOLE_LINE</code>,
	 *            <code>TO_BEGINNING</code> or <code>TO_END</code>
	 */
	public DeleteLineAction(ResourceBundle bundle, String prefix, ITextEditor editor, int type) {
		this(bundle, prefix, editor, type, true);
	}

	/**
	 * Creates a line deletion action.
	 *
	 * @param bundle the resource bundle for UI strings
	 * @param prefix the prefix for the property keys into <code>bundle</code>
	 * @param editor the editor
	 * @param type the line deletion type, must be one of
	 * 	<code>WHOLE_LINE</code>, <code>TO_BEGINNING</code> or <code>TO_END</code>
	 * @param copyToClipboard if <code>true</code>, the contents of the deleted line are copied to the clipboard
	 * @since 2.1
	 */
	public DeleteLineAction(ResourceBundle bundle, String prefix, ITextEditor editor, int type, boolean copyToClipboard) {
		super(bundle, prefix, editor);
		fType= type;
		fCopyToClipboard= copyToClipboard;
		update();
	}

	/**
	 * Creates a line deletion action.
	 *
	 * @param editor the editor
	 * @param type the line deletion type, must be one of <code>WHOLE_LINE</code>,
	 *            <code>TO_BEGINNING</code> or <code>TO_END</code>
	 * @param copyToClipboard if <code>true</code>, the contents of the deleted line are copied to
	 *            the clipboard
	 * @since 3.5
	 */
	public DeleteLineAction(ITextEditor editor, int type, boolean copyToClipboard) {
		this(EditorMessages.getBundleForConstructedKeys(), getPrefix(type, copyToClipboard), editor, type, copyToClipboard);
	}

	/**
	 * Returns the default resource bundle prefix for the given arguments.
	 *
	 * @param type the line deletion type, must be one of <code>WHOLE_LINE</code>,
	 *            <code>TO_BEGINNING</code> or <code>TO_END</code>
	 * @param copyToClipboard if <code>true</code>, the contents of the deleted line are copied to
	 *            the clipboard
	 * @return the prefix for the property keys into <code>bundle</code>
	 * @since 3.5
	 */
	private static String getPrefix(int type, boolean copyToClipboard) {
		switch (type) {
			case WHOLE:
				return copyToClipboard ? "Editor.CutLine." : "Editor.DeleteLine."; //$NON-NLS-1$ //$NON-NLS-2$
			case TO_BEGINNING:
				return copyToClipboard ? "Editor.CutLineToBeginning." : "Editor.DeleteLineToBeginning."; //$NON-NLS-1$ //$NON-NLS-2$
			case TO_END:
				return copyToClipboard ? "Editor.CutLineToEnd." : "Editor.DeleteLineToEnd."; //$NON-NLS-1$ //$NON-NLS-2$
			default:
				Assert.isLegal(false);
				return ""; //$NON-NLS-1$
		}
	}

	/**
	 * Returns the editor's document.
	 *
	 * @param editor the editor
	 * @return the editor's document
	 */
	private static IDocument getDocument(ITextEditor editor) {

		IDocumentProvider documentProvider= editor.getDocumentProvider();
		if (documentProvider == null)
			return null;

		IDocument document= documentProvider.getDocument(editor.getEditorInput());
		if (document == null)
			return null;

		return document;
	}

	/**
	 * Returns the editor's selection.
	 *
	 * @param editor the editor
	 * @return the editor's selection
	 */
	private static ITextSelection getSelection(ITextEditor editor) {

		ISelectionProvider selectionProvider= editor.getSelectionProvider();
		if (selectionProvider == null)
			return null;

		ISelection selection= selectionProvider.getSelection();
		if (!(selection instanceof ITextSelection))
			return null;

		return (ITextSelection) selection;
	}

	@Override
	public void run() {

		if (fTarget == null)
			return;

		ITextEditor editor= getTextEditor();
		if (editor == null)
			return;

		if (!validateEditorInputState())
			return;

		IDocument document= getDocument(editor);
		if (document == null)
			return;

		ITextSelection selection= getSelection(editor);
		if (selection == null)
			return;

		try {
			if (fTarget instanceof TextViewerDeleteLineTarget)
				((TextViewerDeleteLineTarget) fTarget).deleteLine(document, selection, fType, fCopyToClipboard);
			else
				fTarget.deleteLine(document, selection.getOffset(), selection.getLength(), fType, fCopyToClipboard);
		} catch (BadLocationException e) {
			// should not happen
		}
	}

	@Override
	public void update() {

		super.update();
		if (!isEnabled())
			return;

		if (!canModifyEditor()) {
			setEnabled(false);
			return;
		}

		ITextEditor editor= getTextEditor();
		if (editor != null)
			fTarget= editor.getAdapter(IDeleteLineTarget.class);
		else
			fTarget= null;

		setEnabled(fTarget != null);
	}
}
