package tk.amberide.ide.data.state;
import tk.amberide.ide.data.state.node.FieldState;
import tk.amberide.ide.data.state.node.IState;
import tk.amberide.ide.data.state.node.LazyMemberState;
import tk.amberide.ide.data.state.node.SimpleState;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
public abstract class AbstractStateManager implements IStateManager {
protected final ScopedListMap<IState> states = new ScopedListMap<IState>();
protected final ScopedListMap<Method> listeners = new ScopedListMap<Method>();
protected final HashMap<String, String> macros = new HashMap<String, String>();
public void registerStateOwner(Object ownerObject) {
Object parent = null;
Class owner = ownerObject instanceof Class ? (Class) ownerObject : (parent = ownerObject).getClass();
for (Field f : owner.getDeclaredFields()) {
LazyState lazyState;
State state;
if ((lazyState = f.getAnnotation(LazyState.class)) != null) {
addState(lazyState.scope(), new LazyMemberState(f, lazyState.name(), parent));
} else if (Modifier.isStatic(f.getModifiers())
&& parent == null && (state = f.getAnnotation(State.class)) != null) {
addState(state.value(), new FieldState(f));
}
}
for (Method m : owner.getDeclaredMethods()) {
LazyState lazyState;
if ((lazyState = m.getAnnotation(LazyState.class)) != null) {
addState(lazyState.scope(), new LazyMemberState(m, lazyState.name(), parent));
}
}
}
@Override
public void unregisterStateOwner(Object ownerObject) {
Class owner = ownerObject instanceof Class ? (Class) ownerObject : ownerObject.getClass();
for (Map.Entry<Integer, List<IState>> scope : states.entrySet()) {
List<IState> listenerList = scope.getValue();
for (int i = 0; i != listenerList.size(); i++) {
IState state = listenerList.get(i);
Member member = null;
if (state instanceof FieldState) {
member = ((FieldState) state).getField();
} else if (state instanceof LazyMemberState) {
member = ((LazyMemberState) state).getMember();
}
// The mother of all if statements.
//
// if member is not null:
// if member is static and owner is declaring class
// OR if owner is not a class but owner's class is declaring class:
// remove member from list
if (member != null
&& (member.getDeclaringClass() == owner
|| (!(owner instanceof Class) && owner.getClass() == member.getDeclaringClass()))) {
listenerList.remove(i--);
}
}
}
}
public void loadStates() throws Exception {
for (int sc : Scope.scopeIds()) {
loadStates(sc);
}
}
protected void fireStateLoaded(IState state, int scope) {
List<Method> listenerList = listeners.get(scope);
for (Method m : listenerList) {
try {
if (m.getParameterTypes().length == 2) {
m.invoke(scope, state);
} else if (m.getParameterTypes().length == 1) {
m.invoke(state);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void registerMacro(String macro, String value) {
macros.put(macro, value);
}
public void unregisterMacro(String macro) {
macros.remove(macro);
}
@Override
public void registerStateListener(Class listener) {
for (Method member : listener.getDeclaredMethods()) {
if (Modifier.isStatic(member.getModifiers()) && member.isAnnotationPresent(StateListener.class)) {
int[] scopes = member.getAnnotation(StateListener.class).value();
for (int scope : scopes) {
listeners.get(scope).add(member);
}
}
}
}
@Override
public void unregisterStateListener(Class listener) {
for (Map.Entry<Integer, List<Method>> scope : listeners.entrySet()) {
List<Method> listenerList = scope.getValue();
for (int i = 0; i != listenerList.size(); i++) {
if (listenerList.get(i).getClass() == listener) {
listenerList.remove(i);
}
}
}
}
@Override
public int clearMacros() {
int size = macros.size();
macros.clear();
return size;
}
protected String resolveMacros(String str) {
for (Map.Entry<String, String> macro : macros.entrySet()) {
if (str.contains(macro.getKey())) {
str = str.replace(macro.getKey(), macro.getValue());
}
}
return str;
}
@Override
public IState getState(int scope, String name) {
List<IState> sl = states.get(scope);
for (IState state : sl) {
if (state.getName().equals(name)) {
return state;
}
}
return null;
}
@Override
public void addState(int scope, IState state) {
IState pre = getState(scope, state.getName());
if (pre != null) {
removeState(scope, pre);
}
states.get(scope).add(state);
}
@Override
public void addState(int scope, String key, Object value) {
addState(scope, new SimpleState(key, value));
}
@Override
public void removeState(int scope, String key) {
List<IState> stateScope = states.get(scope);
for (int i = 0; i != stateScope.size(); i++) {
if (stateScope.get(i).getName().equals(key)) {
stateScope.remove(i);
}
}
}
@Override
public void removeState(int scope, IState state) {
states.get(scope).remove(state);
}
@Override
public void addStates(int scope, Collection<IState> statesGroup) {
states.get(scope).addAll(statesGroup);
}
@Override
public void clearStates(int scope) {
states.get(scope).clear();
}
@Override
public void clearStates() {
states.clear();
}
@Override
public List<IState> getStates(int scope) {
return states.get(scope);
}
public void emitStates() throws Exception {
for (int scope : states.keySet()) {
emitStates(scope);
}
}
protected static class ScopedListMap<V> extends HashMap<Integer, List<V>> {
@Override
public List<V> get(Object key) {
Scope.validateScope((Integer) key);
if (super.get(key) == null) {
put((Integer) key, new ArrayList<V>());
}
return super.get(key);
}
}
}