/*******************************************************************************
 * Copyright (c) 2007, 2013 Intel 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:
 * Intel Corporation - Initial API and implementation
 * James Blackburn (Broadcom Corp.)
 *******************************************************************************/
package org.eclipse.cdt.internal.core.settings.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.cdtvariables.ICdtVariablesContributor;
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.settings.model.CConfigurationStatus;
import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent;
import org.eclipse.cdt.core.settings.model.ICBuildSetting;
import org.eclipse.cdt.core.settings.model.ICConfigExtensionReference;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICExternalSetting;
import org.eclipse.cdt.core.settings.model.ICFileDescription;
import org.eclipse.cdt.core.settings.model.ICFolderDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICResourceDescription;
import org.eclipse.cdt.core.settings.model.ICSettingBase;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.ICSourceEntry;
import org.eclipse.cdt.core.settings.model.ICStorageElement;
import org.eclipse.cdt.core.settings.model.ICTargetPlatformSetting;
import org.eclipse.cdt.core.settings.model.WriteAccessException;
import org.eclipse.cdt.core.settings.model.extension.CBuildData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationData;
import org.eclipse.cdt.core.settings.model.extension.CConfigurationDataProvider;
import org.eclipse.cdt.core.settings.model.extension.CDataObject;
import org.eclipse.cdt.core.settings.model.extension.CFileData;
import org.eclipse.cdt.core.settings.model.extension.CFolderData;
import org.eclipse.cdt.core.settings.model.extension.CLanguageData;
import org.eclipse.cdt.core.settings.model.extension.CResourceData;
import org.eclipse.cdt.core.settings.model.extension.CTargetPlatformData;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.core.settings.model.util.PathSettingsContainer;
import org.eclipse.cdt.internal.core.settings.model.xml.InternalXmlStorageElement;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;

/**
 * The writable configuration description.
 *
 * @see ICConfigurationDescription
 * @see CConfigurationDescriptionCache
 * @see CProjectDescriptionEvent
 */
