//
//  FLEXViewExplorerViewController.m
//  Flipboard
//
//  Created by Ryan Olson on 6/11/14.
//  Copyright (c) 2014 Flipboard. All rights reserved.
//

#import "FLEXViewExplorerViewController.h"
#import "FLEXRuntimeUtility.h"
#import "FLEXUtility.h"
#import "FLEXObjectExplorerFactory.h"
#import "FLEXImagePreviewViewController.h"
#import "FLEXPropertyEditorViewController.h"

typedef NS_ENUM(NSUInteger, FLEXViewExplorerRow) {
    FLEXViewExplorerRowViewController,
    FLEXViewExplorerRowPreview
};

@interface FLEXViewExplorerViewController ()

// Don't clash with UIViewController's view property
@property (nonatomic, readonly) UIView *viewToExplore;

@end

@implementation FLEXViewExplorerViewController

- (UIView *)viewToExplore
{
    return [self.object isKindOfClass:[UIView class]] ? self.object : nil;
}


#pragma mark - Superclass Overrides

- (NSString *)customSectionTitle
{
    return @"Shortcuts";
}

- (NSArray *)customSectionRowCookies
{
    NSMutableArray *rowCookies = [NSMutableArray array];
    
    if ([FLEXUtility viewControllerForView:self.viewToExplore]) {
        [rowCookies addObject:@(FLEXViewExplorerRowViewController)];
    }
    
    [rowCookies addObject:@(FLEXViewExplorerRowPreview)];
    [rowCookies addObjectsFromArray:[self shortcutPropertyNames]];
    
    return rowCookies;
}

- (NSArray *)shortcutPropertyNames
{
    NSArray *propertyNames = @[@"frame", @"bounds", @"center", @"transform", @"backgroundColor", @"alpha", @"opaque", @"hidden", @"clipsToBounds", @"userInteractionEnabled", @"layer"];
    
    if ([self.viewToExplore isKindOfClass:[UILabel class]]) {
        propertyNames = [@[@"text", @"font", @"textColor"] arrayByAddingObjectsFromArray:propertyNames];
    }
    
    return propertyNames;
}

- (NSString *)customSectionTitleForRowCookie:(id)rowCookie
{
    NSString *title = nil;
    
    if ([rowCookie isKindOfClass:[NSNumber class]]) {
        FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
        switch (row) {
            case FLEXViewExplorerRowViewController:
                title = @"View Controller";
                break;
                
            case FLEXViewExplorerRowPreview:
                title = @"Preview Image";
                break;
        }
    } else if ([rowCookie isKindOfClass:[NSString class]]) {
        objc_property_t property = [self viewPropertyForName:rowCookie];
        if (property) {
            NSString *prettyPropertyName = [FLEXRuntimeUtility prettyNameForProperty:property];
            // Since we're outside of the "properties" section, prepend @property for clarity.
            title = [NSString stringWithFormat:@"@property %@", prettyPropertyName];
        }
    }
    
    return title;
}

- (NSString *)customSectionSubtitleForRowCookie:(id)rowCookie
{
    NSString *subtitle = nil;
    
    if ([rowCookie isKindOfClass:[NSNumber class]]) {
        FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
        switch (row) {
            case FLEXViewExplorerRowViewController:
                subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:[FLEXUtility viewControllerForView:self.viewToExplore]];
                break;
                
            case FLEXViewExplorerRowPreview:
                break;
        }
    } else if ([rowCookie isKindOfClass:[NSString class]]) {
        objc_property_t property = [self viewPropertyForName:rowCookie];
        if (property) {
            id value = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
            subtitle = [FLEXRuntimeUtility descriptionForIvarOrPropertyValue:value];
        }
    }
    
    return subtitle;
}

- (objc_property_t)viewPropertyForName:(NSString *)propertyName
{
    return class_getProperty([self.viewToExplore class], [propertyName UTF8String]);
}

