package com.github.sommeri.less4j.core.compiler.scopes.local; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import com.github.sommeri.less4j.utils.ArraysUtils; import com.github.sommeri.less4j.utils.PubliclyCloneable; public class KeyValueStorage<M, T> implements Cloneable { private LinkedList<Level<M, T>> levels = new LinkedList<Level<M, T>>(); private LinkedList<ValuePlaceholder<M, T>> placeholders = new LinkedList<ValuePlaceholder<M, T>>(); public int size() { return levels.size(); } public void add(M key, T thing) { Level<M, T> lastLevel = getLastLevel(); lastLevel.add(key, thing); } public void add(KeyValueStorage<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 T getValue(M key) { Iterator<Level<M, T>> di = levels.descendingIterator(); while (di.hasNext()) { Level<M, T> level = di.next(); if (level.contains(key)) return level.getValue(key); } return null; } public void remove(M key) { Iterator<Level<M, T>> di = levels.descendingIterator(); while (di.hasNext()) { Level<M, T> level = di.next(); if (level.contains(key)) level.remove(key); } } public Set<Entry<M, T>> getAllEntries() { Set<Entry<M, T>> result = new HashSet<Entry<M,T>>(); Iterator<Level<M, T>> iterator = levels.descendingIterator(); while (iterator.hasNext()) { Level<M, T> level = iterator.next(); result.addAll(level.getAllEntries()); } return result; } public ValuePlaceholder<M, T> createPlaceholder() { Level<M, T> addLevel = addLevel(); ValuePlaceholder<M, T> placeholder = new ValuePlaceholder<M, T>(addLevel); placeholders.add(placeholder); // add level that will be on top of placeholder addLevel(); return placeholder; } public void addDataToFirstPlaceholder(KeyValueStorage<M, T> otherStorage) { // used to be called addToPlaceholder ValuePlaceholder<M, T> placeholder = placeholders.peekFirst(); addDataOnly(placeholder, otherStorage); } private void addDataOnly(ValuePlaceholder<M, T> placeholder, KeyValueStorage<M, T> otherStorage) { for (Level<M, T> level : otherStorage.levels) { placeholder.level.addAll(level); } } public void addToFirstPlaceholder(M key, T value) { ValuePlaceholder<M, T> placeholder = placeholders.peekFirst(); placeholder.level.add(key, value); } public void closeFirstPlaceholder() { // used to be called closePlaceholder placeholders.pop(); } //REPLACE whatever was stored in placeholder public void replacePlaceholder(ValuePlaceholder<M, T> placeholder, KeyValueStorage<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 KeyValueStorage<M, T> clone() { try { @SuppressWarnings("unchecked") KeyValueStorage<M, T> clone = (KeyValueStorage<M, T>) super.clone(); clone.levels = ArraysUtils.deeplyClonedLinkedList(levels); clone.placeholders = new LinkedList<ValuePlaceholder<M, T>>(); for (ValuePlaceholder<M, T> placeholder : placeholders) { int index = levels.indexOf(placeholder.level); Level<M, T> levelClone = clone.levels.get(index); clone.placeholders.add(new ValuePlaceholder<M, T>(levelClone)); } return clone; } catch (CloneNotSupportedException e) { throw new IllegalStateException("Impossible state."); } } @Override public String toString() { return levels.toString(); } private static class Level<M, T> implements PubliclyCloneable { private Map<M, T> storage = new HashMap<M, T>(); public void add(M key, T thing) { storage.put(key, thing); } public Collection<Entry<M, T>> getAllEntries() { return storage.entrySet(); } public T getValue(M key) { return storage.get(key); } public void remove(M key) { storage.remove(key); } public boolean contains(M key) { return storage.containsKey(key); } public void addAll(Level<M, T> otherLevel) { for (Entry<M, T> entry : otherLevel.storage.entrySet()) { add(entry.getKey(), entry.getValue()); } } @Override public Level<M, T> clone() { try { @SuppressWarnings("unchecked") Level<M, T> clone = (Level<M, T>) super.clone(); clone.storage = new HashMap<M, T>(storage); return clone; } catch (CloneNotSupportedException e) { throw new IllegalStateException("Impossible state."); } } @Override public String toString() { return "Level: " + storage.toString(); } } public static class ValuePlaceholder<M, T> { private final Level<M, T> level; public ValuePlaceholder(Level<M, T> level) { super(); this.level = level; } } }