/*******************************************************************************
 * Copyright (c) 2007, 2011 Wind River Systems, Inc. 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:
 *     Anton Leherbauer (Wind River Systems) - initial API and implementation
 *     Andrew Gvozdev
 *******************************************************************************/
package org.eclipse.cdt.ui.tests.text;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.testplugin.CProjectHelper;
import org.eclipse.cdt.internal.core.model.ext.SourceRange;
import org.eclipse.cdt.internal.ui.editor.CEditor;
import org.eclipse.cdt.ui.testplugin.EditorTestHelper;
import org.eclipse.cdt.ui.testplugin.ResourceTestHelper;
import org.eclipse.cdt.ui.tests.BaseUITestCase;
import org.eclipse.cdt.ui.tests.text.AddBlockCommentTest.LinePosition;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.text.IDocument;

import junit.framework.TestSuite;

/**
 * Tests for the RemoveBlockCommentAction.
 *
 * @since 5.0
 */
public class RemoveBlockCommentTest extends BaseUITestCase {
	private ICProject fCProject;

	public static TestSuite suite() {
		return suite(RemoveBlockCommentTest.class, "_");
	}

	private CEditor fEditor;
	private IDocument fDocument;

	@Override
	protected void setUp() throws Exception {
		super.setUp();

		final String PROJECT = "BlockComment";
		// Using any existing file just to open CEditor, the content is not used
		final String filename = "/BlockComment/src/sample/Before.cpp";
		fCProject = EditorTestHelper.createCProject(PROJECT, "resources/formatter");
		fCProject.setOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.TAB);
		fEditor = (CEditor) EditorTestHelper.openInEditor(ResourceTestHelper.findFile(filename), true);

