/*******************************************************************************
 * Copyright (c) 2004, 2010 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 - Initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.managedbuilder.makegen.gnu;

import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineGenerator;
import org.eclipse.cdt.managedbuilder.core.IManagedCommandLineInfo;
import org.eclipse.cdt.managedbuilder.core.IResourceConfiguration;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.internal.macros.FileContextData;
import org.eclipse.cdt.managedbuilder.macros.BuildMacroException;
import org.eclipse.cdt.managedbuilder.macros.IBuildMacroProvider;
import org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderMakefileGenerator;
import org.eclipse.cdt.managedbuilder.makegen.IManagedDependencyGenerator;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;

/**
 * @since 2.0
 * @noextend This class is not intended to be subclassed by clients.
 * @noinstantiate This class is not intended to be instantiated by clients.
 */
public class DefaultGCCDependencyCalculator implements IManagedDependencyGenerator {

	private static final String EMPTY_STRING = new String();
	private static final String[] EMPTY_STRING_ARRAY = new String[0];
	public final String WHITESPACE = " ";	//$NON-NLS-1$

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderDependencyCalculator#findDependencies(org.eclipse.core.resources.IResource)
	 */
	@Override
	public IResource[] findDependencies(IResource resource, IProject project) {
		return null;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderDependencyCalculator#getCalculatorType()
	 */
	@Override
	public int getCalculatorType() {
		return TYPE_COMMAND;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.cdt.managedbuilder.makegen.IManagedBuilderDependencyCalculator#getDependencyCommand()
	 */
	@Override
	public String getDependencyCommand(IResource resource, IManagedBuildInfo info) {
		/*
		 * For a given input, <path>/<resource_name>.<ext>, return a string containing
		 * 	echo -n $(@:%.<out_ext>=%.d) '<path>/' >> $(@:%.<out_ext>=%.d) && \
		 * 	<tool_command> -P -MM -MG <tool_flags> $< >> $(@:%.<out_ext>=%.d)
		 *
		 */
		StringBuffer buffer = new StringBuffer();

		// Get what we need to create the dependency generation command
		IConfiguration config = info.getDefaultConfiguration();

		//	We need to check whether we have any resource specific build information.
		IResourceConfiguration resConfig = null;
		if( config != null ) resConfig = config.getResourceConfiguration(resource.getFullPath().toString());

		String inputExtension = resource.getFileExtension();
		String outputExtension = info.getOutputExtension(inputExtension);

		// Work out the build-relative path for the output files
		IContainer resourceLocation = resource.getParent();
		String relativePath = new String();
		if (resourceLocation != null) {
			relativePath += resourceLocation.getProjectRelativePath().toString();
		}
		if (relativePath.length() > 0) {
			relativePath +=  IManagedBuilderMakefileGenerator.SEPARATOR;
		}

		// Calculate the dependency rule
		// <path>/$(@:%.<out_ext>=%.d)
		String depRule = "'$(@:%." + //$NON-NLS-1$
			outputExtension +
			"=%." + //$NON-NLS-1$
			IManagedBuilderMakefileGenerator.DEP_EXT +
			")'"; //$NON-NLS-1$

		// Add the rule that will actually create the right format for the dep
		buffer.append(IManagedBuilderMakefileGenerator.TAB +
				IManagedBuilderMakefileGenerator.ECHO +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				"-n" + //$NON-NLS-1$
				IManagedBuilderMakefileGenerator.WHITESPACE +
				depRule +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				"$(dir $@)" + //$NON-NLS-1$
				IManagedBuilderMakefileGenerator.WHITESPACE +
				">" + //$NON-NLS-1$
				IManagedBuilderMakefileGenerator.WHITESPACE +
				depRule +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				IManagedBuilderMakefileGenerator.LOGICAL_AND +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				IManagedBuilderMakefileGenerator.LINEBREAK);

		// Add the line that will do the work to calculate dependencies
		IManagedCommandLineInfo cmdLInfo = null;
		String buildCmd = null;
		String[] inputs= new String[1]; inputs[0] = IManagedBuilderMakefileGenerator.IN_MACRO;
		String outflag = "";  //$NON-NLS-1$
		String outputPrefix = "";   //$NON-NLS-1$
		String outputFile = "";   //$NON-NLS-1$
		ITool[] tools;
		if( resConfig != null && (tools = resConfig.getToolsToInvoke()) != null && tools.length > 0) {
			ITool tool = tools[0];
			String cmd = tool.getToolCommand();
			//try to resolve the build macros in the tool command
			try {
				String resolvedCommand = null;

				// does the resource have spaces in its name?
				if (resource.getProjectRelativePath().toString().indexOf(" ") != -1) { //$NON-NLS-1$
					// use fully qualified strings
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									cmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				} else {
					// use builder variables
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									cmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				}

				if((resolvedCommand = resolvedCommand.trim()).length() > 0)
					cmd = resolvedCommand;

			} catch (BuildMacroException e){
			}

			String[] toolFlags = null;
			try {
				toolFlags = tool.getToolCommandFlags(resource.getLocation(),null);
			} catch( BuildException ex ) {
				// TODO add some routines to catch this
				toolFlags = EMPTY_STRING_ARRAY;
			}
			String[] flags = new String[toolFlags.length + 4];
			flags[0] = "-MM";  //$NON-NLS-1$
			flags[1] = "-MG";  //$NON-NLS-1$
			flags[2] = "-P";   //$NON-NLS-1$
			flags[3] = "-w";   //$NON-NLS-1$
			for (int i=0; i<toolFlags.length; i++) {
				flags[4+i] = toolFlags[i];
			}
			IManagedCommandLineGenerator cmdLGen = tool.getCommandLineGenerator();
			cmdLInfo = cmdLGen.generateCommandLineInfo( tool, cmd, flags, outflag, outputPrefix,
					outputFile, inputs, tool.getCommandLinePattern() );
			buildCmd = cmdLInfo.getCommandLine();

			// resolve any remaining macros in the command after it has been generated
			try {
				String resolvedCommand = null;

				// does the resource have spaces in its name?
				if (resource.getProjectRelativePath().toString().indexOf(" ") != -1) { //$NON-NLS-1$
					// use fully qualified strings
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									buildCmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				} else {
					// use builder variables
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									buildCmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				}
				if((resolvedCommand = resolvedCommand.trim()).length() > 0)
					buildCmd = resolvedCommand;

			} catch (BuildMacroException e){
			}


		} else {
			ITool tool = null;
			IFolderInfo foInfo = (IFolderInfo)config.getResourceInfo(resource.getProjectRelativePath(), false);
			tools = foInfo.getFilteredTools();
			for (int index = 0; index < tools.length; index++) {
				ITool tmp = tools[index];
				if (tmp.buildsFileType(inputExtension)) {
					tool = tmp;
					break;
				}
			}
			String cmd = tool != null ? tool.getToolCommand() : null;

			//try to resolve the build macros in the tool command
			try{
				String resolvedCommand = ManagedBuildManager.getBuildMacroProvider().resolveValueToMakefileFormat(cmd,
						"", //$NON-NLS-1$
						" ", //$NON-NLS-1$
						IBuildMacroProvider.CONTEXT_FILE,
						new FileContextData(resource.getLocation(),null,null,tool));
				if((resolvedCommand = resolvedCommand.trim()).length() > 0)
					cmd = resolvedCommand;

			} catch (BuildMacroException e){
			}

			String buildFlags = "-MM -MG -P -w " + info.getToolFlagsForSource(inputExtension, resource.getLocation(), null); //$NON-NLS-1$
			String[] flags = buildFlags.split( "\\s" ); //$NON-NLS-1$
			cmdLInfo = info.generateToolCommandLineInfo( inputExtension, flags, outflag, outputPrefix,
					outputFile, inputs, resource.getLocation(), null);
			// The command to build
			if( cmdLInfo == null ) buildCmd =
				cmd +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				"-MM -MG -P -w " +  //$NON-NLS-1$
				buildFlags +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				IManagedBuilderMakefileGenerator.IN_MACRO;
			else {
				buildCmd = cmdLInfo.getCommandLine();
			}

            // resolve any remaining macros in the command after it has been
            // generated
			try {
				String resolvedCommand = null;

				// does the resource have spaces in its name?
				if (resource.getProjectRelativePath().toString().indexOf(" ") != -1) { //$NON-NLS-1$
					// use fully qualified strings
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									buildCmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				} else {
					// use builder variables
					resolvedCommand = ManagedBuildManager
							.getBuildMacroProvider()
							.resolveValueToMakefileFormat(
									buildCmd,
									"", //$NON-NLS-1$
									" ", //$NON-NLS-1$
									IBuildMacroProvider.CONTEXT_FILE,
									new FileContextData(resource.getLocation(),
											null, null, tool));
				}
                if ((resolvedCommand = resolvedCommand.trim()).length() > 0)
                    buildCmd = resolvedCommand;

            } catch (BuildMacroException e) {
            }
		}

		buffer.append(IManagedBuilderMakefileGenerator.TAB +
				buildCmd +
				IManagedBuilderMakefileGenerator.WHITESPACE +
				">>" +  //$NON-NLS-1$
				IManagedBuilderMakefileGenerator.WHITESPACE + depRule );

		return buffer.toString();
	}

}
