/*******************************************************************************
 * Copyright (c) 2007, 2013 Intel 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:
 * Intel Corporation - Initial API and implementation
 * Baltasar Belyavsky (Texas Instruments) - bug 340219: Project metadata files are saved unnecessarily
 *******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.dataprovider;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.cdt.build.internal.core.scannerconfig2.CfgScannerConfigInfoFactory2;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvider;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.model.ILanguageDescriptor;
import org.eclipse.cdt.core.model.LanguageManager;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICExternalSetting;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.cdt.core.settings.model.IModificationContext;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationDataProvider;
import org.eclipse.cdt.managedbuilder.core.BuildException;
import org.eclipse.cdt.managedbuilder.core.IBuilder;
import org.eclipse.cdt.managedbuilder.core.IConfiguration;
import org.eclipse.cdt.managedbuilder.core.IFolderInfo;
import org.eclipse.cdt.managedbuilder.core.IInputType;
import org.eclipse.cdt.managedbuilder.core.IManagedBuildInfo;
import org.eclipse.cdt.managedbuilder.core.IManagedOptionValueHandler;
import org.eclipse.cdt.managedbuilder.core.IManagedProject;
import org.eclipse.cdt.managedbuilder.core.IOption;
import org.eclipse.cdt.managedbuilder.core.IResourceInfo;
import org.eclipse.cdt.managedbuilder.core.ITool;
import org.eclipse.cdt.managedbuilder.core.IToolChain;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.core.ManagedBuilderCorePlugin;
import org.eclipse.cdt.managedbuilder.internal.core.Builder;
import org.eclipse.cdt.managedbuilder.internal.core.BuilderFactory;
import org.eclipse.cdt.managedbuilder.internal.core.Configuration;
import org.eclipse.cdt.managedbuilder.internal.core.ISettingsChangeListener;
import org.eclipse.cdt.managedbuilder.internal.core.InputType;
import org.eclipse.cdt.managedbuilder.internal.core.ManagedBuildInfo;
import org.eclipse.cdt.managedbuilder.internal.core.ManagedProject;
import org.eclipse.cdt.managedbuilder.internal.core.NotificationManager;
import org.eclipse.cdt.managedbuilder.internal.core.SettingsChangeEvent;
import org.eclipse.cdt.managedbuilder.internal.core.Tool;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.core.runtime.content.IContentType;

/**
 * The main hook ManagedBuild uses to connect to cdt.core's project model.
 * Provides & Persists Build configuration data in the project model storage.
 */
