#include "pch.h"
#include "objc_utils.h"
#include "log.h"
#include "app.h"
#include <atomic>

#ifdef __OBJC__
@implementation PathWithModDate
@end
@implementation ObjcUtils
+ (NSArray*)getFilesAtPathSortedByModificationDate:(NSString*)folderPath
{
    NSArray *allPaths = [NSFileManager.defaultManager contentsOfDirectoryAtPath:folderPath error:nil];

    NSMutableArray *sortedPaths = [NSMutableArray new];
    for (NSString *path in allPaths) {
        NSString *fullPath = [folderPath stringByAppendingPathComponent:path];

        NSDictionary *attr = [NSFileManager.defaultManager attributesOfItemAtPath:fullPath error:nil];
        NSDate *modDate = [attr objectForKey:NSFileModificationDate];

        PathWithModDate *pathWithDate = [[PathWithModDate alloc] init];
        pathWithDate.path = fullPath;
        pathWithDate.modDate = modDate;
        [sortedPaths addObject:pathWithDate];
    }

    [sortedPaths sortUsingComparator:^(PathWithModDate *path1, PathWithModDate *path2) {
        // Descending (most recently modified first)
        return [path2.modDate compare:path1.modDate];
    }];

    return sortedPaths;
}
@end
#endif


std::string base_address;
std::atomic_flag handler_executed;
void exception_handler(NSException *exception)
{
    if (handler_executed.test_and_set())
        exit(0);
    LOG("exception %s\n", [[exception name] cStringUsingEncoding:NSUTF8StringEncoding]);
    NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"];
    LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]);
    if (App::I.canvas && App::I.canvas->m_canvas)
        App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi");
    exit(0);
}

static void signal_handler (int signo) {
    if (handler_executed.test_and_set())
        exit(0);
    LOG("signal %d\n", signo);
    NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"];
    LOG("base:\n%s\ncallstack:\n%s", base_address.c_str(), [callstack cStringUsingEncoding:NSUTF8StringEncoding]);
    if (App::I.canvas && App::I.canvas->m_canvas)
        App::I.canvas->m_canvas->project_save_thread(App::I.data_path + "/recovery.ppi");
    exit(0);
}

void install_global_handlers()
{
    NSString* callstack = [[NSThread callStackSymbols] componentsJoinedByString:@"\n"];
    base_address = [callstack cStringUsingEncoding:NSUTF8StringEncoding];
    NSSetUncaughtExceptionHandler(exception_handler);
    signal(SIGABRT, signal_handler);
    signal(SIGILL, signal_handler);
    signal(SIGSEGV, signal_handler);
    signal(SIGFPE, signal_handler);
    signal(SIGBUS, signal_handler);
    signal(SIGPIPE, signal_handler);
}
