
/*******************************************************
 * Copyright (C) 2018 XMind Ltd. - All Rights Reserved
 *******************************************************/

#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>

#import "./handoff.h"

NSString* ToNSStringNoCopy(const Nan::Utf8String& value) {
  const char* cstr = *value ? *value : "<string conversion failed>";
  return [[NSString alloc] initWithBytesNoCopy:(void*)cstr
                                        length:value.length()
                                      encoding:NSUTF8StringEncoding
                                  freeWhenDone:false];
}

NSString* ToNSString(const Nan::Utf8String& value) {
  const char* cstr = *value ? *value : "<string conversion failed>";
  return [[NSString alloc] initWithBytes:(void*)cstr
                                  length:value.length()
                                encoding:NSUTF8StringEncoding];
}

static NSMutableDictionary* _documentCache = NULL;
static NSMutableDictionary* getDocumentCache() {
  if (_documentCache == NULL) {
    _documentCache = [[NSMutableDictionary alloc] init];
  }
  return _documentCache;
}

NAN_METHOD(HoActivateFile) {
  if (info.Length() != 2 || !info[0]->IsString() || !info[1]->IsString()) {
    Nan::ThrowTypeError("Invalid arguments");
    return;
  }

  Nan::HandleScope scope;

  @autoreleasepool {
    Nan::Utf8String arg0(info[0]);
    Nan::Utf8String arg1(info[1]);
    NSString * path = ToNSStringNoCopy(arg0);
    NSString * type = ToNSStringNoCopy(arg1);

    NSMutableDictionary * cache = getDocumentCache();
    NSUserActivity * doc = [cache valueForKey:path];
    if (doc == nil) {
      // NSURL * url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
      // if (url == nil) {
      //   NSLog(@"[XMind] Can't locate iCloud URL. Handoff disabled.");
      //   return;
      // }

      // NSString * iCloudFolder = url.URLByStandardizingPath.URLByResolvingSymlinksInPath.path;
      // if (![path hasPrefix:iCloudFolder]) {
      //   NSLog(@"[XMind] File not in app iCloud folder. Ignored for Handoff.");
      //   return;
      // }

      NSUserActivity * activity = [[NSUserActivity alloc] initWithActivityType:type];
      activity.userInfo = @{@"NSUserActivityDocumentURL": [NSURL fileURLWithPath:path]};
      [cache setObject:activity forKey:path];
      [activity becomeCurrent];
    } else {
      [doc becomeCurrent];
    }
  }
}

NAN_METHOD(HoDeactivateFile) {
  if (info.Length() != 1 || !info[0]->IsString()) {
    Nan::ThrowTypeError("Invalid arguments");
    return;
  }

  Nan::HandleScope scope;

  @autoreleasepool {
    Nan::Utf8String arg0(info[0]);
    NSString * path = ToNSStringNoCopy(arg0);

    NSMutableDictionary * cache = getDocumentCache();
    [[cache valueForKey:path] invalidate];
    [cache removeObjectForKey:path];
  }
}

NAN_METHOD(HoEnsureUbiquityContainer) {
  if (info.Length() != 1 || !info[0]->IsString()) {
    Nan::ThrowTypeError("Invalid arguments");
    return;
  }

  Nan::HandleScope scope;

  @autoreleasepool {
    Nan::Utf8String arg0(info[0]);
    NSString * identifier = ToNSStringNoCopy(arg0);

    NSURL * url = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:identifier];
    [[NSFileManager defaultManager] createDirectoryAtURL: url
                             withIntermediateDirectories: YES
                                              attributes: NULL
                                                   error: NULL];
  }
}

NAN_METHOD(HoDownloadICloudFile) {
  if (info.Length() != 1 || !info[0]->IsString()) {
    Nan::ThrowTypeError("Invalid arguments");
    return;
  }

  Nan::HandleScope scope;

  @autoreleasepool {
    Nan::Utf8String arg0(info[0]);
    NSString * path = ToNSStringNoCopy(arg0);
    NSURL * url = [NSURL fileURLWithPath:path];
    NSNumber * isInICloud = nil;
    NSError * error = nil;

    if (![url getResourceValue:&isInICloud forKey:NSURLIsUbiquitousItemKey error:&error]) {
      if (error != nil) {
        Nan::ThrowTypeError([error localizedDescription].UTF8String);
      }
      return;
    }

    if (![isInICloud boolValue]) {
      info.GetReturnValue().Set(Nan::New(false));
      return;
    }

    NSString * downloadStatus = nil;
    error = nil;
    if ([url getResourceValue:&downloadStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error]) {
      if ([downloadStatus isEqualToString:NSURLUbiquitousItemDownloadingStatusDownloaded]) {
        info.GetReturnValue().Set(Nan::New(false));
        return;
      }
    }

    if (error != nil) {
      Nan::ThrowTypeError([error localizedDescription].UTF8String);
      return;
    }

    error = nil;
    if (![[NSFileManager defaultManager] startDownloadingUbiquitousItemAtURL:url error:&error])
    {
      if (error != nil) {
        Nan::ThrowTypeError([error localizedDescription].UTF8String);
      }
      return;
    }

    info.GetReturnValue().Set(Nan::New(true));
    return;
  }
}

NAN_METHOD(HoGetUbiquitousItemDownloadingStatus) {
  if (info.Length() != 1 || !info[0]->IsString()) {
    Nan::ThrowTypeError("Invalid arguments");
    return;
  }

  Nan::HandleScope scope;

  @autoreleasepool {
    Nan::Utf8String arg0(info[0]);
    NSString * path = ToNSStringNoCopy(arg0);
    NSURL * url = [NSURL fileURLWithPath:path];
    NSError * error = nil;
    NSString * downloadStatus = nil;
    if ([url getResourceValue:&downloadStatus forKey:NSURLUbiquitousItemDownloadingStatusKey error:&error]) {
      info.GetReturnValue().Set(Nan::New(downloadStatus.UTF8String).ToLocalChecked());
      return;
    }

    if (error != nil) {
      Nan::ThrowTypeError([error localizedDescription].UTF8String);
      return;
    }
  }
}
