package com.tesora.dve.common;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public final class MultiMap<K, V> {
private final Map<K, Collection<V>> backing;
private final CollectionFactory<V> valueStorageFactory;
public MultiMap(final MapFactory<K, Collection<V>> mapFactory, final CollectionFactory<V> valueStorageFactory) {
this.backing = mapFactory.create();
this.valueStorageFactory = valueStorageFactory;
}
public MultiMap(final MapFactory<K, Collection<V>> mapFactory) {
this(mapFactory, new ArrayListFactory<V>());
}
public MultiMap(final CollectionFactory<V> valueStorageFactory) {
this(new LinkedHashMapFactory<K, Collection<V>>(), valueStorageFactory);
}
public MultiMap() {
this(new LinkedHashMapFactory<K, Collection<V>>(), new ArrayListFactory<V>());
}
public boolean isEmpty() {
return backing.isEmpty();
}
public boolean containsKey(K key) {
return backing.containsKey(key);
}
public Collection<V> get(final K key) {
return backing.get(key);
}
public boolean put(final K key, final V value) {
final Collection<V> valueStorage = locateInternalValueStorage(key);
return valueStorage.add(value);
}
public boolean putAll(final K key, final Collection<V> values) {
final Collection<V> valueStorage = locateInternalValueStorage(key);
return valueStorage.addAll(values);
}
public void putAll(final MultiMap<K, V> other) {
for (final K key : other.keySet()) {
final Collection<V> valueStorage = locateInternalValueStorage(key);
valueStorage.addAll(other.get(key));
}
}
private Collection<V> locateInternalValueStorage(final K key) {
Collection<V> valueStorage = backing.get(key);
if (valueStorage == null) {
valueStorage = valueStorageFactory.create();
backing.put(key, valueStorage);
}
return valueStorage;
}
public boolean contains(final K key, final V value) {
final Collection<V> valueStorage = get(key);
if ((valueStorage != null) && (!valueStorage.isEmpty())) {
return valueStorage.contains(value);
}
return false;
}
public boolean remove(final K key, final V value) {
final Collection<V> valueStorage = get(key);
if (valueStorage == null) {
return false;
} else if (valueStorage.isEmpty()) {
backing.remove(key);
return false;
}
final boolean removed = valueStorage.remove(value);
if (valueStorage.isEmpty()) {
backing.remove(key);
return true;
}
return removed;
}
public boolean remove(final K key) {
final Collection<V> valueStorage = get(key);
if (valueStorage == null) {
return false;
} else if (valueStorage.isEmpty()) {
backing.remove(key);
return false;
}
backing.remove(key);
return true;
}
public void clear() {
backing.clear();
}
public Set<K> keySet() {
return backing.keySet();
}
public Collection<V> values() {
final Collection<V> values = valueStorageFactory.create();
for (final Collection<V> valueStorage : backing.values()) {
values.addAll(valueStorage);
}
return values;
}
}