package ns.foundation;
import java.util.Collection;
import java.util.HashSet;
public class NSNotificationCenter {
private static final NSNotificationCenter _defaultCenter = new NSNotificationCenter();
private final NSMutableDictionary<String, NotificationRegistry> _namedRegistries = new NSMutableDictionary<String, NotificationRegistry>();
private final NotificationRegistry _unnamedRegistry = new NotificationRegistry();
private static void postNotification(NSNotificationCenter notificationCenter, NSNotification notification) {
notificationCenter._unnamedRegistry.postNotification(notification);
notificationCenter._namedRegistries.objectForKey(notification.name()).postNotification(notification);
}
public static NSNotificationCenter defaultCenter() {
return _defaultCenter;
}
private void _checkSelector(NSSelector<?> selector) {
Class<?>[] parameterTypes = selector.parameterTypes();
boolean invalid = false;
if (parameterTypes == null || parameterTypes.length != 1) {
invalid = true;
} else {
Class<?> arg = parameterTypes[0];
if (!_NSReflectionUtilities.classIsAssignableFrom(arg, NSNotification.class)) {
invalid = true;
}
}
if (invalid) {
throw new IllegalArgumentException("NSNotificationCenter addObserver() requires a selector taking a single NSNotification argument");
}
}
public synchronized void addObserver(NSSelectable observer, NSSelector<?> selector, String name, Object object) {
if (observer == null || selector == null) {
throw new IllegalArgumentException("NSNotificationCenter addObserver() requires non null observer and selector parameters");
}
_checkSelector(selector);
NotificationRegistry registry;
NotificationObserver _observer = new NotificationObserver(observer, selector);
if (name == null) {
registry = _unnamedRegistry;
} else if ((registry = _namedRegistries.objectForKey(name)) == null) {
registry = new NotificationRegistry();
_namedRegistries.setObjectForKey(registry, name);
}
registry.addObserver(_observer, object);
}
public void postNotification(NSNotification notification) {
if (notification == null) {
throw new IllegalArgumentException("Notification cannot be null");
}
NSNotificationCenter.postNotification(this, notification);
}
public void postNotification(String notificationName, Object notificationObject) {
postNotification(new NSNotification(notificationName, notificationObject, null));
}
public void postNotification(String notificationName, Object notificationObject, NSDictionary<String, Object> userInfo) {
postNotification(new NSNotification(notificationName, notificationObject, userInfo));
}
public void removeObserver(Object observer) {
removeObserver(observer, null, null);
}
public synchronized void removeObserver(Object observer, String name, Object object) {
if (observer == null && name == null && object == null) {
throw new IllegalArgumentException("Can't remove entry with null observer, null name, and null object from NSNotificationCenter");
}
if (name == null) {
for (String key : _namedRegistries.keySet()) {
_namedRegistries.objectForKey(key).removeObserver(observer, object);
}
_unnamedRegistry.removeObserver(observer, object);
} else {
_namedRegistries.objectForKey(name).removeObserver(observer, object);
}
}
@Override
public String toString() {
return super.toString();
}
private static class NotificationRegistry {
private NSMutableDictionary<Integer, NSMutableArray<NotificationObserver>> _objectObservers = new NSMutableDictionary<Integer, NSMutableArray<NotificationObserver>>();
private boolean _observerRemoval = false;
private NSArray<NotificationObserver> _postingObservers;
public void addObserver(NotificationObserver observer, Object _object) {
Object object = _object;
if (object == null) {
object = NSKeyValueCoding.NullValue;
}
NSMutableArray<NotificationObserver> observers = _objectObservers.objectForKey(object.hashCode());
if (observers == null) {
observers = new NSMutableArray<NotificationObserver>();
_objectObservers.setObjectForKey(observers, object.hashCode());
}
if (observers == _postingObservers) {
_postingObservers = observers.immutableClone();
}
observers.add(observer);
}
public void removeObserver(Object observer, Object object) {
NSMutableArray<Integer> removedKeys = new NSMutableArray<Integer>();
Collection<Integer> keys;
if (object == null) {
keys = _objectObservers.keySet();
} else {
keys = new HashSet<Integer>(object.hashCode());
}
for(Integer key : keys) {
NSArray<NotificationObserver> observers = _objectObservers.objectForKey(key);
if (observers != null) {
int index = observers.count();
while(index-- > 0) {
if (observers.objectAtIndex(index).observer() == observer) {
_observerRemoval = true;
if (observers == _postingObservers) {
_postingObservers = observers.immutableClone();
}
observers.remove(index);
}
}
}
if (observers == null || observers.count() == 0) {
removedKeys.add(key);
}
}
for (Integer key : removedKeys) {
_objectObservers.removeObjectForKey(key);
}
}
public void postNotification(NSNotification notification) {
Object object = notification.object();
Collection<Object> keys = new HashSet<Object>();
keys.add(NSKeyValueCoding.NullValue.hashCode());
if (object != null) {
keys.add(object.hashCode());
}
for (Object key : keys) {
_postingObservers = _objectObservers.objectForKey(key);
if (_postingObservers == null) {
continue;
}
NSArray<NotificationObserver> observers = _postingObservers;
_observerRemoval = false;
int index = observers.count();
while (index-- > 0) {
NotificationObserver observer = _postingObservers.get(index);
if (!_observerRemoval || observers.indexOfIdenticalObject(observer) != NSArray.NotFound) {
observer.postNotification(notification);
}
}
}
_postingObservers = null;
}
}
private static class NotificationObserver {
private final NSSelectable _observer;
private final NSSelector<?> _selector;
public NotificationObserver(NSSelectable observer, NSSelector<?> selector) {
_observer = observer;
_selector = selector;
}
public NSSelectable observer() {
return _observer;
}
public void postNotification(NSNotification notification) {
NSSelector._safeInvokeSelector(_selector, _observer, notification);
}
}
}