package com.github.sommeri.less4j.core.compiler.scopes.local;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.github.sommeri.less4j.utils.ArraysUtils;
import com.github.sommeri.less4j.utils.PubliclyCloneable;
public class KeyListStorage<M, T> implements Cloneable {
private LinkedList<Level<M, T>> levels = new LinkedList<Level<M, T>>();
private LinkedList<ListPlaceholder<M, T>> placeholders = new LinkedList<ListPlaceholder<M, T>>();
public void add(M key, T thing) {
Level<M, T> lastLevel = getLastLevel();
lastLevel.add(key, thing);
}
public void add(M key, List<T> thing) {
Level<M, T> lastLevel = getLastLevel();
lastLevel.add(key, thing);
}
public void add(ListPlaceholder<M, T> placeholder, M key, List<T> thing) {
placeholder.level.add(key, thing);
}
public void add(KeyListStorage<M, T> otherStorage) {
levels.addAll(otherStorage.levels);
placeholders.addAll(otherStorage.placeholders);
}
public boolean contains(M key) {
for (Level<M, T> level : levels) {
if (level.contains(key))
return true;
}
return false;
}
public List<T> getValues(M key) {
LinkedList<T> result = new LinkedList<T>();
for (Level<M, T> level : levels) {
result.addAll(level.getValues(key));
}
return result;
}
public List<T> getAllValues() {
LinkedList<T> result = new LinkedList<T>();
for (Level<M, T> level : levels) {
result.addAll(level.getAllValues());
}
return result;
}
public ListPlaceholder<M, T> createPlaceholder() {
Level<M, T> addLevel = addLevel();
ListPlaceholder<M, T> placeholder = new ListPlaceholder<M, T>(addLevel);
placeholders.add(placeholder);
// add level that will be on top of placeholder
addLevel();
return placeholder;
}
public void addDataToFirstPlaceholder(KeyListStorage<M, T> otherStorage) { // used to be called addToPlaceholder
ListPlaceholder<M, T> placeholder = placeholders.peekFirst();
addDataOnly(placeholder, otherStorage);
}
private void addDataOnly(ListPlaceholder<M, T> placeholder, KeyListStorage<M, T> otherStorage) {
for (Level<M, T> level : otherStorage.levels) {
placeholder.level.addAll(level);
}
}
public void closeFirstPlaceholder() { // used to be called closePlaceholder
placeholders.pop();
}
//REPLACE whatever was stored in placeholder
public void replacePlaceholder(ListPlaceholder<M, T> placeholder, KeyListStorage<M, T> otherStorage) {
//replace in data
ArraysUtils.replace(levels, placeholder.level, otherStorage.levels);
ArraysUtils.replace(placeholders, placeholder, otherStorage.placeholders);
}
private Level<M, T> getLastLevel() {
if (levels.isEmpty()) {
addLevel();
}
Level<M, T> lastLevel = levels.peekLast();
return lastLevel;
}
private Level<M, T> addLevel() {
levels.add(new Level<M, T>());
return levels.peekLast();
}
@Override
public KeyListStorage<M, T> clone() {
try {
@SuppressWarnings("unchecked")
KeyListStorage<M, T> clone = (KeyListStorage<M, T>) super.clone();
clone.levels = ArraysUtils.deeplyClonedLinkedList(levels);
clone.placeholders = new LinkedList<ListPlaceholder<M, T>>();
for (ListPlaceholder<M, T> placeholder : placeholders) {
int index = levels.indexOf(placeholder.level);
Level<M, T> levelClone = clone.levels.get(index);
clone.placeholders.add(new ListPlaceholder<M, T>(levelClone));
}
return clone;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("Impossible state.");
}
}
private static class Level<M, T> implements PubliclyCloneable {
private Map<M, List<T>> storage = new HashMap<M, List<T>>();
public void add(M key, T thing) {
getStoredList(key).add(thing);
}
public void add(M key, List<T> things) {
getStoredList(key).addAll(things);
}
public void addAll(Level<M, T> otherLevel) {
for (Entry<M, List<T>> entry : otherLevel.storage.entrySet()) {
add(entry.getKey(), entry.getValue());
}
}
private List<T> getStoredList(M key) {
List<T> list = storage.get(key);
if (list == null) {
list = new ArrayList<T>();
storage.put(key, list);
}
return list;
}
public boolean contains(M key) {
return storage.containsKey(key);
}
public List<T> getValues(M key) {
return storage.containsKey(key) ? storage.get(key) : new ArrayList<T>();
}
public Collection<T> getAllValues() {
List<T> result = new ArrayList<T>();
for (List<T> list : storage.values()) {
result.addAll(list);
}
return result;
}
@Override
public Level<M, T> clone() {
try {
@SuppressWarnings("unchecked")
Level<M, T> clone = (Level<M, T>) super.clone();
//should I creat also new lists? old versoin have not done that
clone.storage = new HashMap<M, List<T>>(storage);
return clone;
} catch (CloneNotSupportedException e) {
throw new IllegalStateException("Impossible state.");
}
}
}
public static class ListPlaceholder<M, T> {
private final Level<M, T> level;
public ListPlaceholder(Level<M, T> level) {
super();
this.level = level;
}
}
}