/*******************************************************************************
* Copyright (c) 2007, 2011 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
* Christian Walther (Indel AG) - [335344] changing language IDs
*******************************************************************************/
package org.eclipse.cdt.internal.core.settings.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.cdt.core.settings.model.CExternalSetting;
import org.eclipse.cdt.core.settings.model.ICExternalSetting;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.util.CDataUtil;
import org.eclipse.cdt.core.settings.model.util.EntryContentsKey;
import org.eclipse.cdt.core.settings.model.util.EntryNameKey;
import org.eclipse.cdt.core.settings.model.util.KindBasedStore;
class CExternalSettinsDeltaCalculator {
static private CExternalSettinsDeltaCalculator fInstance;
private CExternalSettinsDeltaCalculator(){
}
public static CExternalSettinsDeltaCalculator getInstance(){
if(fInstance == null)
fInstance = new CExternalSettinsDeltaCalculator();
return fInstance;
}
static class ExtSettingsDelta {
CExternalSetting fSetting;
boolean fAdded;
KindBasedStore<ICSettingEntry[][]> fEntryChangeStore;
ExtSettingsDelta(CExternalSetting setting){
fSetting = setting;
fEntryChangeStore = new KindBasedStore<ICSettingEntry[][]>(false);
}
ExtSettingsDelta(CExternalSetting setting, boolean added){
fSetting = setting;
fAdded = added;
}
boolean isChange(){
return fEntryChangeStore != null;
}
boolean isAdded(){
return fAdded;
}
CExternalSetting getSetting(){
return fSetting;
}
ICSettingEntry[][] getEntriesDelta(int kind){
if(fEntryChangeStore != null)
return fEntryChangeStore.get(kind);
ICSettingEntry [] entries = fSetting.getEntries(kind);
if(entries == null || entries.length == 0)
return null;
ICSettingEntry[][] delta = new ICSettingEntry[2][];
if(fAdded)
delta[0] = entries;
else
delta[1] = entries;
return delta;
}
ICSettingEntry[][] getEntriesDelta(){
int kinds[] = KindBasedStore.getLanguageEntryKinds();
List<ICSettingEntry> added = new ArrayList<ICSettingEntry>();
List<ICSettingEntry> removed = new ArrayList<ICSettingEntry>();
for (int kind : kinds) {
ICSettingEntry[][] d = getEntriesDelta(kind);
if(d == null)
continue;
if(d[0] != null){
added.addAll(Arrays.asList(d[0]));
}
if(d[1] != null){
removed.addAll(Arrays.asList(d[1]));
}
}
ICSettingEntry[][] delta = new ICSettingEntry[2][];
if(added.size() != 0){
delta[0] = added.toArray(new ICSettingEntry[added.size()]);
}
if(removed.size() != 0){
delta[1] = removed.toArray(new ICSettingEntry[removed.size()]);
}
return delta;
}
}
static class ExtSettingMapKey {
private ICExternalSetting fSetting;
public ExtSettingMapKey(ICExternalSetting setting){
fSetting = setting;
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof ExtSettingMapKey))
return false;
ExtSettingMapKey other = (ExtSettingMapKey)obj;
return settingsMatch(fSetting, other.fSetting);
}
@Override
public int hashCode() {
return code(fSetting.getCompatibleLanguageIds())
+ code(fSetting.getCompatibleContentTypeIds())
+ code(fSetting.getCompatibleExtensions());
}
private int code(String[] arr){
if(arr == null || arr.length == 0)
return 0;
int code = 0;
for (String str : arr) {
code += str.hashCode();
}
return code;
}
public ICExternalSetting getSetting(){
return fSetting;
}
}
private static ExtSettingsDelta createDelta(CExternalSetting setting1, CExternalSetting setting2){
int kinds[] = KindBasedStore.getAllEntryKinds();
ExtSettingsDelta extDelta = null;
for (int kind : kinds) {
ICSettingEntry entries1[] = setting1.getEntries(kind);
ICSettingEntry entries2[] = setting2.getEntries(kind);
Map<EntryContentsKey, ICSettingEntry> map1 = CDataUtil.fillEntriesMapByContentsKey(new LinkedHashMap<EntryContentsKey, ICSettingEntry>(), entries1);
Map<EntryContentsKey, ICSettingEntry> map2 = CDataUtil.fillEntriesMapByContentsKey(new LinkedHashMap<EntryContentsKey, ICSettingEntry>(), entries2);
Map<EntryContentsKey, ICSettingEntry> map1Copy = new LinkedHashMap<EntryContentsKey, ICSettingEntry>(map1);
// Set set1 = new HashSet(Arrays.asList(entries1));
// Set set2 = new HashSet(Arrays.asList(entries2));
// Set set1Copy = new HashSet(set1);
map1.keySet().removeAll(map2.keySet());
map2.keySet().removeAll(map1Copy.keySet());
ICSettingEntry entriesAdded[] = null, entriesRemoved[] = null;
if(map1.size() != 0)
entriesAdded = map1.values().toArray(new ICSettingEntry[map1.size()]);
if(map2.size() != 0)
entriesRemoved = map2.values().toArray(new ICSettingEntry[map2.size()]);
if(entriesAdded == null && entriesRemoved == null)
continue;
if(extDelta == null){
extDelta = new ExtSettingsDelta(setting1);
}
extDelta.fEntryChangeStore.put(kind, new ICSettingEntry[][]{entriesAdded, entriesRemoved});
}
return extDelta;
}
static boolean settingsMatch(ICExternalSetting setting1, ICExternalSetting setting2) {
if(setting1.equals(setting2))
return true;
return settingsMatch(setting1,
setting2.getCompatibleLanguageIds(),
setting2.getCompatibleContentTypeIds(),
setting2.getCompatibleExtensions());
}
static boolean settingsMatch(ICExternalSetting setting,
String languageIDs[], String contentTypeIDs[], String extensions[]){
if(!Arrays.equals(setting.getCompatibleLanguageIds(), languageIDs))
return false;
if(!Arrays.equals(setting.getCompatibleContentTypeIds(), contentTypeIDs))
return false;
if(!Arrays.equals(setting.getCompatibleExtensions(), extensions))
return false;
return true;
}
private static Map<ExtSettingMapKey, ICExternalSetting> toSettingsKeyMap(ICExternalSetting[] settings){
Map<ExtSettingMapKey, ICExternalSetting> map = new HashMap<ExtSettingMapKey, ICExternalSetting>();
for (ICExternalSetting setting : settings) {
if(map.put(new ExtSettingMapKey(setting), setting) != null)
throw new IllegalArgumentException();
}
return map;
}
ExtSettingsDelta[] getSettingChange(CExternalSetting newSettings[],
CExternalSetting oldSettings[]){
if(newSettings == null || newSettings.length == 0)
return createDeltas(oldSettings, false);
if(oldSettings == null || oldSettings.length == 0)
return createDeltas(newSettings, true);
LinkedList<ExtSettingsDelta> deltaList = new LinkedList<ExtSettingsDelta>();
Map<ExtSettingMapKey, ICExternalSetting> newMap= toSettingsKeyMap(newSettings);
Map<ExtSettingMapKey, ICExternalSetting> oldMap = toSettingsKeyMap(oldSettings);
for (Entry<ExtSettingMapKey, ICExternalSetting> entry : newMap.entrySet()) {
CExternalSetting newSetting = (CExternalSetting)entry.getValue();
CExternalSetting oldSetting = (CExternalSetting)oldMap.remove(entry.getKey());
if(oldSetting == null){
deltaList.addLast(new ExtSettingsDelta(newSetting, true));
} else {
ExtSettingsDelta delta = createDelta(newSetting, oldSetting);
if(delta != null)
deltaList.addLast(delta);
}
}
for (ICExternalSetting oldSettng : oldMap.values()) {
// removals must be prepended to the list so that they are applied before additions,
// otherwise a setting that was just added might be immediately removed again in
// CExternalSettingsDeltaProcessor.applyDelta(ICLanguageSetting, ExtSettingsDelta[], int)
// if the old and new setting only differ in their language sets and these overlap
deltaList.addFirst(new ExtSettingsDelta((CExternalSetting)oldSettng, false));
}
if(deltaList.size() == 0)
return null;
return deltaList.toArray(new ExtSettingsDelta[deltaList.size()]);
}
private static ExtSettingsDelta[] createDeltas(CExternalSetting settings[], boolean added){
if(settings == null || settings.length == 0)
return null;
ExtSettingsDelta deltas[] = new ExtSettingsDelta[settings.length];
for(int i = 0; i < settings.length; i++){
deltas[i] = new ExtSettingsDelta(settings[i], added);
}
return deltas;
}
Set<ICSettingEntry> calculateUpdatedEntries(ICSettingEntry current[], ICSettingEntry added[], ICSettingEntry removed[]){
// EntryComparator comparator = new EntryComparator();
LinkedHashSet<ICSettingEntry> set = new LinkedHashSet<ICSettingEntry>();
set.addAll(Arrays.asList(current));
set.addAll(Arrays.asList(added));
set.removeAll(Arrays.asList(removed));
return set;
}
static ICSettingEntry[][] getAllEntries(ExtSettingsDelta[] deltas, int kind){
if(deltas == null || deltas.length == 0)
return null;
Map<EntryNameKey, ICSettingEntry> addedMap = new LinkedHashMap<EntryNameKey, ICSettingEntry>();
Map<EntryNameKey, ICSettingEntry> removedMap = new LinkedHashMap<EntryNameKey, ICSettingEntry>();
for (ExtSettingsDelta delta : deltas) {
ICSettingEntry[][] change = delta.getEntriesDelta(kind);
if(change == null)
continue;
if(change[0] != null){
CDataUtil.fillEntriesMapByNameKey(addedMap, change[0]);
}
if(change[1] != null){
CDataUtil.fillEntriesMapByNameKey(removedMap, change[1]);
}
removedMap.keySet().removeAll(addedMap.keySet());
}
if(addedMap.size() == 0 && removedMap.size() == 0)
return null;
ICSettingEntry[][] result = new ICSettingEntry[2][];
if(addedMap.size() != 0){
result[0] = addedMap.values().toArray(new ICSettingEntry[addedMap.size()]);
}
if(removedMap.size() != 0){
result[1] = removedMap.values().toArray(new ICSettingEntry[removedMap.size()]);
}
return result;
}
}