//
//  NSArray-Addtions.m
//  JasonDevelop
//
//  Created by Jason Lee on 10/29/14.
//  Copyright (c) jasondevelop. All rights reserved.
//
@import ObjectiveC.runtime;
#import "NSArray-Addtions.h"

@implementation NSArray (Addtions)

- (NSString*)jsonStringWithPrettyPrint:(BOOL) prettyPrint {
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self
                                                       options:(NSJSONWritingOptions) (prettyPrint ? NSJSONWritingPrettyPrinted : 0)
                                                         error:&error];

    if (!jsonData) {
        NSLog(@"bv_jsonStringWithPrettyPrint: error: %@", error.localizedDescription);
        return @"[]";
    } else {
        return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
}

- (id)objectKey:(NSString *)key eqaulToString:(NSString *)aString {

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF.%@ == %@", key, aString];
    NSArray *filteredArray = [self filteredArrayUsingPredicate:pred];
    
    return filteredArray && filteredArray.count ? filteredArray[0] : nil;
}

- (id)objectByUsingPredicateFormat:(NSString *)format, ... {
    
    va_list args;
    va_start(args, format);
    
    NSPredicate *pred = [NSPredicate predicateWithFormat:format arguments:args];
    NSArray *filteredArray = [self filteredArrayUsingPredicate:pred];
    
    return filteredArray && filteredArray.count ? filteredArray[0] : nil;
}

- (id)objectInSubArrays:(NSString *)description as:(id)aObject {
    id robject = nil;
    
    for (id object in self) {
        if (description && [description isKindOfClass:[NSString class]]) {
            //make selector
            SEL selector = NSSelectorFromString(description);
            
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            //get sub array
            NSArray *subarray = [object performSelector:selector];
#pragma clang diagnostic pop
            
            //find associated object from subArray
            for (id subObject in subarray) {
                if ([subObject isEqual:aObject]) {
                    robject = subObject;
                    break;
                }
            }
        }
        
        if (robject) {
            break;
        }
    }
    return robject;
}

- (id)matchedObjectName:(NSString *)objectName condition:(BOOL)condition {
    id matchedObject = nil;
    for (id object in self) {
        id associatedObj = objc_getAssociatedObject(object, (__bridge const void *)(objectName));
        if ([associatedObj boolValue] == condition) {
            matchedObject = object;
            break;
        }
    }
    return matchedObject;
}

- (NSArray *)matchedArrayByObjectName:(NSString *)objectName condition:(BOOL)condition {
    NSMutableArray *marray = [[NSMutableArray alloc] init];
    for (id object in self) {
        id associatedObj = objc_getAssociatedObject(object, (__bridge const void *)(objectName));
        if ([associatedObj boolValue] == condition) {
            [marray addObject:object];
        }
    }
    return marray;
}

- (NSArray *)matchedArrayInSubArrays:(id)description objectName:(NSString *)objectName condition:(BOOL)condition {
    NSMutableArray *marray = [[NSMutableArray alloc] init];
    
    for (id object in self) {
        if (description && [description isKindOfClass:[NSString class]]) {
            //make selector
            SEL selector = NSSelectorFromString(description);
            
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            //get sub array
            NSArray *subarray = [object performSelector:selector];
#pragma clang diagnostic pop
            
            //find associated object from subArray
            id matchedObject = [subarray matchedObjectName:objectName condition:condition];
            if (matchedObject) {
                [marray addObject:matchedObject];
            }
        }
    }
    return marray;
}

- (NSArray *)matchedArrayInSubArrays:(id)description predicateFormat:(NSString *)format, ... {

    va_list args;
    va_start(args, format);

    NSPredicate *pred = [NSPredicate predicateWithFormat:format arguments:args];
    return [self matchedArrayInSubArrays:description predicate:pred];
}

- (NSArray *)matchedArrayInSubArrays:(id)description predicate:(NSPredicate *)pred {
    NSMutableArray *marray = [[NSMutableArray alloc] init];
    for (id object in self) {
        if (description && [description isKindOfClass:[NSString class]]) {
            SEL selector = NSSelectorFromString(description);
            
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            NSArray *subarray = [object performSelector:selector];
#pragma clang diagnostic pop
            
            NSArray *filteredArray = nil;
            @try {
                filteredArray = [subarray filteredArrayUsingPredicate:pred];
                if (filteredArray && filteredArray.count) {
                    [marray addObjectsFromArray:filteredArray];
                }
            }
            @catch (NSException *exception) {
                continue;
            }
        } else if ([object isKindOfClass:[NSArray class]]) {
            NSArray *array = object;
            
            NSArray *filteredArray = [array filteredArrayUsingPredicate:pred];
            [marray addObjectsFromArray:filteredArray];
            
        } else if ([object isKindOfClass:[NSDictionary class]]) {
            NSLog(@"%s\n %@", __PRETTY_FUNCTION__, object);
        }
    }
    return marray;
}

- (NSArray *)filteredArrayUsingPredicateFormat:(NSString *)format, ... {
    
    va_list args;
    va_start(args, format);
    
    NSPredicate *pred = [NSPredicate predicateWithFormat:format arguments:args];
    return [self filteredArrayUsingPredicate:pred];
}

@end