		fDocument = EditorTestHelper.getSourceViewer(fEditor).getDocument();
		// Delete contents
		fDocument.set("");
	}

	@Override
	protected void tearDown() throws Exception {
		EditorTestHelper.closeEditor(fEditor);

		if (fCProject != null)
			CProjectHelper.delete(fCProject);

		super.tearDown();
	}

	/**
	 * Run an action to comment block defined by line positions
	 * and assert that the result matches the expected result.
	 * "Before" and "After" are taken from test comments.
	 *
	 * @param startLinePosition
	 * @param endLinePosition
	 * @throws Exception
	 */
	protected void assertFormatterResult(LinePosition startLinePosition, LinePosition endLinePosition)
			throws Exception {
		CharSequence[] contents = getContentsForTest(2);
		String before = contents[0].toString();
		String after = contents[1].toString();

		fDocument.set(before);

		SourceRange range = new SourceRange(startLinePosition.getOffset(),
				endLinePosition.getOffset() - startLinePosition.getOffset());
		fEditor.setSelection(range, true);

		IAction commentAction = fEditor.getAction("RemoveBlockComment");
		assertNotNull("No RemoveBlockComment action", commentAction);
		commentAction.setEnabled(true);
		commentAction.run();

		String expected = after;
		assertEquals(expected, fDocument.get());
	}

	/**
	 * Run an action to comment block defined by line positions
	 * and assert that the result matches the expected result.
	 * "Before" and "After" are taken from test comments.
	 *
	 * @param startLinePosition
	 * @param endLinePosition
	 * @param before editor contents before the operation
	 * @param after expected editor contents after the operation
	 * @throws Exception
	 */
	protected void assertFormatterResult(LinePosition startLinePosition, LinePosition endLinePosition, String before,
			String after) throws Exception {
		fDocument.set(before);

		SourceRange range = new SourceRange(startLinePosition.getOffset(),
				endLinePosition.getOffset() - startLinePosition.getOffset());
		fEditor.setSelection(range, true);

		IAction commentAction = fEditor.getAction("RemoveBlockComment");
		assertNotNull("No RemoveBlockComment action", commentAction);
		commentAction.setEnabled(true);
		commentAction.run();

		String expected = after;
		assertEquals(expected, fDocument.get());
	}

	//int i, /*j,*/ k;

	//int i, j, k;
	public void testUncommentPlain() throws Exception {
		LinePosition startSelection = new LinePosition(1, 10, fDocument);
		LinePosition endSelection = new LinePosition(1, 11, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int /*j,*/ k;

	//int j, k;
	public void testRightBorderIn() throws Exception {
		LinePosition startSelection = new LinePosition(1, 10, fDocument);
		LinePosition endSelection = new LinePosition(1, 11, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int /*j,*/ k;

	//int /*j,*/ k;
	public void testRightBorderOut() throws Exception {
		LinePosition startSelection = new LinePosition(1, 11, fDocument);
		LinePosition endSelection = new LinePosition(1, 12, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}
	//123456789-123

	//int /*j,*/ k;

	//int j, k;
	public void testLeftBorderIn() throws Exception {
		LinePosition startSelection = new LinePosition(1, 5, fDocument);
		LinePosition endSelection = new LinePosition(1, 6, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int /*j,*/ k;

	//int /*j,*/ k;
	public void testLeftBorderOut() throws Exception {
		LinePosition startSelection = new LinePosition(1, 4, fDocument);
		LinePosition endSelection = new LinePosition(1, 5, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int /*i,
	//    j,*/
	//    k;

	//int i,
	//    j,
	//    k;
	public void testUncommentPartialLines1() throws Exception {
		LinePosition startSelection = new LinePosition(1, 7, fDocument);
		LinePosition endSelection = new LinePosition(2, 2, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int i,
	///*    j,
	//    k*/;

	//int i,
	//    j,
	//    k;
	public void testUncommentPartialLines2() throws Exception {
		LinePosition startSelection = new LinePosition(2, 1, fDocument);
		LinePosition endSelection = new LinePosition(3, 8, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int i;
	///*int j;*/
	//int k;

	//int i;
	//int j;
	//int k;
	public void testUncommentExactlyOneLineNoLoopingPlease() throws Exception {
		LinePosition startSelection = new LinePosition(2, 1, fDocument);
		LinePosition endSelection = new LinePosition(3, 1, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int i;
	///*
	//int j;
	//int k;
	//*/
	//int l;

	//int i;
	//int j;
	//int k;
	//int l;
	public void testUncommentTwoOrMoreLines() throws Exception {
		LinePosition startSelection = new LinePosition(2, 1, fDocument);
		LinePosition endSelection = new LinePosition(4, 1, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	///*const*/ int i;

	//const int i;
	public void testUncommentFirstCharacterInFile() throws Exception {
		LinePosition startSelection = new LinePosition(1, 1, fDocument);
		LinePosition endSelection = new LinePosition(1, 6, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	///*#include <x>*/
	//#include <y>

	//#include <x>
	//#include <y>
	public void testUncommentPreprocessorFirstLine() throws Exception {
		LinePosition startSelection = new LinePosition(1, 1, fDocument);
		LinePosition endSelection = new LinePosition(1, 6, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//int i; /*// comment*/
	//int j;

	//int i; // comment
	//int j;
	public void testUncommentCppComment() throws Exception {
		LinePosition startSelection = new LinePosition(1, 10, fDocument);
		LinePosition endSelection = new LinePosition(1, 12, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//#include <x>
	///*#include <y>*/
	//#include <z>

	//#include <x>
	//#include <y>
	//#include <z>
	public void testUncommentSpecialPartition() throws Exception {
		LinePosition startSelection = new LinePosition(2, 1, fDocument);
		LinePosition endSelection = new LinePosition(3, 1, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//#include <x>
	///*
	//   #include \
	//      <y>
	//*/
	//#include <z>

	//#include <x>
	//   #include \
	//      <y>
	//#include <z>
	public void testUncommentSpecialPartitionExtra() throws Exception {
		LinePosition startSelection = new LinePosition(3, 8, fDocument);
		LinePosition endSelection = new LinePosition(3, 10, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	///*int i;*/
	///*int j;*/
	//int k;

	//int i;
	//int j;
	//int k;
	public void testUncommentConnectedComments() throws Exception {
		LinePosition startSelection = new LinePosition(1, 5, fDocument);
		LinePosition endSelection = new LinePosition(2, 5, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	//
	///*
	//
	//*/

	//
	//
	public void testUncommentEndOfFile() throws Exception {
		LinePosition startSelection = new LinePosition(3, 1, fDocument);
		LinePosition endSelection = new LinePosition(5, 2, fDocument);
		assertFormatterResult(startSelection, endSelection);
	}

	public void testMixedEOLs() throws Exception {
		String before = "/*\r\n" + "int i;\r\n" + "int j;\n" + "*/\n" + "int k;";
		String after = "int i;\r\n" + "int j;\n" + "int k;";
		LinePosition startSelection = new LinePosition(2, 1, fDocument);
		LinePosition endSelection = new LinePosition(3, 1, fDocument);
		assertFormatterResult(startSelection, endSelection, before, after);
	}
}
