LCLicenceObserver.m

This file can be downloaded as part of milnlicence.tbz.

//
//  LCLicenceObserver.m
//  LicenceCore - https://indie.miln.eu
//
//  Copyright © Graham Miln. All rights reserved. https://miln.eu
//
//  This package is subject to the terms of the Artistic License 2.0.
//  If a copy of the Artistic-2.0 was not distributed with this file, you can
//  obtain one at https://indie.miln.eu/licence

#import "LCLicenceObserver.h"

// KVO Content
static NSString* LCLicenceObserverKVOIsLicensedContext = @"LCLicenceObserverKVOIsLicensedContext";
static NSString* LCLicenceObserverKVOLicencesContext = @"LCLicenceObserverKVOLicencesContext";
static NSString* LCLicenceObserverKVOPendingContext = @"LCLicenceObserverKVOPendingContext";

@interface LCLicenceObserver ()
@property(strong) LCLicenceCore* core;
@property(weak) NSObject<LCLicenceObserverProtocol>* delegate;

- (void)isLicensedDidChange:(BOOL)isLicensed;
- (void)licencesDidChange:(LCLicence*)aLicence;
@end

@implementation LCLicenceObserver

+ (instancetype)observerWithCore:(LCLicenceCore*)aCore delegate:(NSObject<LCLicenceObserverProtocol>*)aDelegate {
	return [(LCLicenceObserver*)[[self class] alloc] initWithCore:aCore delegate:aDelegate];
}

- (instancetype)initWithCore:(LCLicenceCore*)aCore delegate:(NSObject<LCLicenceObserverProtocol>*)aDelegate {
	NSParameterAssert(aCore);
	NSParameterAssert(aDelegate);
	if ((self = [super init])) {
		self.core = aCore;
		self.delegate = aDelegate;
		
		[self.core addObserver:self forKeyPath:LCLicenceCoreKeyIsLicensed options:0 context:(__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)];
		[self.core addObserver:self forKeyPath:LCLicenceCoreKeyLicences options:(NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:(__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)];
	}
	return self;
}

- (void)dealloc {
	[self.core removeObserver:self forKeyPath:LCLicenceCoreKeyLicences context:(__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)];
	[self.core removeObserver:self forKeyPath:LCLicenceCoreKeyIsLicensed context:(__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
	if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOIsLicensedContext)) {
		NSNumber* value = [object valueForKeyPath:keyPath];
		if ([value respondsToSelector:@selector(boolValue)]) {
			[self isLicensedDidChange:[value boolValue]];
		}
	} else if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOLicencesContext)) {
		id old = change[NSKeyValueChangeOldKey];
		if ([old isKindOfClass:NSArray.class]) {
			NSArray<LCLicence*>* oldLicences = old;
			[oldLicences enumerateObjectsUsingBlock:^(LCLicence* inLicence, NSUInteger __unused inIndex,BOOL* __unused outShouldStop) {
				[inLicence removeObserver:self forKeyPath:LCLicenceKeyIsPending context:(__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)];
			}];
		}
		
		id new = change[NSKeyValueChangeNewKey];
		if ([new isKindOfClass:NSArray.class]) {
			NSArray<LCLicence*>* newLicences = new;
			[newLicences enumerateObjectsUsingBlock:^(LCLicence* inLicence, NSUInteger __unused inIndex,BOOL* __unused outShouldStop) {
				[inLicence addObserver:self forKeyPath:LCLicenceKeyIsPending options:(NSKeyValueObservingOptionInitial|NSKeyValueObservingOptionNew) context:(__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)];
			}];
		}
		
		// TODO: diff old and new, then inform delegate only for new licences
		[self licencesDidChange:nil];
	} else if (context == (__bridge void * _Nullable)(LCLicenceObserverKVOPendingContext)) {
		if ([object isKindOfClass:LCLicence.class]) {
			[self licencesDidChange:object];
		}
	} else {
		[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
	}
}

#pragma mark -

- (void)isLicensedDidChange:(BOOL)isLicensed {
	if ([self.delegate respondsToSelector:@selector(licenceObserver:licensed:)]) {
		[self.delegate licenceObserver:self licensed:isLicensed];
	}
}

- (void)licencesDidChange:(LCLicence*)aLicence {
	if ([self.delegate respondsToSelector:@selector(licenceObserver:didChange:)]) {
		[self.delegate licenceObserver:self didChange:aLicence];
	}
}

@end