// // PNObjectModel.m // Pods // // Created by Giuseppe Nucifora on 16/01/16. // // #import "PNObjectModel.h" #import "PNObject+Protected.h" #import "PEARFileManager.h" #import "PNObjectConstants.h" @import RNCryptor; @interface PNObjectModel() @property (nonatomic, strong) PEARFileManager *fileManager; @end @implementation PNObjectModel static PNObjectModel *SINGLETON = nil; static bool isFirstAccess = YES; #pragma mark Public Method + (instancetype) sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ isFirstAccess = NO; SINGLETON = [[super allocWithZone:NULL] init]; }); return SINGLETON; } - (NSString * _Nullable) objectName:(id _Nonnull) object { BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]]; if(isPNObjectSubclass) { if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) { NSString *className; //if ([[object subClassDelegate] respondsToSelector:@selector(objectClassName)]) { @try { className = (NSString *)[[object class] performSelector:@selector(objectClassName)]; } @catch (NSException *exception) { return nil; } @finally { return className; } //} } } return nil; } - (BOOL) issetPNObjectModelForObject:(id _Nonnull) object { NSString *className = [self objectName:object]; if (!className) { return NO; } return [_fileManager checkPath:className]; } #pragma mark - + (id) allocWithZone:(NSZone *)zone { return [self sharedInstance]; } + (id)copyWithZone:(struct _NSZone *)zone { return [self sharedInstance]; } + (id)mutableCopyWithZone:(struct _NSZone *)zone { return [self sharedInstance]; } - (id)copy { return [[PNObjectModel alloc] init]; } - (id)mutableCopy { return [[PNObjectModel alloc] init]; } - (id) init { if(SINGLETON){ return SINGLETON; } if (isFirstAccess) { [self doesNotRecognizeSelector:_cmd]; } self = [super init]; if (self) { _fileManager = [PEARFileManager sharedInstatnce]; [_fileManager setRootDirectory:k_ROOT_DIR_DOCUMENTS]; NSLogDebug(@"%@",[_fileManager getRootDirectoryPath]); } return self; } #pragma mark Public Methods - (id _Nonnull) fetchObjectsWithClass:(Class _Nonnull) class { BOOL isPNObjectSubclass = [class isSubclassOfClass:[PNObject class]]; if(isPNObjectSubclass) { NSString *className; @try { className = (NSString *)[class performSelector:@selector(objectClassName)]; } @catch (NSException *exception) { } @finally { if ([_fileManager checkPath:className]) { NSError *error = nil; NSData *data = [RNCryptor decryptData:[_fileManager fetchFileDataWithPath:className] password:[[PNObjectConfig sharedInstance] encrypKey] error:&error]; return [NSKeyedUnarchiver unarchiveObjectWithData:data]; } else return nil; } } } - (id _Nonnull) saveLocally:(id _Nonnull) object { BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]]; if(isPNObjectSubclass) { if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) { if ([(PNObject*) object singleInstance]) { NSDictionary *objectDict = [(PNObject*) object reverseMapping]; NSData *objectData = [RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objectDict] password:[[PNObjectConfig sharedInstance] encrypKey]]; if ([self issetPNObjectModelForObject:object]) { if ([_fileManager updateFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) { return object; } else { return [NSError errorWithDomain:NSLocalizedString(@"Object cannot be updated", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } else { if ([_fileManager createFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) { return object; } else { return [NSError errorWithDomain:NSLocalizedString(@"Object cannot be created", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } } else { if ([self issetPNObjectModelForObject:object]) { //NSData * data = [_fileManager fetchFileDataWithPath:[self objectName:object]]; NSError *error = nil; NSData *data = [RNCryptor decryptData:[_fileManager fetchFileDataWithPath:[self objectName:object]] password:[[PNObjectConfig sharedInstance] encrypKey] error:&error]; NSMutableArray *objects = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:data]]; NSDictionary *objectDict = [(PNObject*)object reverseMapping]; [objects addObject:objectDict]; NSData *objectData = [RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objects] password:[[PNObjectConfig sharedInstance] encrypKey]]; if ([_fileManager updateFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) { return objects; } else { return [NSError errorWithDomain:NSLocalizedString(@"Objects list cannot be updated", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } else { NSMutableArray *objects = [[NSMutableArray alloc] init]; NSDictionary *objectDict = [(PNObject*)object reverseMapping]; [objects addObject:objectDict]; NSData *objectData = [RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objects] password:[[PNObjectConfig sharedInstance] encrypKey]]; if ([_fileManager createFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) { return object; } else { return [NSError errorWithDomain:NSLocalizedString(@"Objects list cannot be created", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } } } else { return [NSError errorWithDomain:NSLocalizedString(@"passed object is not conform to protocol PNObjectSubclassing", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } else { return [NSError errorWithDomain:NSLocalizedString(@"passed object is not PNObject Subclass", @"") code:kHTTPStatusCodeBadRequest userInfo:nil]; } } /*- (id _Nonnull) saveNSUSerDefautls:(id _Nonnull) object { }*/ - (BOOL) removeObjectLocally:(id _Nonnull) object { BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]]; if(isPNObjectSubclass) { if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) { if ([self issetPNObjectModelForObject:object]) { return [_fileManager deletePath:[self objectName:object]]; } } } return NO; } @end