/* * This file is part of Skript. * * Skript is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Skript 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Skript. If not, see <http://www.gnu.org/licenses/>. * * * Copyright 2011-2014 Peter Güttinger * */ package ch.njol.skript.expressions.base; import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.ScriptLoader; import ch.njol.skript.SkriptAPIException; import ch.njol.skript.classes.Changer; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.classes.Changer.ChangerUtils; import ch.njol.skript.classes.ClassInfo; import ch.njol.skript.lang.DefaultExpression; import ch.njol.skript.lang.Expression; import ch.njol.skript.lang.SkriptParser.ParseResult; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.log.ParseLogHandler; import ch.njol.skript.log.SkriptLogger; import ch.njol.skript.registrations.Classes; import ch.njol.skript.registrations.EventValues; import ch.njol.skript.util.Getter; import ch.njol.skript.util.Utils; import ch.njol.util.Kleenean; /** * A useful class for creating default expressions. It simply returns the event value of the given type. * <p> * This class can be used as default expression with <code>new EventValueExpression<T>(T.class)</code> or extended to make it manually placeable in expressions with: * * <pre> * class MyExpression extends EventValueExpression<SomeClass> { * public MyExpression() { * super(SomeClass.class); * } * // ... * } * </pre> * * @author Peter Güttinger * @see Classes#registerClass(ClassInfo) * @see ClassInfo#defaultExpression(DefaultExpression) * @see DefaultExpression */ public class EventValueExpression<T> extends SimpleExpression<T> implements DefaultExpression<T> { private final Class<? extends T> c; @Nullable private Changer<? super T> changer; private final Map<Class<? extends Event>, Getter<? extends T, ?>> getters = new HashMap<Class<? extends Event>, Getter<? extends T, ?>>(); public EventValueExpression(final Class<? extends T> c) { this(c, null); } public EventValueExpression(final Class<? extends T> c, final @Nullable Changer<? super T> changer) { assert c != null; this.c = c; this.changer = changer; } @Override @Nullable protected T[] get(final Event e) { final T o = getValue(e); if (o == null) return null; @SuppressWarnings("unchecked") final T[] one = (T[]) Array.newInstance(c, 1); one[0] = o; return one; } @SuppressWarnings("unchecked") @Nullable private <E extends Event> T getValue(final E e) { if (getters.containsKey(e.getClass())) { final Getter<? extends T, ? super E> g = (Getter<? extends T, ? super E>) getters.get(e.getClass()); return g == null ? null : g.get(e); } for (final Entry<Class<? extends Event>, Getter<? extends T, ?>> p : getters.entrySet()) { if (p.getKey().isAssignableFrom(e.getClass())) { getters.put(e.getClass(), p.getValue()); return p.getValue() == null ? null : ((Getter<? extends T, ? super E>) p.getValue()).get(e); } } getters.put(e.getClass(), null); return null; } @Override public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) { if (exprs.length != 0) throw new SkriptAPIException(this.getClass().getName() + " has expressions in its pattern but does not override init(...)"); return init(); } @SuppressWarnings("null") @Override public boolean init() { final ParseLogHandler log = SkriptLogger.startParseLogHandler(); try { boolean hasValue = false; final Class<? extends Event>[] es = ScriptLoader.getCurrentEvents(); if (es == null) { assert false; return false; } for (final Class<? extends Event> e : es) { if (getters.containsKey(e)) { hasValue = getters.get(e) != null; continue; } final Getter<? extends T, ?> getter = EventValues.getEventValueGetter(e, c, getTime()); if (getter != null) { getters.put(e, getter); hasValue = true; } } if (!hasValue) { log.printError("There's no " + Classes.getSuperClassInfo(c).getName() + " in " + Utils.a(ScriptLoader.getCurrentEventName()) + " event"); return false; } log.printLog(); return true; } finally { log.stop(); } } @Override public Class<? extends T> getReturnType() { return c; } @Override public boolean isSingle() { return true; } @Override public String toString(final @Nullable Event e, final boolean debug) { if (!debug || e == null) return "event-" + Classes.getSuperClassInfo(c).getName(); return Classes.getDebugMessage(getValue(e)); } @SuppressWarnings("unchecked") @Override @Nullable public Class<?>[] acceptChange(final ChangeMode mode) { Changer<? super T> ch = changer; if (ch == null) changer = ch = (Changer<? super T>) Classes.getSuperClassInfo(c).getChanger(); return ch == null ? null : ch.acceptChange(mode); } @Override public void change(final Event e, final @Nullable Object[] delta, final ChangeMode mode) { final Changer<? super T> ch = changer; if (ch == null) throw new UnsupportedOperationException(); ChangerUtils.change(ch, getArray(e), delta, mode); } @Override public boolean setTime(final int time) { final Class<? extends Event>[] es = ScriptLoader.getCurrentEvents(); if (es == null) { assert false; return false; } for (final Class<? extends Event> e : es) { assert e != null; if (EventValues.doesEventValueHaveTimeStates(e, c)) { super.setTime(time); return true; } } return false; } /** * @return true */ @Override public boolean isDefault() { return true; } }