public class ConfigurationDataProvider extends CConfigurationDataProvider implements ISettingsChangeListener {
	private static final String BUILD_SYSTEM_DATA_MODULE_NAME = "cdtBuildSystem";	//$NON-NLS-1$
	private static final String VERSION_ATTRIBUTE = "version";	//$NON-NLS-1$
	private static final String PREF_CFG_ID = "org.eclipse.cdt.build.core.prefbase.cfg";	//$NON-NLS-1$
	public static final String PREF_TC_ID = "org.eclipse.cdt.build.core.prefbase.toolchain";	//$NON-NLS-1$
	private static final String PREF_TOOL_ID = "org.eclipse.cdt.build.core.settings.holder";	//$NON-NLS-1$
	private static final QualifiedName CFG_PERSISTED_PROPERTY = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "configPersisted");	//$NON-NLS-1$
	private static final QualifiedName NATURES_USED_ON_CACHE_PROPERTY = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "naturesUsedOnCache");	//$NON-NLS-1$
	private static final QualifiedName BUILD_INFO_PROPERTY = new QualifiedName(ManagedBuilderCorePlugin.getUniqueIdentifier(), "buildInfo");	//$NON-NLS-1$

	private static boolean registered;

	public ConfigurationDataProvider(){
		if(!registered){
			registered = true;
			NotificationManager.getInstance().subscribe(this);
		}
	}

	private static class DesApplyRunnable implements IWorkspaceRunnable {
		IBuilder fBuilder;
		IProject fProject;

		DesApplyRunnable(IProject project, IBuilder builder){
			fProject = project;
			fBuilder = builder;
		}

		@Override
		public void run(IProgressMonitor monitor) throws CoreException {
			try {
				IProjectDescription eDes = fProject.getDescription();
				if(BuilderFactory.applyBuilder(eDes, fBuilder) == BuilderFactory.CMD_CHANGED) {
					fProject.setDescription(eDes, monitor);
				}
			} catch (Exception e){
				ManagedBuilderCorePlugin.log(e);
			}
		}

	}

	static BuildConfigurationData writeConfiguration(ICConfigurationDescription cfgDescription, BuildConfigurationData baseData)
			throws CoreException {

		BuildConfigurationData appliedCfg = baseData;
		ICStorageElement rootElement = cfgDescription.getStorage(BUILD_SYSTEM_DATA_MODULE_NAME, true);
		rootElement.clear();
		rootElement.setAttribute(VERSION_ATTRIBUTE, ManagedBuildManager.getVersion().toString());
		ICStorageElement cfgElemen = rootElement.createChild(IConfiguration.CONFIGURATION_ELEMENT_NAME);
		Configuration cfg = (Configuration)appliedCfg.getConfiguration();
		Builder b = (Builder)cfg.getEditableBuilder();
		// Need to ensure that build macro supplier can get the description for this configuration during the write...
		cfg.setConfigurationDescription(cfgDescription);
		if(b != null && b.isManagedBuildOn() && b.getBuildPathAttribute(false) == null){
			String bPath = b.getDefaultBuildPath();
			b.setBuildPathAttribute(bPath);
		}
//		cfg.setConfigurationDescription(des);
//		ManagedBuildManager.performValueHandlerEvent(cfg, IManagedOptionValueHandler.EVENT_APPLY);
		cfg.serialize(cfgElemen);

		return appliedCfg;
	}

	protected CConfigurationData applyPreferences(ICConfigurationDescription cfgDescription, CConfigurationData baseData) throws CoreException {
		BuildConfigurationData appliedCfg = writeConfiguration(cfgDescription, (BuildConfigurationData)baseData);

		IConfiguration cfg = ((BuildConfigurationData)baseData).getConfiguration();
		try {
			CfgScannerConfigInfoFactory2.savePreference(cfg);
		} catch (CoreException e){
			ManagedBuilderCorePlugin.log(e);
		}

		return appliedCfg;
	}

	@Override
	public CConfigurationData applyConfiguration(ICConfigurationDescription cfgDescription,
			ICConfigurationDescription baseCfgDescription, CConfigurationData baseData,
			IModificationContext context, IProgressMonitor monitor) throws CoreException {

		if (cfgDescription.isPreferenceConfiguration()) {
			return applyPreferences(cfgDescription, baseData);
		}

		BuildConfigurationData baseCfgData = (BuildConfigurationData)baseData;
		IConfiguration baseCfg = baseCfgData.getConfiguration();
		BuildConfigurationData appliedCfgData;
		if(context.isBaseDataCached() && !baseCfg.isDirty()){
			appliedCfgData = baseCfgData;
			context.setConfigurationSettingsFlags(IModificationContext.CFG_DATA_STORAGE_UNMODIFIED | IModificationContext.CFG_DATA_SETTINGS_UNMODIFIED);
		} else {
			appliedCfgData = writeConfiguration(cfgDescription, baseCfgData);

			IManagedBuildInfo info = getBuildInfo(cfgDescription);
			ManagedProject mProj = (ManagedProject)info.getManagedProject();
			mProj.applyConfiguration((Configuration)appliedCfgData.getConfiguration());
			writeManagedProjectInfo(cfgDescription.getProjectDescription(), mProj);
			if (baseCfgDescription instanceof ILanguageSettingsProvidersKeeper) {
				String[] defaultIds = ((ILanguageSettingsProvidersKeeper)baseCfgDescription).getDefaultLanguageSettingsProvidersIds();
				List<ILanguageSettingsProvider> providers;
				if (defaultIds == null) {
					ICProjectDescription prjDescription = baseCfgDescription.getProjectDescription();
					if (prjDescription != null) {
						IProject project = prjDescription.getProject();
						// propagate the preference to project properties
						ScannerDiscoveryLegacySupport.defineLanguageSettingsEnablement(project);
					}

					IConfiguration cfg = appliedCfgData.getConfiguration();
					defaultIds = cfg != null ? cfg.getDefaultLanguageSettingsProviderIds() : null;
					if (defaultIds == null) {
						defaultIds = ScannerDiscoveryLegacySupport.getDefaultProviderIdsLegacy(baseCfgDescription);
					}
					providers = LanguageSettingsManager.createLanguageSettingsProviders(defaultIds);
				} else {
					providers = ((ILanguageSettingsProvidersKeeper)baseCfgDescription).getLanguageSettingProviders();
				}
				if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
					((ILanguageSettingsProvidersKeeper)cfgDescription).setDefaultLanguageSettingsProvidersIds(defaultIds);
					((ILanguageSettingsProvidersKeeper) cfgDescription).setLanguageSettingProviders(providers);
				}
			}

			try {
				CfgScannerConfigInfoFactory2.save(appliedCfgData, cfgDescription.getProjectDescription(), baseCfgDescription.getProjectDescription(), !isPersistedCfg(cfgDescription));
			} catch (CoreException e){
				ManagedBuilderCorePlugin.log(e);
			}
			info.setValid(true);
			// Update the ManagedBuildInfo in the ManagedBuildManager map. Doing this creates a barrier for subsequent
			// ManagedBuildManager#getBuildInfo(...) see Bug 305146 for more
			ManagedBuildManager.setLoaddedBuildInfo(cfgDescription.getProjectDescription().getProject(), info);

			setPersistedFlag(cfgDescription);
			cacheNaturesIdsUsedOnCache(cfgDescription);
		}

		if(cfgDescription.isActive()){
			IConfiguration cfg = appliedCfgData.getConfiguration();
			IBuilder builder = cfg.getEditableBuilder();
			IProject project = context.getProject();
			IProjectDescription eDes = context.getEclipseProjectDescription();
			switch(BuilderFactory.applyBuilder(eDes, builder)){
			case BuilderFactory.CMD_UNDEFINED:
				IWorkspaceRunnable applyR = new DesApplyRunnable(project, builder);
				context.addWorkspaceRunnable(applyR);
				break;
			case BuilderFactory.CMD_CHANGED:
				context.setEclipseProjectDescription(eDes);
				break;
			}
		}

		return appliedCfgData;
	}

	private void setPersistedFlag(ICConfigurationDescription cfgDescription){
		cfgDescription.setSessionProperty(CFG_PERSISTED_PROPERTY, Boolean.TRUE);
	}

	private static void writeManagedProjectInfo(ICProjectDescription prjDescription, ManagedProject mProj) throws CoreException {
		ICStorageElement rootElement = prjDescription.getStorage(BUILD_SYSTEM_DATA_MODULE_NAME, true);
		rootElement.clear();
		rootElement.setAttribute(VERSION_ATTRIBUTE, ManagedBuildManager.getVersion().toString());
		ICStorageElement mProjElem = rootElement.createChild(IManagedProject.MANAGED_PROJECT_ELEMENT_NAME);
		mProj.serializeProjectInfo(mProjElem);
	}

	protected CConfigurationData createPreferences(ICConfigurationDescription cfgDescription, CConfigurationData baseData) throws CoreException {
		Configuration cfg = (Configuration)((BuildConfigurationData)baseData).getConfiguration();
		Configuration newCfg = new Configuration((ManagedProject)cfg.getManagedProject(), cfg, cfgDescription.getId(), true, true, true);
		newCfg.setConfigurationDescription(cfgDescription);
		newCfg.setName(cfgDescription.getName());
//		if(!newCfg.getId().equals(cfg.getId())){
//			newCfg.exportArtifactInfo();
//		}

		return newCfg.getConfigurationData();
	}


	@Override
	public CConfigurationData createConfiguration(ICConfigurationDescription cfgDescription,
			ICConfigurationDescription baseCfgDescription, CConfigurationData base, boolean clone,
			IProgressMonitor monitor) throws CoreException {

		if(cfgDescription.isPreferenceConfiguration())
			return createPreferences(cfgDescription, base);

		Configuration cfg = (Configuration)((BuildConfigurationData)base).getConfiguration();
		Configuration newCfg = copyCfg(cfg, cfgDescription);

		if(!newCfg.getId().equals(cfg.getId()) && newCfg.canExportedArtifactInfo()){
			// Bug 335001: Remove existing exported settings as they point at this configuration
			for (ICExternalSetting extSetting : newCfg.getConfigurationDescription().getExternalSettings())
				newCfg.getConfigurationDescription().removeExternalSetting(extSetting);
			// Now export the new settings
			newCfg.exportArtifactInfo();
		}

		setPersistedFlag(cfgDescription);

		return newCfg.getConfigurationData();
	}

	public static Configuration copyCfg(Configuration cfg, ICConfigurationDescription cfgDescription) {
		IManagedBuildInfo info = getBuildInfo(cfgDescription);
		ManagedProject mProj = (ManagedProject)info.getManagedProject();

		Configuration newCfg = new Configuration(mProj, cfg, cfgDescription.getId(), true, true, false);
		newCfg.setConfigurationDescription(cfgDescription);
		newCfg.setName(cfgDescription.getName());

		cfgDescription.setConfigurationData(ManagedBuildManager.CFG_DATA_PROVIDER_ID, newCfg.getConfigurationData());

		ManagedBuildManager.performValueHandlerEvent(newCfg, IManagedOptionValueHandler.EVENT_OPEN);

//		if(!newCfg.getId().equals(cfg.getId())){
//			newCfg.exportArtifactInfo();
//		}

		return newCfg;
	}

	private static IManagedBuildInfo getBuildInfo(ICConfigurationDescription cfgDescription) {
		ICProjectDescription projDes = cfgDescription.getProjectDescription();
		IProject project = projDes.getProject();
		IManagedBuildInfo info = ManagedBuildManager.getBuildInfo(project, false);
		if(info == null)
			info = ManagedBuildManager.createBuildInfo(project);

		setLoaddedBuildInfo(projDes, info);

		getManagedProject(cfgDescription, info);

		return info;
	}

	private static void setLoaddedBuildInfo(ICProjectDescription prjDescription, IManagedBuildInfo info) {
		prjDescription.setSessionProperty(BUILD_INFO_PROPERTY, info);
	}

	public static ManagedBuildInfo getLoaddedBuildInfo(ICProjectDescription prjDescription) {
		return (ManagedBuildInfo)prjDescription.getSessionProperty(BUILD_INFO_PROPERTY);
	}

	private static IManagedProject getManagedProject(ICConfigurationDescription cfgDescription, IManagedBuildInfo info) {
		IManagedProject mProj = info.getManagedProject();
		if(mProj == null){
			mProj = createManagedProject(info, cfgDescription.getProjectDescription());
		}
		return mProj;
	}

	private static IManagedProject createManagedProject(IManagedBuildInfo info, ICProjectDescription prjDescription) {
		IManagedProject mProj = null;
		try {
			ICStorageElement rootElem = prjDescription.getStorage(BUILD_SYSTEM_DATA_MODULE_NAME, false);
			if(rootElem != null){
				String version = rootElem.getAttribute(VERSION_ATTRIBUTE);
				ICStorageElement children[] = rootElem.getChildren();
				for(int i = 0; i < children.length; i++){
					if(IManagedProject.MANAGED_PROJECT_ELEMENT_NAME.equals(children[i].getName())){
						mProj = new ManagedProject((ManagedBuildInfo)info, children[i], false, version);
						break;
					}
				}
			}
		} catch (CoreException e) {
			mProj = null;
		}

		if(mProj == null){
			mProj = new ManagedProject(prjDescription);
			info.setManagedProject(mProj);
		}

		return mProj;
	}

	public static String[] getNaturesIdsUsedOnCache(IConfiguration cfg) {
		ICConfigurationDescription cfgDescription = ManagedBuildManager.getDescriptionForConfiguration(cfg);
		if(cfgDescription != null)
			return getNaturesIdsUsedOnCache(cfgDescription);
		return null;
	}

	public static String[] getNaturesIdsUsedOnCache(ICConfigurationDescription cfgDescription) {
		String[] strs = (String[])cfgDescription.getSessionProperty(NATURES_USED_ON_CACHE_PROPERTY);
		return strs != null && strs.length != 0 ? (String[])strs.clone() : strs;
	}

	public static void cacheNaturesIdsUsedOnCache(ICConfigurationDescription cfgDescription) {
		IProject project = cfgDescription.getProjectDescription().getProject();
		try {
			IProjectDescription eDes = project.getDescription();
			String[] natures = eDes.getNatureIds();
			setNaturesIdsUsedOnCache(cfgDescription, natures);
		} catch (CoreException e) {
			ManagedBuilderCorePlugin.log(e);
		}
	}

	private static void setNaturesIdsUsedOnCache(ICConfigurationDescription cfgDescription, String ids[]) {
		ids = ids != null && ids.length != 0 ? (String[])ids.clone() : ids;
		cfgDescription.setSessionProperty(NATURES_USED_ON_CACHE_PROPERTY, ids);
	}

	private Configuration load(ICConfigurationDescription cfgDescription, ManagedProject mProj, boolean isPreference) throws CoreException {
		ICStorageElement rootElement = cfgDescription.getStorage(BUILD_SYSTEM_DATA_MODULE_NAME, true);
		ICStorageElement children[] = rootElement.getChildren();
		String version = rootElement.getAttribute(VERSION_ATTRIBUTE);
		Configuration cfg = null;

		for(int i = 0; i < children.length; i++){
			if(IConfiguration.CONFIGURATION_ELEMENT_NAME.equals(children[i].getName())){
				cfg = new Configuration(mProj, children[i], version, isPreference);
				ManagedBuildManager.performValueHandlerEvent(cfg, IManagedOptionValueHandler.EVENT_OPEN);
				break;
			}
		}
		return cfg;
	}

	protected CConfigurationData loadPreferences(ICConfigurationDescription cfgDescription) throws CoreException {
		Configuration cfg = load(cfgDescription, null, true);
		cfg = updatePreferenceOnLoad(cfg, cfgDescription);
		cfg.setConfigurationDescription(cfgDescription);
		return cfg.getConfigurationData();
	}

	public static Configuration getClearPreference(String id) {
		Configuration cfg = createEmptyPrefConfiguration(id, null);
		cfg = adjustPreferenceConfig(cfg);
		return cfg;
	}

	private static Configuration updatePreferenceOnLoad(Configuration cfg, ICConfigurationDescription cfgDescription) {
		if(cfg == null) {
			cfg = createEmptyPrefConfiguration(cfgDescription.getId(), cfgDescription.getName());
		}
		cfg = adjustPreferenceConfig(cfg);
		return cfg;
	}

	private static Configuration adjustPreferenceConfig(Configuration cfg) {
		LanguageManager mngr = LanguageManager.getInstance();
		ILanguageDescriptor dess[] = mngr.getLanguageDescriptors();
		Map<String, ILanguageDescriptor[]> map = mngr.getContentTypeIdToLanguageDescriptionsMap();

		IResourceInfo[] rcInfos = cfg.getResourceInfos();
		for(int i = 0; i < rcInfos.length; i++){
			if(rcInfos[i] instanceof IFolderInfo){
				adjustFolderInfo((IFolderInfo)rcInfos[i], dess, new HashMap<Object, ILanguageDescriptor[]>(map));
			}
		}

		return cfg;
	}

	private static void adjustFolderInfo(IFolderInfo info, ILanguageDescriptor dess[], HashMap<Object, ILanguageDescriptor[]> map) {
		IToolChain tch = info.getToolChain();
		Map<String, ILanguageDescriptor> langMap = new HashMap<String, ILanguageDescriptor>();
		for(int i = 0; i < dess.length; i++){
			langMap.put(dess[i].getId(), dess[i]);
		}
		if(PREF_TC_ID.equals(tch.getSuperClass().getId())){
			ITool[] tools = tch.getTools();
			for(int i = 0; i < tools.length; i++){
				Tool tool = (Tool)tools[i];
				IInputType types[] = tool.getAllInputTypes();
				for(int k = 0; k < types.length; k++){
					InputType type = (InputType)types[k];
					String langId = type.getLanguageId(tool);
					if(langId != null){
						ILanguageDescriptor des = langMap.remove(langId);
						if(des != null)
							adjustInputType(tool, type, des);
						continue;
					} else {
						IContentType[] cTypes = type.getSourceContentTypes();
						for(int c = 0; c < cTypes.length; c++){
							IContentType cType = cTypes[c];
							ILanguageDescriptor[] langs = map.remove(cType.getId());
							if(langs != null && langs.length != 0){
								for(int q = 0; q < langs.length; q++){
									langMap.remove(langs[q].getId());
								}

								adjustInputType(tool, type, langs[0]);
							}
						}
					}
				}
			}

			if(!langMap.isEmpty()){
				addTools(tch, langMap, map);
			}
		}
	}

	private static InputType adjustInputType(Tool tool, InputType type, ILanguageDescriptor des) {
		String [] cTypeIds = des.getContentTypeIds();
		String srcIds[] = type.getSourceContentTypeIds();
		String hIds[] = type.getHeaderContentTypeIds();

		Set<String> landTypes = new HashSet<String>(Arrays.asList(cTypeIds));
		landTypes.removeAll(Arrays.asList(srcIds));
		landTypes.removeAll(Arrays.asList(hIds));

		if(landTypes.size() != 0){
			List<String> srcList = new ArrayList<String>();
			srcList.addAll(landTypes);
			type = (InputType)tool.getEditableInputType(type);
			type.setSourceContentTypeIds(srcList.toArray(new String[srcList.size()]));
		}

		if(!des.getId().equals(type.getLanguageId(tool))){
			type = (InputType)tool.getEditableInputType(type);
			type.setLanguageIdAttribute(des.getId());
			type.setLanguageNameAttribute(des.getName());
		}
		return type;
	}

	private static void addTools(IToolChain tc, Map<String, ILanguageDescriptor> langMap, Map<Object, ILanguageDescriptor[]> cTypeToLangMap ){
		ITool extTool = ManagedBuildManager.getExtensionTool(PREF_TOOL_ID);
		List<ILanguageDescriptor> list = new ArrayList<ILanguageDescriptor>(langMap.values());
		ILanguageDescriptor des;
		while(list.size() != 0){
			des = list.remove(list.size() - 1);
			String[] ctypeIds = des.getContentTypeIds();
			boolean addLang = false;
			for(int i = 0; i < ctypeIds.length; i++){
				ILanguageDescriptor[] langs = cTypeToLangMap.remove(ctypeIds[i]);
				if(langs != null && langs.length != 0){
					addLang = true;
					for(int q = 0; q < langs.length; q++){
						list.remove(langs[q]);
					}
				}
			}

			if(addLang){
				String id = ManagedBuildManager.calculateChildId(extTool.getId(), null);
				String name = des.getName();
				Tool tool = (Tool)tc.createTool(extTool, id, name, false);
				InputType type = (InputType)tool.getInputTypes()[0];
				type = (InputType)tool.getEditableInputType(type);
				type.setSourceContentTypes(des.getContentTypes());
				type.setLanguageNameAttribute(des.getName());
				type.setName(des.getName());
				type.setLanguageIdAttribute(des.getId());
			}
		}
	}


	private static Configuration createEmptyPrefConfiguration(String id, String name) {
		Configuration extCfg = (Configuration)ManagedBuildManager.getExtensionConfiguration(PREF_CFG_ID);
		Configuration emptyPrefCfg = null;
		if(extCfg != null){
			if(id == null)
				id = ManagedBuildManager.calculateChildId(extCfg.getId(), null);
			if(name == null)
				name = extCfg.getName();
			emptyPrefCfg = new Configuration(null, extCfg, id, false, true, true);
			emptyPrefCfg.setName(name);
			emptyPrefCfg.setPerRcTypeDiscovery(false);
		}

		return emptyPrefCfg;
	}

	@Override
	public CConfigurationData loadConfiguration(ICConfigurationDescription cfgDescription, IProgressMonitor monitor) throws CoreException {
		if(cfgDescription.isPreferenceConfiguration()) {
			return loadPreferences(cfgDescription);
		}

		IManagedBuildInfo info = getBuildInfo(cfgDescription);
		Configuration cfg = load(cfgDescription, (ManagedProject)info.getManagedProject(), false);

		if (cfg != null) {
			IProject project = cfgDescription.getProjectDescription().getProject();
			cfg.setConfigurationDescription(cfgDescription);
			info.setValid(true);
			setPersistedFlag(cfgDescription);
			cacheNaturesIdsUsedOnCache(cfgDescription);
			// Update the ManagedBuildInfo in the ManagedBuildManager map. Doing this creates a barrier for subsequent
			// ManagedBuildManager#getBuildInfo(...) see Bug 305146 for more
			ManagedBuildManager.setLoaddedBuildInfo(project, info);

			if (cfgDescription instanceof ILanguageSettingsProvidersKeeper) {
				String[] defaultIds = cfg.getDefaultLanguageSettingsProviderIds();
				if (defaultIds != null) {
					((ILanguageSettingsProvidersKeeper) cfgDescription).setDefaultLanguageSettingsProvidersIds(defaultIds);
				}
			}
			
			return cfg.getConfigurationData();
		}
		return null;
	}

	private boolean isPersistedCfg(ICConfigurationDescription cfgDescription) {
		return cfgDescription.getSessionProperty(CFG_PERSISTED_PROPERTY) != null;
	}

	@Override
	public void settingsChanged(SettingsChangeEvent event) {
		BuildLanguageData datas[] = (BuildLanguageData[])event.getRcInfo().getCLanguageDatas();
		IOption option = event.getOption();

		try {
			int type = option.getValueType();
			for(int i = 0; i < datas.length; i++){
				datas[i].optionsChanged(type);
			}
		} catch (BuildException e) {
			ManagedBuilderCorePlugin.log(e);
		}
	}

	@Override
	public void removeConfiguration(ICConfigurationDescription cfgDescription, CConfigurationData data, IProgressMonitor monitor) {
		IConfiguration cfg = ((BuildConfigurationData)data).getConfiguration();
		ManagedBuildManager.performValueHandlerEvent(cfg, IManagedOptionValueHandler.EVENT_CLOSE);
		IManagedBuildInfo info = getBuildInfo(cfgDescription);
		IManagedProject mProj = info.getManagedProject();
		mProj.removeConfiguration(cfg.getId());
	}

	@Override
	public void dataCached(ICConfigurationDescription cfgDescription, CConfigurationData data, IProgressMonitor monitor) {
		BuildConfigurationData cfgData = (BuildConfigurationData)data;
		((Configuration)cfgData.getConfiguration()).setConfigurationDescription(cfgDescription);
		cfgData.clearCachedData();
	}

}
