//
//  Created by Ivano Bilenchi on 09/03/18.
//  Copyright © 2018-2020 SisInf Lab. All rights reserved.
//

#import <Foundation/Foundation.h>

/**
 * Use this directive to mark method implementations that should be overridden
 * by concrete subclasses.
 */
#define ABSTRACT_METHOD {                                                                           \
    @throw [NSException exceptionWithName:NSInternalInconsistencyException                          \
        reason:@"This method should be overridden in a subclass."                                   \
        userInfo:nil];                                                                              \
}

/**
 * Use this directive to automatically create a singleton instance getter. Example syntax:
 *
 * SHARED_INSTANCE(MyClass *, sharedInstance, {
 *     return [[MyClass alloc] init];
 * })
 *
 * @param type The type of the shared instance.
 * @param name The name of the shared instance getter.
 * @param body The body of the shared instance initializer.
 */
#define SHARED_INSTANCE(TYPE, NAME, BODY)                                                           \
static inline TYPE __##NAME##_initializer(void) BODY                                                \
+ (TYPE)NAME {                                                                                      \
    static TYPE __instance;                                                                         \
    static dispatch_once_t onceToken;                                                               \
    dispatch_once(&onceToken, ^{                                                                    \
        __instance = __##NAME##_initializer();                                                      \
    });                                                                                             \
    return __instance;                                                                              \
}

/**
 * Use this directive in place of @synthesize to automatically create a
 * lazy getter for the specified property. The property is instantiated
 * through a generated method. Example syntax:
 *
 * SYNTHESIZE_LAZY(NSMutableString *, myMutableString, {
 *     return [NSMutableString stringWithString:@"my mutable string"];
 * })
 *
 * @param type The type of the property.
 * @param name The name of the property.
 * @param body The body of the lazy setter.
 */
#define SYNTHESIZE_LAZY(TYPE, NAME, BODY)                                                           \
@synthesize NAME = _##NAME;                                                                         \
- (TYPE)__##NAME##_lazyGetter BODY                                                                  \
- (TYPE)NAME {                                                                                      \
    if (!_##NAME) _##NAME = [self __##NAME##_lazyGetter];                                           \
    return _##NAME;                                                                                 \
}

/**
 * Use this directive in place of @synthesize to automatically create a
 * lazy getter for the specified property. The property is instantiated
 * through a generated inline function. Example syntax:
 *
 * SYNTHESIZE_LAZY(NSMutableString *, myMutableString, {
 *     return [NSMutableString stringWithString:@"my mutable string"];
 * })
 *
 * @param type The type of the property.
 * @param name The name of the property.
 * @param body The body of the lazy setter.
 */
#define SYNTHESIZE_LAZY_INLINE(TYPE, NAME, BODY)                                                    \
static inline TYPE __##NAME##_lazy_getter(__unused id self) BODY                                    \
@synthesize NAME = _##NAME;                                                                         \
- (TYPE)NAME {                                                                                      \
    if (!_##NAME) _##NAME = __##NAME##_lazy_getter(self);                                           \
    return _##NAME;                                                                                 \
}

/**
 * Use this directive in place of @synthesize to automatically create a
 * computed getter with no backing ivar for the specified readonly property.
 *
 * @param type The type of the property.
 * @param name The name of the property.
 * @param body The body of the computed getter.
 */
#define SYNTHESIZE_COMPUTED(TYPE, NAME, BODY)                                                       \
@dynamic NAME;                                                                                      \
- (TYPE)NAME BODY
