/*
 * This is the source code of Telegram for iOS v. 1.1
 * It is licensed under GNU GPL v. 2 or later.
 * You should have received a copy of the license in this archive (see LICENSE).
 *
 * Copyright Ernesto Guevara, 2014.
 */

#import "FreedomUIKit.h"

#import <objc/runtime.h>
#import <objc/message.h>

#import "TGHacks.h"
#import "TGNavigationController.h"

#define DEBUG_KEYBOARD_QUEUE false

void freedomUIKitInit2(); // iOS 6
void freedomUIKitInit3(); // Notification Center Hook

#if defined(DEBUG) && DEBUG_KEYBOARD_QUEUE
void freedomUIKitInit4(); // Keyboard Queue Debug
#endif

void freedomUIKitInit()
{   
    freedomUIKitInit2();
    freedomUIKitInit3();
    
#if defined(DEBUG) && DEBUG_KEYBOARD_QUEUE
    freedomUIKitInit4();
#endif
}

#pragma mark -

static int freedomUIKit_decorated2(__unused id self, __unused SEL _cmd)
{
    return 0;
}

void freedomUIKitInit2()
{
    if (iosMajorVersion() == 6)
    {
        FreedomDecoration instanceDecorations[] = {
            { .name = 0,
              .imp = (IMP)&freedomUIKit_decorated2,
              .newIdentifier = (FreedomIdentifier){ .string = "3066a13b3e6b", .key = 0x52d50551U },
              .newEncoding = (FreedomIdentifier){ .string = "1a7291", .key = 0x3ab3273U }
            }
        };
        
        freedomClassAutoDecorate(0x1468e61aU, NULL, 0, instanceDecorations, sizeof(instanceDecorations) / sizeof(instanceDecorations[0]));
    }
}

#pragma mark -

static bool test3 = false;
static bool test3_1 = false;

@implementation FFNotificationCenter

static bool (^shouldRotateBlock)() = nil;

+ (void)setShouldRotateBlock:(bool (^)())block
{
    shouldRotateBlock = [block copy];
}

- (void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo
{
    bool clearFlag = false;
    if ([aName isEqualToString:UIDeviceOrientationDidChangeNotification])
    {
        clearFlag = true;
        test3 = true;
        test3_1 = true;
    }
    
    if ([aName isEqualToString:UIDeviceOrientationDidChangeNotification])
    {
        if (shouldRotateBlock == nil || shouldRotateBlock())
            [super postNotificationName:aName object:anObject userInfo:aUserInfo];
    }
    else
        [super postNotificationName:aName object:anObject userInfo:aUserInfo];
    
    if (clearFlag)
        test3 = false;
}

@end

bool freedomUIKitTest3()
{
    return test3;
}

bool freedomUIKitTest3_1()
{
    bool value = test3_1;
    test3_1 = false;
    return value;
}

void freedomUIKitInit3()
{
    object_setClass([NSNotificationCenter defaultCenter], [FFNotificationCenter class]);
}

#pragma mark -

static bool test4 = false;
static bool test4_1 = false;

@interface TGHelperQueue : NSProxy
{
    id _target;
}

@end

@implementation TGHelperQueue

- (instancetype)initWithTargetQueue:(id)target
{
    if (self != nil)
    {
        _target = target;
    }
    return self;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
    return [_target methodSignatureForSelector:selector];
}

- (void)forwardInvocation:(NSInvocation *)__unused invocation
{
}

- (id)forwardingTargetForSelector:(SEL)selector
{
    static char *name = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        name = copyFreedomIdentifierValue((FreedomIdentifier){ .string = "536772a971686fb4484777b1706768b6574769b8626f75b4576e7eb9", .key = 0xdd1b0624U });
    });
    
    if (!strcmp(sel_getName(selector), name))
    {
        if (test4 || test4_1)
        {
            return nil;
        }
    }

    return _target;
}

- (void)doWork
{
}

@end

static UIView *freedomUIKitFindView(UIView *view)
{
    if (view == nil)
        return nil;
    
    if (object_getClass(view) == freedomClass(0x9cb128e7U))
        return view;
    
    for (UIView *subview in view.subviews)
    {
        UIView *result = freedomUIKitFindView(subview);
        if (result != nil)
            return result;
    }
    
    return nil;
}

void freedomUIKitTest4(dispatch_block_t block)
{
    if (iosMajorVersion() < 7 || iosMajorVersion() > 7 || (iosMajorVersion() == 7 && iosMinorVersion() >= 1))
    {
        if (block != nil)
            block();
    }
    else
    {
        UIView *view = freedomUIKitFindView([TGHacks applicationKeyboardWindow]);
        if (view != nil)
        {
            static ptrdiff_t queueOffset = -1;
            static bool queueInitialized = false;
            if (!queueInitialized)
            {
                queueInitialized = true;
                queueOffset = freedomIvarOffset(object_getClass(view), 0xba913cbU);
            }
            
            if (queueOffset >= 0)
            {
                __strong NSObject **queue = ((__strong NSObject **)(void *)(((uint8_t *)(__bridge void *)view) + queueOffset));
                if (*queue != nil)
                {
                    if (object_getClass(*queue) != [TGHelperQueue class])
                    {
                        TGHelperQueue *helper = [[TGHelperQueue alloc] initWithTargetQueue:*queue];
                        *queue = (NSObject *)helper;
                    }
                }
            }
        }
        
        bool previousTest4 = test4;
        test4 = true;
        
        if (block != nil)
            block();
        
        test4 = previousTest4;
    }
}

void freedomUIKitTest4_1()
{
    test4_1 = true;
    
    dispatch_async(dispatch_get_main_queue(), ^
    {
        test4_1 = false;
    });
}

#if defined(DEBUG) && DEBUG_KEYBOARD_QUEUE
void freedomUIKit_decorated4_1(id self, SEL _cmd, id arg1)
{
    static void (*nativeImpl)(id, SEL, id) = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        nativeImpl = (void *)freedomNativeImpl([self class], _cmd);
    });
    
    if (nativeImpl != NULL)
        nativeImpl(self, _cmd, arg1);
    
    TGLog(@"invoke %@", NSStringFromSelector(_cmd));
}


void freedomUIKit_decorated4_2(id self, SEL _cmd)
{
    static void (*nativeImpl)(id, SEL) = NULL;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        nativeImpl = (void *)freedomNativeImpl([self class], _cmd);
    });
    
    if (nativeImpl != NULL)
        nativeImpl(self, _cmd);
    
    TGLog(@"invoke %@", NSStringFromSelector(_cmd));
}

void freedomUIKitInit4()
{
    FreedomDecoration instanceDecorations[] = {
        { .name = 0xbb6dbb9eU, //addTask:
            .imp = (IMP)&freedomUIKit_decorated4_1,
            .newIdentifier = FreedomIdentifierEmpty,
            .newEncoding = FreedomIdentifierEmpty
        },
        { .name = 0x757d9b1cU, //waitUntilAllTasksAreFinished
            .imp = (IMP)&freedomUIKit_decorated4_2,
            .newIdentifier = FreedomIdentifierEmpty,
            .newEncoding = FreedomIdentifierEmpty
        }
    };
    
    freedomClassAutoDecorate(0xfed2643dU, NULL, 0, instanceDecorations, sizeof(instanceDecorations) / sizeof(instanceDecorations[0]));
}
#endif
