package org.tmatesoft.svn.core.internal.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.tmatesoft.svn.core.SVNProperty;
import org.tmatesoft.svn.core.internal.wc.SVNObjectsPool;
import org.tmatesoft.svn.core.wc.SVNRevision;
public class SVNEntryHashMap extends SVNHashMap {
private static final long serialVersionUID = 1L;
private static final Set<String> ourNonPoolableKeys = new HashSet<String>();
private static final Set<String> ourURLKeys = new HashSet<String>();
static {
ourNonPoolableKeys.add(SVNProperty.CHECKSUM);
ourNonPoolableKeys.add(SVNProperty.COMMITTED_DATE);
ourNonPoolableKeys.add(SVNProperty.TEXT_TIME);
ourNonPoolableKeys.add(SVNProperty.WORKING_SIZE);
ourNonPoolableKeys.add(SVNProperty.LOCK_CREATION_DATE);
ourNonPoolableKeys.add(SVNProperty.PROP_TIME);
ourURLKeys.add(SVNProperty.URL);
ourURLKeys.add(SVNProperty.COPYFROM_URL);
ourURLKeys.add(SVNProperty.FILE_EXTERNAL_PATH);
ourURLKeys.add(SVNProperty.REPOS);
}
private SVNObjectsPool myObjectsPool;
public SVNEntryHashMap(SVNObjectsPool pool) {
this(null, pool);
}
public SVNEntryHashMap(Map<?, ?> map, SVNObjectsPool pool) {
myObjectsPool = pool;
init();
putAll(map);
}
@Override
public Object put(Object key, Object value) {
key = getObjectFromPool(key);
return super.put(key, value);
}
@Override
protected TableEntry createTableEntry(Object key, Object value, int hash) {
return new PooledTableEntry(myObjectsPool, key, value, hash);
}
private Object getObjectFromPool(Object value) {
if (myObjectsPool != null) {
return myObjectsPool.getObject(value);
}
return value;
}
private static boolean isNonPoolableKey(Object key) {
return ourNonPoolableKeys.contains(key);
}
private static boolean isURLKey(Object key) {
return ourURLKeys.contains(key);
}
protected static class PooledTableEntry extends SVNHashMap.TableEntry {
private SVNObjectsPool myObjectsPool;
public PooledTableEntry(SVNObjectsPool pool, Object key, Object value, int hash) {
myObjectsPool = pool;
init(key, value, hash);
}
public Object setValue(Object value) {
Object valueForPool = getPoolValue(super.getKey(), value);
return super.setValue(valueForPool);
}
public Object getValue() {
return getRealValue(super.getValue());
}
private Object getRealValue(Object value) {
if (value instanceof StringAsArray) {
return ((StringAsArray) value).toString();
}
return value;
}
private Object getPoolValue(Object key, Object value) {
if (myObjectsPool != null) {
if (value instanceof String) {
if (isURLKey(key)) {
return new StringAsArray((String) value, myObjectsPool);
} else if (!isNonPoolableKey(key)) {
return myObjectsPool.getObject(value);
}
return value;
} else if (value instanceof String[]) {
String[] array = (String[]) value;
for (int i = 0; i < array.length; i++) {
array[i] = (String) myObjectsPool.getObject(array[i]);
}
} else if (value instanceof SVNRevision) {
return myObjectsPool.getObject(value);
}
}
return value;
}
}
private static Object[] split(String url) {
ArrayList<String> segments = new ArrayList<String>();
int startIndex = 0;
int count = 0;
for(int i = 0; i < url.length(); i++) {
char ch = url.charAt(i);
if (ch != '/' && i > 0 && url.charAt(i - 1) == '/') {
count++;
if (count > 3) {
segments.add(url.substring(startIndex, i));
startIndex = i;
}
}
}
if (startIndex < url.length()) {
segments.add(url.substring(startIndex));
}
return segments.toArray();
}
private static class StringAsArray {
private Object[] segments;
private int hashCode;
public StringAsArray(String str, SVNObjectsPool pool) {
hashCode = str.hashCode();
segments = split(str);
for (int i = 0; i < segments.length; i++) {
segments[i] = pool.getObject(segments[i]);
}
}
public boolean equals(Object other) {
if (other instanceof StringAsArray) {
return Arrays.equals(segments, ((StringAsArray) other).segments);
}
return false;
}
public int hashCode() {
return hashCode;
}
public String toString() {
StringBuffer str = new StringBuffer();
for (int i = 0; i < segments.length; i++) {
str.append((String) segments[i]);
}
return str.toString();
}
}
}