/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2016 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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/>.
*/
package fr.gael.dhus.util.functional.collect;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* A read-only Map backed by a two ArrayLists and a HashMap, with predictable iteration order.
* All iterators returned by {@code values().iterator()}, {@code keySet().iterator()} and
* {@code entrySet().iterator()} are sorted.
* @param <K> Key type.
* @param <V> Value type.
*/
public class SortedMap<K, V> implements Map<K, V>
{
private final Map<K,V> index;
private final List<V> iterableValues;
private final List<K> iterableKeys;
/**
* Creates a new SortedMap.
* @param to_sort map to sort.
* @param cmp Comparator on values of `to_sort` map.
*/
public SortedMap(Map<K,V> to_sort, final Comparator<? super V> cmp)
{
Objects.requireNonNull(to_sort, "Map to sort param must not be null");
Objects.requireNonNull(cmp, "comparator param must not be null");
this.index = to_sort;
ArrayList<V> iterable_values = new ArrayList<>(to_sort.size());
iterable_values.addAll(to_sort.values());
Collections.sort(iterable_values, cmp);
this.iterableValues = Collections.unmodifiableList(iterable_values);
ArrayList<K> iterable_keys = new ArrayList<>(to_sort.size());
iterable_keys.addAll(to_sort.keySet());
Collections.sort(iterable_keys, new Comparator<K>()
{
@Override
public int compare(K o1, K o2)
{
return cmp.compare(index.get(o1), index.get(o2));
}
});
this.iterableKeys = Collections.unmodifiableList(iterable_keys);
}
@Override
public int size()
{
return index.size();
}
@Override
public boolean isEmpty()
{
return index.isEmpty();
}
@Override
public boolean containsKey(Object key)
{
return index.containsKey(key);
}
@Override
public boolean containsValue(Object value)
{
return iterableValues.contains(value);
}
@Override
public V get(Object key)
{
return index.get(key);
}
@Override
public Set<K> keySet()
{
return new AbstractSet()
{
@Override
public Iterator iterator()
{
return iterableKeys.iterator();
}
@Override
public int size()
{
return iterableKeys.size();
}
};
}
@Override
public Collection<V> values()
{
return Collections.unmodifiableList(iterableValues);
}
@Override
public Set<Entry<K, V>> entrySet()
{
return new AbstractSet()
{
@Override
public Iterator iterator()
{
final Iterator<K> it = iterableKeys.iterator();
return new Iterator()
{
@Override
public boolean hasNext()
{
return it.hasNext();
}
@Override
public Object next()
{
K key = it.next();
return new AbstractMap.SimpleImmutableEntry<>(key, index.get(key));
}
@Override
public void remove()
{
throw new UnsupportedOperationException("Read only.");
}
};
}
@Override
public int size()
{
return index.size();
}
};
}
// vvvv Not Implemented (Read Only). vvvv
@Override
public V put(K key, V value)
{
throw new UnsupportedOperationException("Read-Only.");
}
@Override
public V remove(Object key)
{
throw new UnsupportedOperationException("Read-Only.");
}
@Override
public void putAll(Map<? extends K, ? extends V> m)
{
throw new UnsupportedOperationException("Read-Only.");
}
@Override
public void clear()
{
throw new UnsupportedOperationException("Read-Only.");
}
}