public class CConfigurationDescription extends CDataProxyContainer
		implements ICConfigurationDescription, IProxyFactory, IInternalCCfgInfo, ILanguageSettingsProvidersKeeper {
	private CfgProxyCache fCache;
	//	private ProxyProvider fFileProxyProvider;
	//	private ProxyProvider fFolderProxyProvider;
	//	private ProxyProvider fRcProxyProvider;
	private PathSettingsContainer fPathContainer;
	private ResourceDescriptionHolder fRcHolder;
	private CConfigurationSpecSettings fCfgSpecSettings;
	private CConfigurationDescriptionCache fCfgCache;
	private boolean fIsPreference = false;

	CConfigurationDescription(CConfigurationData data, ICDataProxyContainer cr) throws CoreException {
		this(data, null, cr);
	}

	CConfigurationDescription(CConfigurationData data, String buildSystemId, ICDataProxyContainer cr)
			throws CoreException {
		super(data, cr, null);
		if (!(cr instanceof ICProjectDescription))
			fIsPreference = true;

		if (data instanceof CConfigurationDescriptionCache)
			fCfgCache = (CConfigurationDescriptionCache) data;

		setConfiguration(this);
		if (buildSystemId != null)
			getSpecSettings().setBuildSystemId(buildSystemId);

	}

	/**
	 * Creating a new configuration as a copy of an existing base CConfigurationDescription
	 *
	 * @param id
	 * @param name
	 * @param base
	 * @param projectDes
	 * @throws CoreException
	 */
	CConfigurationDescription(String id, String name, ICConfigurationDescription base, CProjectDescription projectDes)
			throws CoreException {
		super(null, projectDes, null);

		setConfiguration(this);
		internalSetId(id);

		CConfigurationSpecSettings baseSettings = ((CConfigurationDescription) base).getSpecSettings();
		InternalXmlStorageElement baseRootEl = (InternalXmlStorageElement) baseSettings.getRootStorageElement();
		ICStorageElement newRootEl = CProjectDescriptionManager.getInstance().createStorage(projectDes.getStorageBase(),
				id, baseRootEl);

		fCfgSpecSettings = new CConfigurationSpecSettings(this, baseSettings, newRootEl);
		fCfgSpecSettings.setId(id);
		fCfgSpecSettings.setName(name);
		fCfgSpecSettings.serializeId();
		CConfigurationData baseData = ((IInternalCCfgInfo) base).getConfigurationData(false);
		if (baseData instanceof CConfigurationDescriptionCache) {
			baseData = ((CConfigurationDescriptionCache) baseData).getConfigurationData();
		}
		setData(CProjectDescriptionManager.getInstance().createData(this, base, baseData, false, null));
	}

	/**
	 * Converter config constructor.
	 */
	CConfigurationDescription(String id, String name, ICStorageElement el, CProjectDescription projectDes)
			throws CoreException {
		super(null, projectDes, null);

		setConfiguration(this);

		ICStorageElement storage = CProjectDescriptionManager.getInstance().createStorage(projectDes, id);
		fCfgSpecSettings = new CConfigurationSpecSettings(this, storage, el);
		fCfgSpecSettings.setId(id);
		fCfgSpecSettings.setName(name);
		fCfgSpecSettings.setBuildSystemId(CCorePlugin.DEFAULT_PROVIDER_ID);
		CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance();
		CConfigurationData data = mngr.createDefaultConfigData(projectDes.getProject(), id, name,
				PathEntryConfigurationDataProvider.getDataFactory());
		setData(data);
		fCfgSpecSettings.reconcileExtensionSettings(false);
	}

	/**
	 * Preference config constructor.
	 */
	CConfigurationDescription(String id, String name, String bsId, ICStorageElement el, ICDataProxyContainer cr)
			throws CoreException {
		super(null, cr, null);
		fIsPreference = true;

		setConfiguration(this);

		fCfgSpecSettings = new CConfigurationSpecSettings(this, el);
		fCfgSpecSettings.setId(id);
		fCfgSpecSettings.setName(name);
		fCfgSpecSettings.setBuildSystemId(bsId);

		CConfigurationDataProvider dataProvider = CProjectDescriptionManager.getInstance().getProvider(this);
		CConfigurationData data = dataProvider.loadConfiguration(this, new NullProgressMonitor());
		setData(data);

		if (!fCfgSpecSettings.isLanguageSettingProvidersLoaded()) {
			// default ids would come from the preference configuration, ensure sensible defaults
			String[] defaultIds = ScannerDiscoveryLegacySupport.getDefaultProviderIdsLegacy(this);
			List<ILanguageSettingsProvider> providers = LanguageSettingsManager
					.createLanguageSettingsProviders(defaultIds);
			setDefaultLanguageSettingsProvidersIds(defaultIds);
			setLanguageSettingProviders(providers);
		}
	}

	void doWritable() throws CoreException {
		if (!containsWritableData()) {
			CConfigurationData data = getConfigurationData(false);
			CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache) data;
			data = cache.getConfigurationData();
			setData(CProjectDescriptionManager.getInstance().createData(this, cache, data, true, null));
		}
	}

	//	public CConfigurationDescriptionCache getCache(){
	//		return fCfgCache;
	//	}

	@Override
	public String getId() {
		String id = super.getId();
		if (id == null) {
			try {
				id = getSpecSettings().getId();
			} catch (CoreException e) {
				//TODO: log
			}
		}
		return id;
	}

	@Override
	public String getName() {
		String name = super.getName();
		if (name == null) {
			try {
				name = getSpecSettings().getName();
			} catch (CoreException e) {
				//TODO: log
			}
		}
		return name;
	}

	@Override
	public String getDescription() {
		CConfigurationData data = getConfigurationData(false);
		return data.getDescription();
	}

	@Override
	public CConfigurationData getConfigurationData(boolean write) {
		CConfigurationData data = (CConfigurationData) getData(write);
		if (data == null)
			throw new IllegalStateException();
		return data;
	}

	@Override
	public ICProjectDescription getProjectDescription() {
		if (fIsPreference)
			return null;
		return (ICProjectDescription) getParent();
	}

	public ICResourceDescription[] getResourceDescriptions(int kind) {
		return getRcHolder().getResourceDescriptions(kind);
	}

	@Override
	public ICFolderDescription getRootFolderDescription() {
		return (ICFolderDescription) getRcHolder().getCurrentResourceDescription();
	}

	@Override
	public boolean isActive() {
		if (fIsPreference)
			return false;
		return getProjectDescription().getActiveConfiguration() == this;
	}

	@Override
	public void setActive() throws WriteAccessException {
		if (fIsPreference)
			return;
		getProjectDescription().setActiveConfiguration(this);
	}

	@Override
	public void removeResourceDescription(ICResourceDescription des) throws CoreException {
		CConfigurationData data = getConfigurationData(true);
		IPath path = des.getPath();
		getRcHolder().removeResurceDescription(path);
		data.removeResourceData((CResourceData) ((CDataProxy) des).getData(false));
	}

	@Override
	public final int getType() {
		return ICSettingBase.SETTING_CONFIGURATION;
	}

	@Override
	public CDataProxy createProxy(CDataObject data) {
		switch (data.getType()) {
		case ICSettingBase.SETTING_FOLDER:
			return new CFolderDescription((CFolderData) data, this);
		case ICSettingBase.SETTING_FILE:
			return new CFileDescription((CFileData) data, this);
		case ICSettingBase.SETTING_TARGET_PLATFORM:
			return new CTargetPlatformSetting((CTargetPlatformData) data, this);
		case ICSettingBase.SETTING_BUILD:
			return new CBuildSetting((CBuildData) data, this);

		}
		return null;
	}

	@Override
	protected IProxyProvider createChildProxyProvider() {
		ICDataScope scope = new ICDataScope() {

			@Override
			public CDataObject[] getChildren() {
				CConfigurationData data = getConfigurationData(false);
				List<CDataObject> list = new ArrayList<>();
				CResourceData rcDatas[] = data.getResourceDatas();
				for (int i = 0; i < rcDatas.length; i++) {
					list.add(rcDatas[i]);
				}
				CTargetPlatformData tpData = data.getTargetPlatformData();
				list.add(tpData);
				CBuildData buildData = data.getBuildData();
				list.add(buildData);
				// TODO add other data types
				return list.toArray(new CDataObject[list.size()]);
			}

			@Override
			public boolean isStatic() {
				return !containsWritableData();
			}

		};
		IProxyCache cache = getCfgProxyCache();

		return new ProxyProvider(scope, cache, this);
	}

	protected ResourceDescriptionHolder createHolder(CFolderDescription des) {
		PathSettingsContainer container = des.getPathContainer();
		if (container == null) {
			container = getPathContainer().getChildContainer(des.getPath(), true, true);
			des.setPathContainer(container);
		}
		//TODO: check
		return new ProviderBasedRcDesHolder(getChildrenProxyProvider(), container, false);
	}

	protected ResourceDescriptionHolder createHolder(CFileDescription des) {
		PathSettingsContainer container = des.getPathContainer();
		if (container == null) {
			container = getPathContainer().getChildContainer(des.getPath(), true, true);
			des.setPathContainer(container);
		}
		//TODO: check
		return new ProviderBasedRcDesHolder(getChildrenProxyProvider(), container, false);
	}

	private CfgProxyCache getCfgProxyCache() {
		if (fCache == null)
			fCache = new CfgProxyCache(getPathContainer());
		return fCache;
	}

	private PathSettingsContainer getPathContainer() {
		if (fPathContainer == null)
			fPathContainer = PathSettingsContainer.createRootContainer();
		return fPathContainer;
	}

	private ResourceDescriptionHolder getRcHolder() {
		if (fRcHolder == null)
			fRcHolder = new ProviderBasedRcDesHolder(getChildrenProxyProvider(), getPathContainer(), true);
		return fRcHolder;
	}

	@Override
	public ICResourceDescription getResourceDescription(IPath path, boolean exactPath) {
		return getRcHolder().getResourceDescription(path, exactPath);
	}

	@Override
	public void setDescription(String des) throws WriteAccessException {
		getConfigurationData(true).setDescription(des);
	}

	@Override
	public ICResourceDescription[] getResourceDescriptions() {
		return getResourceDescriptions(ICSettingBase.SETTING_FILE | ICSettingBase.SETTING_FOLDER);
	}

	@Override
	public ICStorageElement getStorage(String id, boolean create) throws CoreException {
		return getSpecSettings().getStorage(id, create);
	}

	@Override
	public ICStorageElement importStorage(String id, ICStorageElement el)
			throws UnsupportedOperationException, CoreException {
		return getSpecSettings().importStorage(id, el);
	}

	@Override
	public void removeStorage(String id) throws CoreException {
		getSpecSettings().removeStorage(id);
	}

	@Override
	public void setReadOnly(boolean readOnly, boolean keepModify) {
		try {
			getSpecSettings().setReadOnly(readOnly, keepModify);
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
	}

	@Override
	public CConfigurationSpecSettings getSpecSettings() throws CoreException {
		if (fCfgSpecSettings == null) {
			if (fCfgCache != null) {
				if (fCfgCache.isInitializing())
					fCfgSpecSettings = fCfgCache.getSpecSettings();
				else {
					fCfgSpecSettings = new CConfigurationSpecSettings(this, fCfgCache.getSpecSettings());
					fCfgCache = null;
				}
			} else {
				fCfgSpecSettings = new CConfigurationSpecSettings(this, (ICStorageElement) null);
			}

			//			fCfgSpecSettings = CProjectDescriptionManager.getInstance().createConfigurationSpecSettings(this);
		} else if (fCfgSpecSettings.getConfigurarion() != this) {
			if (!fCfgCache.isInitializing()) {
				fCfgSpecSettings = new CConfigurationSpecSettings(this, fCfgCache.getSpecSettings());
				fCfgCache = null;
			}
		}
		return fCfgSpecSettings;
	}

	@Override
	public String getBuildSystemId() {
		try {
			return getSpecSettings().getBuildSystemId();
		} catch (CoreException e) {
		}
		return null;
	}

	@Override
	public CConfigurationData getConfigurationData() {
		CConfigurationData data = getConfigurationData(true);
		if (data instanceof CConfigurationDescriptionCache) {
			data = ((CConfigurationDescriptionCache) data).getConfigurationData();
		}
		return data;
	}

	@Override
	public void setConfigurationData(String buildSystemId, CConfigurationData data) throws WriteAccessException {
		String oldId = getId();
		setData(data);
		if (!fIsPreference) {
			((CProjectDescription) getProjectDescription()).updateMap(this, oldId);
		}
		try {
			CConfigurationSpecSettings settings = getSpecSettings();
			settings.setId(data.getId());
			settings.setName(data.getName());
			settings.setBuildSystemId(buildSystemId);
		} catch (CoreException e) {
		}
	}

	@Override
	public boolean isModified() {
		try {
			CConfigurationSpecSettings settings = getSpecSettings();
			if (settings.isModified())
				return true;
		} catch (CoreException e) {
		}
		return !(getConfigurationData(false) instanceof CConfigurationDescriptionCache);
	}

	void removeConfiguration() {
		//		CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance();
		//		CConfigurationData data = getConfigurationData(true);//fCfgCache.getBaseData();
		//
		//		try {
		//			mngr.removeData(this, data);
		//		} catch (CoreException e) {
		//		}

		try {
			getSpecSettings().removeConfiguration();
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
		((CProjectDescription) getProjectDescription()).configurationRemoved(this);
		remove();
	}

	@Override
	public ICFileDescription createFileDescription(IPath path, ICResourceDescription base)
			throws CoreException, WriteAccessException {
		CConfigurationData data = getConfigurationData(true);
		CResourceData baseRcData = (CResourceData) ((CDataProxy) base).getData(true);
		CFileData createdData = null;
		if (base instanceof ICFileDescription) {
			createdData = data.createFileData(path, (CFileData) baseRcData);
		} else {
			ICFolderDescription baseFo = (ICFolderDescription) base;
			String fileName = path.lastSegment();
			CLanguageSetting baseLang = (CLanguageSetting) baseFo.getLanguageSettingForFile(fileName);
			//			if(baseLang == null){
			//				ICLanguageSetting allSettings[] = baseFo.getLanguageSettings();
			//				if(allSettings.length != 0)
			//					baseLang = (CLanguageSetting)allSettings[0];
			//			}
			CLanguageData baseLangData = baseLang != null ? (CLanguageData) baseLang.getData(false) : null;
			createdData = data.createFileData(path, (CFolderData) baseRcData, baseLangData);
		}

		if (createdData == null)
			throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CConfigurationDescription.0")); //$NON-NLS-1$

		CDataProxy proxy = getChildrenProxyProvider().getProxy(createdData);
		if (!(proxy instanceof ICFileDescription))
			throw ExceptionFactory.createCoreException(
					SettingsModelMessages.getString("CConfigurationDescription.1") + proxy.getClass().getName()); //$NON-NLS-1$

		return (ICFileDescription) proxy;
	}

	@Override
	public ICFolderDescription createFolderDescription(IPath path, ICFolderDescription base)
			throws CoreException, WriteAccessException {
		CConfigurationData data = getConfigurationData(true);
		CFolderData baseRcData = (CFolderData) ((CDataProxy) base).getData(true);
		CFolderData createdData = data.createFolderData(path, baseRcData);

		if (createdData == null)
			throw ExceptionFactory.createCoreException(SettingsModelMessages.getString("CConfigurationDescription.2")); //$NON-NLS-1$

		CDataProxy proxy = getChildrenProxyProvider().getProxy(createdData);
		if (!(proxy instanceof ICFolderDescription))
			throw ExceptionFactory.createCoreException(
					SettingsModelMessages.getString("CConfigurationDescription.3") + proxy.getClass().getName()); //$NON-NLS-1$

		return (ICFolderDescription) proxy;
	}

	@Override
	public ICTargetPlatformSetting getTargetPlatformSetting() {
		CConfigurationData data = getConfigurationData(false);
		return (ICTargetPlatformSetting) getChildrenProxyProvider().getProxy(data.getTargetPlatformData());
	}

	@Override
	public ICFileDescription[] getFileDescriptions() {
		return (ICFileDescription[]) getRcHolder().getResourceDescriptions(ICSettingBase.SETTING_FILE);
	}

	@Override
	public ICFolderDescription[] getFolderDescriptions() {
		return (ICFolderDescription[]) getRcHolder().getResourceDescriptions(ICSettingBase.SETTING_FOLDER);
	}

	@Override
	public ICSourceEntry[] getSourceEntries() {
		CConfigurationData data = getConfigurationData(false);
		ICSourceEntry[] srcEntries = data.getSourceEntries();
		IProject proj = fIsPreference ? null : getProjectDescription().getProject();
		return CDataUtil.adjustEntries(srcEntries, true, proj);
		//		return getRcHolder().calculateSourceEntriesFromPaths(proj, srcPaths);
	}

	@Override
	public void setSourceEntries(ICSourceEntry[] entries) throws CoreException {
		CConfigurationData data = getConfigurationData(true);
		IProject project = fIsPreference ? null : getProjectDescription().getProject();
		if (entries != null) {
			entries = CDataUtil.adjustEntries(entries, false, project);
		}

		data.setSourceEntries(entries);

		if (entries == null) {
			CExternalSettingsManager.getInstance().restoreSourceEntryDefaults(this);
		}
	}

	//	private ICResourceDescription createResourceDescription(IPath path, ICResourceDescription base){
	//		if(fIsPreference)
	//			return null;
	//		IProject project = getProjectDescription().getProject();
	//		IResource rc = project.findMember(path);
	//		ICResourceDescription des = null;
	//		if(rc != null){
	//			if(rc.getType() == IResource.FILE) {
	//				try {
	//					des = createFileDescription(path, base);
	//				} catch (WriteAccessException e) {
	//				} catch (CoreException e) {
	//				}
	//			} else if (rc.getType() == IResource.FOLDER) {
	//				try {
	//					des = createFolderDescription(path, (ICFolderDescription)base);
	//				} catch (WriteAccessException e) {
	//				} catch (CoreException e) {
	//				}
	//			}
	//		}
	//
	//		return des;
	//	}

	@Override
	public Map<String, String> getReferenceInfo() {
		try {
			CConfigurationSpecSettings specs = getSpecSettings();
			return specs.getReferenceInfo();
		} catch (CoreException e) {
		}
		return new HashMap<>(0);
	}

	@Override
	public void setReferenceInfo(Map<String, String> refs) {
		try {
			CConfigurationSpecSettings specs = getSpecSettings();
			specs.setReferenceInfo(refs);
		} catch (CoreException e) {
		}
	}

	@Override
	public ICExternalSetting createExternalSetting(String[] languageIDs, String[] contentTypeIDs, String[] extensions,
			ICSettingEntry[] entries) {
		try {
			return getSpecSettings().createExternalSetting(languageIDs, contentTypeIDs, extensions, entries);
		} catch (CoreException e) {
		}
		return null;
	}

	@Override
	public ICExternalSetting[] getExternalSettings() {
		try {
			return getSpecSettings().getExternalSettings();
		} catch (CoreException e) {
		}
		return null;
	}

	@Override
	public void removeExternalSetting(ICExternalSetting setting) {
		try {
			getSpecSettings().removeExternalSetting(setting);
		} catch (CoreException e) {
		}
	}

	@Override
	public void removeExternalSettings() {
		try {
			getSpecSettings().removeExternalSettings();
		} catch (CoreException e) {
		}
	}

	@Override
	public ICBuildSetting getBuildSetting() {
		CConfigurationData data = getConfigurationData(false);
		return (ICBuildSetting) getChildrenProxyProvider().getProxy(data.getBuildData());
	}

	@Override
	public void setSessionProperty(QualifiedName name, Object value) {
		try {
			getSpecSettings().setSettionProperty(name, value);
		} catch (CoreException e) {
		}
	}

	@Override
	public Object getSessionProperty(QualifiedName name) {
		try {
			return getSpecSettings().getSettionProperty(name);
		} catch (CoreException e) {
		}
		return null;
	}

	@Override
	public ICdtVariablesContributor getBuildVariablesContributor() {
		CConfigurationData data = getConfigurationData(false);
		return data.getBuildVariablesContributor();
	}

	@Override
	public void setName(String name) {
		if (name.equals(getName()))
			return;

		getConfigurationData(true).setName(name);
		try {
			getSpecSettings().setName(name);
		} catch (CoreException e) {
		}
	}

	@Override
	public ICConfigExtensionReference create(String extensionPoint, String extension) throws CoreException {
		return getSpecSettings().create(extensionPoint, extension);
	}

	@Override
	public ICConfigExtensionReference[] get(String extensionPointID) {
		try {
			return getSpecSettings().get(extensionPointID);
		} catch (CoreException e) {
		}
		return new ICConfigExtensionReference[0];
	}

	@Override
	public void remove(ICConfigExtensionReference ext) throws CoreException {
		getSpecSettings().remove(ext);
	}

	@Override
	public void remove(String extensionPoint) throws CoreException {
		getSpecSettings().remove(extensionPoint);
	}

	@Override
	public boolean isPreferenceConfiguration() {
		return fIsPreference;
	}

	@Override
	protected boolean containsWritableData() {
		if (super.containsWritableData())
			return true;

		CConfigurationDescriptionCache data = (CConfigurationDescriptionCache) doGetData();
		return data.isInitializing();
	}

	@Override
	public ICLanguageSetting getLanguageSettingForFile(IPath path, boolean ignoreExcludeStatus) {
		return CProjectDescriptionManager.getLanguageSettingForFile(this, path, ignoreExcludeStatus);
	}

	boolean isExcluded(IPath path) {
		//		if(path.segmentCount() == 0)
		//			return false;
		IProject project = fIsPreference ? null : getProjectDescription().getProject();
		ICSourceEntry[] entries = getResolvedSourceEntries();
		if (project != null)
			path = project.getFullPath().append(path);
		return CDataUtil.isExcluded(path, entries);
	}

	void setExcluded(IPath path, boolean isFolder, boolean exclude) {
		//		if(path.segmentCount() == 0)
		//			return;
		if (isExcluded(path) == exclude)
			return;

		ICSourceEntry[] newEntries = getUpdatedSourceEntries(path, isFolder, exclude);
		if (newEntries != null) {
			try {
				setSourceEntries(newEntries);
			} catch (CoreException e) {
				CCorePlugin.log(e);
			}
		}
	}

	boolean canExclude(IPath path, boolean isFolder, boolean exclude) {
		if (isExcluded(path) == exclude)
			return true;

		return getUpdatedSourceEntries(path, isFolder, exclude) != null;
	}

	private ICSourceEntry[] getUpdatedSourceEntries(IPath path, boolean isFolder, boolean exclude) {
		//		if(path.segmentCount() == 0)
		//			return;
		IProject project = fIsPreference ? null : getProjectDescription().getProject();
		if (project != null)
			path = project.getFullPath().append(path);

		CConfigurationData data = getConfigurationData(false);
		ICSourceEntry[] newEntries = null;
		if (project != null) {
			if (!(data instanceof CConfigurationDescriptionCache)) {
				ICProjectDescription roDes = CProjectDescriptionManager.getInstance().getProjectDescription(project,
						false);
				if (roDes != null) {
					ICConfigurationDescription roCfg = roDes.getConfigurationById(getId());
					if (roCfg != null) {
						newEntries = roCfg.getResolvedSourceEntries();
						if (CDataUtil.isExcluded(path, newEntries) != exclude)
							newEntries = null;
						else
							newEntries = roCfg.getSourceEntries();
					}
				}
			}
		}

		if (newEntries == null) {
			try {
				newEntries = CDataUtil.setExcluded(path, isFolder, exclude, getResolvedSourceEntries(), false);
				if (CDataUtil.isEqual(newEntries, getResolvedSourceEntries()))
					newEntries = null;
			} catch (CoreException e) {
			}
		}

		return newEntries;
	}

	@Override
	public String[] getExternalSettingsProviderIds() {
		try {
			return getSpecSettings().getExternalSettingsProviderIds();
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
		return new String[0];
	}

	@Override
	public void setExternalSettingsProviderIds(String[] ids) {
		try {
			getSpecSettings().setExternalSettingsProviderIds(ids);
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
	}

	@Override
	public void updateExternalSettingsProviders(String[] ids) {
		try {
			getSpecSettings().updateExternalSettingsProviders(ids);
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
	}

	@Override
	public ICSourceEntry[] getResolvedSourceEntries() {
		ICSourceEntry[] entries = getSourceEntries();
		return CDataUtil.resolveEntries(entries, this);
	}

	@Override
	public CConfigurationStatus getConfigurationStatus() {
		CConfigurationData data = getConfigurationData(false);
		CConfigurationStatus status = data.getStatus();
		return status != null ? status : CConfigurationStatus.CFG_STATUS_OK;
	}

	@Override
	public void setLanguageSettingProviders(List<? extends ILanguageSettingsProvider> providers) {
		try {
			getSpecSettings().setLanguageSettingProviders(providers);
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
	}

	@Override
	public List<ILanguageSettingsProvider> getLanguageSettingProviders() {
		try {
			return getSpecSettings().getLanguageSettingProviders();
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
		return null;
	}

	@Override
	public void setDefaultLanguageSettingsProvidersIds(String[] ids) {
		try {
			getSpecSettings().setDefaultLanguageSettingsProvidersIds(ids);
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
	}

	@Override
	public String[] getDefaultLanguageSettingsProvidersIds() {
		try {
			return getSpecSettings().getDefaultLanguageSettingsProvidersIds();
		} catch (CoreException e) {
			CCorePlugin.log(e);
		}
		return null;
	}
}
