/*******************************************************************************
 * Copyright (c) 2003, 2013 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.ant.tests.ui;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.ant.internal.ui.AntUIPlugin;
import org.eclipse.ant.internal.ui.IAntUIPreferenceConstants;
import org.eclipse.ant.launching.IAntLaunchConstants;
import org.eclipse.ant.tests.ui.testplugin.ConsoleLineTracker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.swt.graphics.Color;
import org.eclipse.ui.console.IHyperlink;

public class BuildTests extends AbstractAntUIBuildTest {

	public BuildTests(String name) {
		super(name);
	}

	/**
	 * Tests launching Ant and getting messages logged to the console.
	 */
	public void testOutput() throws CoreException {
		launch("echoing"); //$NON-NLS-1$
		assertTrue("Incorrect number of messages logged for build. Should be 8. Was " + ConsoleLineTracker.getNumberOfMessages(), ConsoleLineTracker.getNumberOfMessages() == 8); //$NON-NLS-1$
		String message = ConsoleLineTracker.getMessage(6);
		assertTrue("Incorrect last message. Should start with Total time:. Message: " + message, message.startsWith("Total time:")); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * This build will fail. With verbose on you should be presented with a full stack trace. Bug 82833
	 */
	public void testVerboseStackTrace() throws Exception {
		launch("failingTarget", "-k -verbose"); //$NON-NLS-1$ //$NON-NLS-2$
		assertEquals("Incorrect message", "BUILD FAILED", ConsoleLineTracker.getMessage(19)); //$NON-NLS-1$ //$NON-NLS-2$
		assertTrue("Incorrect message" + ConsoleLineTracker.getMessage(22), ConsoleLineTracker.getMessage(22).startsWith("\tat org.apache.tools.ant.taskdefs.Zip")); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Tests launching Ant and getting the build failed message logged to the console with associated link. Bug 42333 and 44565
	 */
	public void testBuildFailedMessage() throws CoreException {
		launch("bad"); //$NON-NLS-1$
		assertTrue("Incorrect number of messages logged for build. Should be 10. Was " + ConsoleLineTracker.getNumberOfMessages(), ConsoleLineTracker.getNumberOfMessages() == 10); //$NON-NLS-1$
		String message = ConsoleLineTracker.getMessage(5);
		assertTrue("Incorrect last message. Should start with BUILD FAILED. Message: " + message, message.startsWith("BUILD FAILED")); //$NON-NLS-1$ //$NON-NLS-2$
		int offset = -1;
		try {
			offset = ConsoleLineTracker.getDocument().getLineOffset(4) + 30; // link to buildfile that failed
		}
		catch (BadLocationException e) {
			assertTrue("failed getting offset of line", false); //$NON-NLS-1$
		}
		IHyperlink link = getHyperlink(offset, ConsoleLineTracker.getDocument());
		assertNotNull("No hyperlink found at offset " + offset, link); //$NON-NLS-1$
	}

	/**
	 * Tests launching Ant and that the correct links are in the console doc
	 */
	public void testLinks() throws CoreException {
		launch("build"); //$NON-NLS-1$
		int offset = 25; // buildfile link
		IHyperlink link = getHyperlink(offset, ConsoleLineTracker.getDocument());
		assertNotNull("No hyperlink found at offset " + offset, link); //$NON-NLS-1$
		activateLink(link);

		try {
			offset = ConsoleLineTracker.getDocument().getLineOffset(4) + 10; // echo link
		}
		catch (BadLocationException e) {
			assertTrue("failed getting offset of line", false); //$NON-NLS-1$
		}
		link = getHyperlink(offset, ConsoleLineTracker.getDocument());
		assertNotNull("No hyperlink found at offset " + offset, link); //$NON-NLS-1$
		activateLink(link);
	}

	/**
	 * Tests launching Ant and that build failed presents links to the failures when multi-line.
	 */
	public void testBuildFailedLinks() throws CoreException {
		launch("102282"); //$NON-NLS-1$
		try {
			int offset = ConsoleLineTracker.getDocument().getLineOffset(9) + 10; // second line of build failed link
			IHyperlink link = getHyperlink(offset, ConsoleLineTracker.getDocument());
			assertNotNull("No hyperlink found at offset " + offset, link); //$NON-NLS-1$
			activateLink(link);

		}
		catch (BadLocationException e) {
			assertTrue("failed getting offset of line", false); //$NON-NLS-1$
		}
	}

	/**
	 * Tests launching Ant and that the correct colors are in the console doc
	 */
	public void testColor() throws BadLocationException, CoreException {
		launch("echoing"); //$NON-NLS-1$
		int offset = 15; // buildfile
		Color color = getColorAtOffset(offset, ConsoleLineTracker.getDocument());
		assertNotNull("No color found at " + offset, color); //$NON-NLS-1$
		assertEquals(AntUIPlugin.getPreferenceColor(IAntUIPreferenceConstants.CONSOLE_INFO_COLOR), color);
		try {
			offset = ConsoleLineTracker.getDocument().getLineOffset(4) + 10; // echo
		}
		catch (BadLocationException e) {
			assertTrue("failed getting offset of line", false); //$NON-NLS-1$
		}
		color = getColorAtOffset(offset, ConsoleLineTracker.getDocument());
		assertNotNull("No color found at " + offset, color); //$NON-NLS-1$
		assertEquals(AntUIPlugin.getPreferenceColor(IAntUIPreferenceConstants.CONSOLE_WARNING_COLOR), color);
	}

	/**
	 * Tests launching Ant in a separate vm and that the correct property substitions occur
	 */
	public void testPropertySubstitution() throws CoreException {
		ILaunchConfiguration config = getLaunchConfiguration("74840"); //$NON-NLS-1$
		assertNotNull("Could not locate launch configuration for " + "74840", config); //$NON-NLS-1$ //$NON-NLS-2$
		ILaunchConfigurationWorkingCopy copy = config.getWorkingCopy();
		Map<String, String> properties = new HashMap<>(1);
		properties.put("platform.location", "${workspace_loc}"); //$NON-NLS-1$ //$NON-NLS-2$
		copy.setAttribute(IAntLaunchConstants.ATTR_ANT_PROPERTIES, properties);
		copy.setAttribute(IAntLaunchConstants.ATTR_ANT_PROPERTIES, properties);
		launchAndTerminate(copy, 20000);
		ConsoleLineTracker.waitForConsole();
		assertTrue("Incorrect number of messages logged for build. Should be 8. Was " + ConsoleLineTracker.getNumberOfMessages(), ConsoleLineTracker.getNumberOfMessages() == 8); //$NON-NLS-1$
		assertTrue("Incorrect echo message. Should not include unsubstituted property", !ConsoleLineTracker.getMessage(4).trim().startsWith("[echo] ${workspace_loc}")); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * Tests specifying the XmlLogger as a listener (bug 80435)
	 * 
	 * @throws FileNotFoundException
	 */
	public void testXmlLoggerListener() throws CoreException, FileNotFoundException {
		launch("echoing", "-listener org.apache.tools.ant.XmlLogger"); //$NON-NLS-1$ //$NON-NLS-2$
		assertTrue("Incorrect number of messages logged for build. Should be 8. Was " + ConsoleLineTracker.getNumberOfMessages(), ConsoleLineTracker.getNumberOfMessages() == 8); //$NON-NLS-1$
		String message = ConsoleLineTracker.getMessage(6);
		assertTrue("Incorrect last message. Should start with Total time:. Message: " + message, message.startsWith("Total time:")); //$NON-NLS-1$ //$NON-NLS-2$
		// find the log file generated by the xml logger
		getProject().getFolder("buildfiles").refreshLocal(IResource.DEPTH_INFINITE, null); //$NON-NLS-1$
		File file = getBuildFile("log.xml"); //$NON-NLS-1$
		String content = getFileContentAsString(file);
		assertTrue("XML logging file is empty", content.length() > 0); //$NON-NLS-1$
	}

	/**
	 * Tests launching Ant and getting the build failed message logged to the console. Bug 42333.
	 */
	// public void testBuildFailedMessageDebug() throws CoreException {
	// launchInDebug("bad");
	// assertTrue("Incorrect number of messages logged for build. Should be 35. Was " + ConsoleLineTracker.getNumberOfMessages(),
	// ConsoleLineTracker.getNumberOfMessages() == 35);
	// String message= ConsoleLineTracker.getMessage(33);
	// assertTrue("Incorrect last message. Should start with Build Failed:. Message: " + message, message.startsWith("BUILD FAILED:"));
	// }
	//
	// /**
	// * Tests launching Ant and that the
	// * correct links are in the console doc
	// */
	// public void testLinksDebug() throws CoreException {
	// launchInDebug("echoing");
	// int offset= 0;
	// try {
	// offset= ConsoleLineTracker.getDocument().getLineOffset(2) + 15; //buildfile line 3
	// } catch (BadLocationException e) {
	// assertTrue("failed getting offset of line", false);
	// }
	// IConsoleHyperlink link= getHyperlink(offset, ConsoleLineTracker.getDocument());
	// assertNotNull("No hyperlink found at offset " + offset, link);
	//
	// try {
	// offset= ConsoleLineTracker.getDocument().getLineOffset(33) + 10; //echo link
	// } catch (BadLocationException e) {
	// assertTrue("failed getting offset of line", false);
	// }
	// link= getHyperlink(offset, ConsoleLineTracker.getDocument());
	// assertNotNull("No hyperlink found at offset " + offset, link);
	// }
	//
	// /**
	// * Tests launching Ant and that the
	// * correct colors are in the console doc
	// */
	// public void testColorDebug() throws BadLocationException, CoreException {
	// launchInDebug("echoing");
	// int offset= 0;
	// try {
	// offset= ConsoleLineTracker.getDocument().getLineOffset(2) + 15; //buildfile line 3
	// } catch (BadLocationException e) {
	// assertTrue("failed getting offset of line", false);
	// }
	// Color color= getColorAtOffset(offset, ConsoleLineTracker.getDocument());
	// assertNotNull("No color found at " + offset, color);
	// assertEquals(AntUIPlugin.getPreferenceColor(IAntUIPreferenceConstants.CONSOLE_INFO_COLOR), color);
	//
	// try {
	// offset= ConsoleLineTracker.getDocument().getLineOffset(4) + 3; //debug info
	// } catch (BadLocationException e) {
	// assertTrue("failed getting offset of line", false);
	// }
	// color= getColorAtOffset(offset, ConsoleLineTracker.getDocument());
	// assertNotNull("No color found at " + offset, color);
	// assertEquals(AntUIPlugin.getPreferenceColor(IAntUIPreferenceConstants.CONSOLE_DEBUG_COLOR), color);
	//
	// try {
	// offset= ConsoleLineTracker.getDocument().getLineOffset(33) + 10; //echo line 33
	// } catch (BadLocationException e) {
	// assertTrue("failed getting offset of line", false);
	// }
	// color= getColorAtOffset(offset, ConsoleLineTracker.getDocument());
	// assertNotNull("No color found at " + offset, color);
	// assertEquals(AntUIPlugin.getPreferenceColor(IAntUIPreferenceConstants.CONSOLE_WARNING_COLOR), color);
	// }
}
