/**
* Copyright 2008 - 2015 The Loon Game Engine Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.5
*/
package loon.utils.reply;
public abstract class AbstractValue<T> extends Bypass implements VarView<T>
{
@Override public <M> VarView<M> map (final Function<? super T, M> func) {
final AbstractValue<T> outer = this;
return new MappedValue<M>() {
@Override public M get () {
return func.apply(outer.get());
}
@Override public String toString () {
return outer + ".map(" + func + ")";
}
@Override protected Connection connect () {
return outer.connect(new Listener<T>() {
@Override public void onChange (T value, T ovalue) {
notifyChange(func.apply(value), func.apply(ovalue));
}
});
}
};
}
@Override public <M> VarView<M> flatMap (
final Function<? super T, ? extends VarView<M>> func) {
final AbstractValue<T> outer = this;
final VarView<? extends VarView<M>> mapped = map(func);
return new MappedValue<M>() {
private Connection conn;
@Override public M get () {
return mapped.get().get();
}
@Override public String toString () {
return outer + ".flatMap(" + func + ")";
}
@Override protected Connection connect () {
conn = mapped.connect(new UnitPort() {
public void onEmit () { reconnect(); }
});
return mapped.get().connect(new Listener<M>() {
@Override public void onChange (M value, M ovalue) {
notifyChange(value, ovalue);
}
});
}
@Override protected void disconnect () {
super.disconnect();
if (conn != null) conn.close();
}
};
}
@Override public Connection connect (Listener<? super T> listener) {
return addConnection(listener);
}
@Override public Connection connectNotify (Listener<? super T> listener) {
Connection conn = connect(listener);
try {
listener.onChange(get(), null);
return conn;
} catch (RuntimeException re) {
conn.close();
throw re;
} catch (Error e) {
conn.close();
throw e;
}
}
@Override public Connection connect (ActView.Listener<? super T> listener) {
return connect(wrap(listener));
}
@Override public Connection connectNotify (ActView.Listener<? super T> listener) {
return connectNotify(wrap(listener));
}
private static <T> Listener<T> wrap (final ActView.Listener<? super T> listener) {
return new Listener<T>() {
public void onChange (T newValue, T oldValue) {
listener.onEmit(newValue);
}
};
}
@Override public Connection connect (Port<? super T> port) {
return connect((Listener<? super T>)port);
}
@Override public Connection connectNotify (Port<? super T> port) {
return connectNotify((Listener<? super T>)port);
}
@Override public void disconnect (Listener<? super T> listener) {
removeConnection(listener);
}
@Override public int hashCode () {
T value = get();
return (value == null) ? 0 : value.hashCode();
}
@Override public boolean equals (Object other) {
if (other == null) return false;
if (other.getClass() != getClass()) return false;
T value = get();
@SuppressWarnings("unchecked") T ovalue = ((AbstractValue<T>)other).get();
return areEqual(value, ovalue);
}
@Override public String toString () {
String cname = getClass().getName();
return cname.substring(cname.lastIndexOf(".")+1) + "(" + get() + ")";
}
@Override Listener<T> placeholderListener () {
@SuppressWarnings("unchecked") Listener<T> p = (Listener<T>)Ports.DEF;
return p;
}
protected T updateAndNotifyIf (T value) {
return updateAndNotify(value, false);
}
protected T updateAndNotify (T value) {
return updateAndNotify(value, true);
}
protected T updateAndNotify (T value, boolean force) {
checkMutate();
T ovalue = updateLocal(value);
if (force || !areEqual(value, ovalue)) {
emitChange(value, ovalue);
}
return ovalue;
}
protected void emitChange (T value, T oldValue) {
notifyChange(value, oldValue);
}
protected void notifyChange (T value, T oldValue) {
notify(CHANGE, value, oldValue, null);
}
protected T updateLocal (T value) {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked") protected static final Notifier CHANGE = new Notifier() {
public void notify (Object lner, Object value, Object oldValue, Object ignored) {
((Listener<Object>)lner).onChange(value, oldValue);
}
};
}