/**
* MIT License
*
* Copyright (c) 2017 zgqq
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package mah.mode;
import mah.action.*;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by zgq on 2017-01-09 09:50
*/
public abstract class AbstractMode implements Mode {
private final Map<String, Action> namedActions = new HashMap<>();
private final Map<Class<?>, List<Action>> actionHandlers = new HashMap<>();
private final String name;
private final Lock lock = new ReentrantLock();
private final List<Mode> children = new ArrayList<>();
private final Set<String> excludeActions = new HashSet<>();
public AbstractMode(String name, Mode child) {
this.name = name;
if (children == null) {
throw new ModeException("Parent mode must not be null,child mode is " + getName());
}
this.children.add(child);
}
public AbstractMode(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
private void addNamedAction(Action action) {
namedActions.put(action.getName(), action);
}
public final void registerAction(Action action) {
Class<?> handler = action.getHandler();
if (!(action instanceof NoSourceAction)) {
if (handler == null) {
throw new ActionException("actions must have a handler");
}
List<Action> actions = actionHandlers.get(handler);
if (actions == null) {
actions = new ArrayList<>();
actionHandlers.put(handler, actions);
} else {
if (actions.contains(action)) {
throw new ActionException("Action should be registered once");
}
}
actions.add(action);
}
addNamedAction(action);
}
@Override
public final void updateActionHandler(ActionHandler actionHandler) {
Class<? extends ActionHandler> clazz = actionHandler.getClass();
actionHandlers.forEach((aClass, actions) -> {
if (aClass.isAssignableFrom(clazz)) {
for (Action action : actions) {
ActionManager.getInstance().updateActionHandler(action, actionHandler);
}
}
}
);
}
@Override
public void addChild(Mode mode) {
lock.lock();
try {
if (this.children.contains(mode)) {
throw new IllegalStateException("Child already existed");
}
this.children.add(mode);
} finally {
lock.unlock();
}
}
@Override
public final FindResult findAction(String actionName) {
if (excludeActions.contains(actionName)) {
return new FindResult(null, FindResult.ResultType.EXCLUDED);
}
Action action = dfsAction(actionName);
if (action == null) {
return new FindResult(action, FindResult.ResultType.NOT_FOUND);
} else {
return new FindResult(action, FindResult.ResultType.FOUND);
}
}
@Nullable
private Action dfsAction(String actionName) {
Action action = namedActions.get(actionName);
if (action != null) {
return action;
}
for (Mode child : children) {
AbstractMode abstractChild = (AbstractMode) child;
action = abstractChild.dfsAction(actionName);
if (action != null) {
return action;
}
}
return null;
}
@Override
public void excludeAction(String actionName) {
excludeActions.add(actionName);
}
@Override
public void trigger() {
ModeManager.getInstance().triggerMode(this);
}
@Override
public List<Mode> getChildren() {
lock.lock();
try {
return Collections.unmodifiableList(children);
} finally {
lock.unlock();
}
}
}