/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.cdt.core.settings.model.util;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import org.eclipse.cdt.core.model.CoreModelUtil;
public class PatternNameMap {
private static final char[] SPEC_CHARS = new char[]{'*', '?'};
static final String DOUBLE_STAR_PATTERN = "**"; //$NON-NLS-1$
private Map<String, PathSettingsContainer> fChildrenMap;
private Map<StringCharArray, PathSettingsContainer> fPatternMap;
private Collection<PathSettingsContainer> fValues;
private boolean fContainsDoubleStar;
private static class StringCharArray {
private String fString;
private char[] fCharArray;
StringCharArray(String string){
fString = string;
}
char[] getCharArray(){
if(fCharArray == null){
fCharArray = fString.toCharArray();
}
return fCharArray;
}
@Override
public boolean equals(Object obj) {
if(obj == this)
return true;
if(!(obj instanceof StringCharArray))
return false;
return fString.equals(((StringCharArray)obj).fString);
}
@Override
public int hashCode() {
return fString.hashCode();
}
@Override
public String toString() {
return fString;
}
}
private class EmptyIterator implements Iterator<PathSettingsContainer>{
@Override
public boolean hasNext() {
return false;
}
@Override
public PathSettingsContainer next() {
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new IllegalStateException();
}
}
private class ValuesCollection extends AbstractCollection<PathSettingsContainer> {
private class Iter implements Iterator<PathSettingsContainer> {
private Iterator<Entry<String, PathSettingsContainer>> fEntrySetIter;
private Entry<String, PathSettingsContainer> fCur;
Iter (Iterator<Entry<String, PathSettingsContainer>> entryIter){
this.fEntrySetIter = entryIter;
}
@Override
public boolean hasNext() {
return fEntrySetIter.hasNext();
}
@Override
public PathSettingsContainer next() {
fCur = fEntrySetIter.next();
return fCur.getValue();
}
@Override
public void remove() {
fEntrySetIter.remove();
String name = fCur.getKey();
if(DOUBLE_STAR_PATTERN.equals(name)){
fContainsDoubleStar = false;
} else {
removePattern(name);
}
}
}
@Override
public Iterator<PathSettingsContainer> iterator() {
return fChildrenMap != null ? new Iter(fChildrenMap.entrySet().iterator()) : new EmptyIterator();
}
@Override
public int size() {
return PatternNameMap.this.size();
}
@Override
public void clear(){
PatternNameMap.this.clear();
}
@Override
public boolean contains(Object o){
return fChildrenMap != null ? fChildrenMap.containsValue(o) : false;
}
}
public /* PathSettingsContainer */ Object get(String name){
return fChildrenMap != null ? fChildrenMap.get(name) : null;
}
public int size(){
return fChildrenMap != null ? fChildrenMap.size() : 0;
}
public boolean isEmpty(){
return fChildrenMap == null || fChildrenMap.isEmpty();
}
public boolean hasPatterns(){
return fContainsDoubleStar || hasPatternsMap();
}
public boolean hasPatternsMap(){
return (fPatternMap != null && fPatternMap.size() != 0);
}
public List<PathSettingsContainer> getValues(String name){
if(fChildrenMap == null)
return null;
PathSettingsContainer val = fChildrenMap.get(name);
if(hasPatternsMap()){
List<PathSettingsContainer> list;
if(val != null){
list = new ArrayList<PathSettingsContainer>(3);
list.add(val);
} else {
list = null;
}
Map.Entry<PatternNameMap.StringCharArray,PathSettingsContainer> entry;
StringCharArray strCA;
char[] nameCharArray = name.toCharArray();
for(Iterator<Map.Entry<PatternNameMap.StringCharArray,PathSettingsContainer>> iter = fPatternMap.entrySet().iterator(); iter.hasNext();){
entry = iter.next();
strCA = entry.getKey();
if(CoreModelUtil.match(strCA.getCharArray(), nameCharArray, true)){
if(list == null)
list = new ArrayList<PathSettingsContainer>(2);
list.add(entry.getValue());
}
}
return list;
} else if (val != null){
List<PathSettingsContainer> list = new ArrayList<PathSettingsContainer>(1);
list.add(val);
return list;
}
return null;
}
public boolean containsDoubleStar(){
return fContainsDoubleStar;
}
public /* PathSettingsContainer */ Object put(String name, /* PathSettingsContainer */Object value){
return put(name, (PathSettingsContainer)value);
}
private PathSettingsContainer put(String name, PathSettingsContainer value){
if(value == null)
return (PathSettingsContainer)remove(name);
PathSettingsContainer oldValue;
if(fChildrenMap == null){
fChildrenMap = new HashMap<String, PathSettingsContainer>();
oldValue = null;
} else {
oldValue = fChildrenMap.get(name);
}
fChildrenMap.put(name, value);
if(DOUBLE_STAR_PATTERN.equals(name)){
fContainsDoubleStar = true;
} else if(isPatternName(name)){
StringCharArray strCA = new StringCharArray(name);
if(fPatternMap == null)
fPatternMap = new HashMap<StringCharArray, PathSettingsContainer>();
fPatternMap.put(strCA, value);
}
return oldValue;
}
public /* PathSettingsContainer */ Object remove(String name){
if(fChildrenMap != null){
PathSettingsContainer oldVal = fChildrenMap.remove(name);
if(fChildrenMap.size() == 0){
fChildrenMap = null;
fPatternMap = null;
fContainsDoubleStar = false;
} else if(DOUBLE_STAR_PATTERN.equals(name)){
fContainsDoubleStar = false;
} else {
removePattern(name);
}
return oldVal;
}
return null;
}
private void removePattern(String name){
if (fPatternMap != null){
fPatternMap.remove(new StringCharArray(name));
if(fPatternMap.size() == 0)
fPatternMap = null;
}
}
private static boolean hasSpecChars(String str){
for(int i = 0; i < SPEC_CHARS.length; i++){
if(str.indexOf(SPEC_CHARS[i]) != -1)
return true;
}
return false;
}
public static boolean isPatternName(String str){
//TODO: check escape chars
return hasSpecChars(str);
}
public void clear(){
fChildrenMap = null;
fPatternMap = null;
fContainsDoubleStar = false;
}
public Collection<PathSettingsContainer> values(){
if(fValues == null)
fValues = new ValuesCollection();
return fValues;
}
}