/*******************************************************************************
 * 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
 * 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<CDataObject>();
				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<String, String>(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<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;
	}
}