- (BOOL)customSectionCanDrillIntoRowWithCookie:(id)rowCookie
{
    return YES;
}

- (UIViewController *)customSectionDrillInViewControllerForRowCookie:(id)rowCookie
{
    UIViewController *drillInViewController = nil;
    
    if ([rowCookie isKindOfClass:[NSNumber class]]) {
        FLEXViewExplorerRow row = [rowCookie unsignedIntegerValue];
        switch (row) {
            case FLEXViewExplorerRowViewController:
                drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:[FLEXUtility viewControllerForView:self.viewToExplore]];
                break;
                
            case FLEXViewExplorerRowPreview:
                drillInViewController = [[self class] imagePreviewViewControllerForView:self.viewToExplore];
                break;
        }
    } else if ([rowCookie isKindOfClass:[NSString class]]) {
        objc_property_t property = [self viewPropertyForName:rowCookie];
        if (property) {
            id currentValue = [FLEXRuntimeUtility valueForProperty:property onObject:self.viewToExplore];
            if ([FLEXPropertyEditorViewController canEditProperty:property currentValue:currentValue]) {
                drillInViewController = [[FLEXPropertyEditorViewController alloc] initWithTarget:self.object property:property];
            } else {
                drillInViewController = [FLEXObjectExplorerFactory explorerViewControllerForObject:currentValue];
            }
        }
    }

    return drillInViewController;
}

+ (UIViewController *)imagePreviewViewControllerForView:(UIView *)view
{
    UIViewController *imagePreviewViewController = nil;
    if (!CGRectIsEmpty(view.bounds)) {
        CGSize viewSize = view.bounds.size;
        UIGraphicsBeginImageContextWithOptions(viewSize, NO, 0.0);
        [view drawViewHierarchyInRect:CGRectMake(0, 0, viewSize.width, viewSize.height) afterScreenUpdates:YES];
        UIImage *previewImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        imagePreviewViewController = [[FLEXImagePreviewViewController alloc] initWithImage:previewImage];
    }
    return imagePreviewViewController;
}


#pragma mark - Runtime Adjustment

+ (void)initialize
{
    // A quirk of UIView: a lot of the "@property"s are not actually properties from the perspective of the runtime.
    // We add these properties to the class at runtime if they haven't been added yet.
    // This way, we can use our property editor to access and change them.
    // The property attributes match the declared attributes in UIView.h
    NSDictionary *frameAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGRect)), kFLEXUtilityAttributeNonAtomic : @""};
    [FLEXRuntimeUtility tryAddPropertyWithName:"frame" attributes:frameAttributes toClass:[UIView class]];
    
    NSDictionary *alphaAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(CGFloat)), kFLEXUtilityAttributeNonAtomic : @""};
    [FLEXRuntimeUtility tryAddPropertyWithName:"alpha" attributes:alphaAttributes toClass:[UIView class]];
    
    NSDictionary *clipsAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @""};
    [FLEXRuntimeUtility tryAddPropertyWithName:"clipsToBounds" attributes:clipsAttributes toClass:[UIView class]];
    
    NSDictionary *opaqueAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isOpaque"};
    [FLEXRuntimeUtility tryAddPropertyWithName:"opaque" attributes:opaqueAttributes toClass:[UIView class]];
    
    NSDictionary *hiddenAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(@encode(BOOL)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCustomGetter : @"isHidden"};
    [FLEXRuntimeUtility tryAddPropertyWithName:"hidden" attributes:hiddenAttributes toClass:[UIView class]];
    
    NSDictionary *backgroundColorAttributes = @{kFLEXUtilityAttributeTypeEncoding : @(FLEXEncodeClass(UIColor)), kFLEXUtilityAttributeNonAtomic : @"", kFLEXUtilityAttributeCopy : @""};
    [FLEXRuntimeUtility tryAddPropertyWithName:"backgroundColor" attributes:backgroundColorAttributes toClass:[UIView class]];
}

@end
