//
//  virtualization_14_arm64.m
//
//  Created by codehex.
//

#import "virtualization_14_arm64.h"

/*!
 @abstract Restore a virtual machine.
 @discussion
    Restore a stopped virtual machine to a state previously saved to file through `saveMachineStateToURL:completionHandler:`.

    If the file cannot be read, or contains otherwise invalid contents, this operation will fail with a `VZErrorRestore` error.
    If the virtual machine is not in the stopped state, this operation will fail with a `VZErrorInvalidVirtualMachineStateTransition` error.
    If the virtual machine cannot be started due to an internal error, this operation will fail with a `VZErrorInternal` error.
    The `VZVirtualMachineConfiguration` must also support restoring, which can be checked with  `-[VZVirtualMachineConfiguration validateSaveRestoreSupportWithError:]`.

    If this operation fails, the virtual machine state is unchanged.
    If successful, the virtual machine is restored and placed in the paused state.
 @param saveFileURL URL to file containing saved state of a suspended virtual machine.
    The file must have been generated by `saveMachineStateToURL:completionHandler:` on the same host.
    Otherwise, this operation will fail with a `VZErrorRestore` error indicating a permission denied failure reason.

    The virtual machine must also be configured compatibly with the state contained in the file.
    If the `VZVirtualMachineConfiguration` is not compatible with the content of the file, this operation will fail with a `VZErrorRestore` error indicating an invalid argument failure reason.

    Files generated with `saveMachineStateToURL:completionHandler:` on a software version that is newer than the current version will also be rejected with an invalid argument failure reason.
    In some cases, `restoreMachineStateFromURL:completionHandler:` can fail if a software update has changed the host in a way that would be incompatible with the previous format.
    In this case, an invalid argument error will be surfaced. In most cases, the virtual machine should be restarted with `startWithCompletionHandler:`.
 @param completionHandler Block called after the virtual machine has been successfully started or on error.
    The error parameter passed to the block is nil if the restore was successful.
 @see -[VZVirtualMachineConfiguration validateSaveRestoreSupportWithError:]
 */
void restoreMachineStateFromURLWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle, const char *saveFilePath)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        NSString *saveFilePathNSString = [NSString stringWithUTF8String:saveFilePath];
        NSURL *saveFileURL = [NSURL fileURLWithPath:saveFilePathNSString];
        vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
        dispatch_sync((dispatch_queue_t)queue, ^{
            [(VZVirtualMachine *)machine restoreMachineStateFromURL:saveFileURL completionHandler:handler];
        });
        Block_release(handler);
        return;
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

/*!
 @abstract Save a virtual machine.
 @discussion
    Save a paused virtual machine to file.
    The contents of this file can be used later to restore the state of the paused virtual machine.

    If the virtual machine is not paused, this operation will fail with a `VZErrorInvalidVirtualMachineState` error.
    If the virtual machine cannot be saved, this operation will fail with a `VZErrorSave` error.
    The `VZVirtualMachineConfiguration` must also support saving, which can be checked with  `-[VZVirtualMachineConfiguration validateSaveRestoreSupportWithError:]`.

    If this operation fails, the virtual machine state is unchanged.
    If successful, the file is written out and the virtual machine state is unchanged.
 @param saveFileURL URL to location where the saved state of the virtual machine is to be written.
    Each file is protected by an encryption key that is tied to the host on which it is created.
 @param completionHandler Block called after the virtual machine has been successfully saved or on error.
    The error parameter passed to the block is nil if the save was successful.
 @see -[VZVirtualMachineConfiguration validateSaveRestoreSupportWithError:]
 */
void saveMachineStateToURLWithCompletionHandler(void *machine, void *queue, uintptr_t cgoHandle, const char *saveFilePath)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        NSString *saveFilePathNSString = [NSString stringWithUTF8String:saveFilePath];
        NSURL *saveFileURL = [NSURL fileURLWithPath:saveFilePathNSString];
        vm_completion_handler_t handler = makeVMCompletionHandler(cgoHandle);
        dispatch_sync((dispatch_queue_t)queue, ^{
            [(VZVirtualMachine *)machine saveMachineStateToURL:saveFileURL completionHandler:handler];
        });
        Block_release(handler);
        return;
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

void *newVZLinuxRosettaAbstractSocketCachingOptionsWithName(const char *name, void **error)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        NSString *nameNSString = [NSString stringWithUTF8String:name];
        return [[VZLinuxRosettaAbstractSocketCachingOptions alloc] initWithName:nameNSString error:(NSError *_Nullable *_Nullable)error];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

uint32_t maximumNameLengthVZLinuxRosettaAbstractSocketCachingOptions()
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        return (uint32_t)[VZLinuxRosettaAbstractSocketCachingOptions maximumNameLength];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

void *newVZLinuxRosettaUnixSocketCachingOptionsWithPath(const char *path, void **error)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        NSString *pathNSString = [NSString stringWithUTF8String:path];
        return [[VZLinuxRosettaUnixSocketCachingOptions alloc] initWithPath:pathNSString error:(NSError *_Nullable *_Nullable)error];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

uint32_t maximumPathLengthVZLinuxRosettaUnixSocketCachingOptions()
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        return (uint32_t)[VZLinuxRosettaUnixSocketCachingOptions maximumPathLength];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

void setOptionsVZLinuxRosettaDirectoryShare(void *rosetta, void *cachingOptions)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        [(VZLinuxRosettaDirectoryShare *)rosetta setOptions:(VZLinuxRosettaCachingOptions *)cachingOptions];
        return;
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

/*!
 @abstract Configuration for a Mac keyboard.
 @discussion
    This device can be used by VZVirtualMachineView to send keyboard events to the virtual machine.
    This keyboard supports Apple-specific features such as the globe key.
    Note: this device is only recognized by virtual machines running macOS 13.0 and later. In order to support both macOS 13.0 and earlier
    guests, VZVirtualMachineConfiguration.keyboards can be set to an array containing both a VZMacKeyboardConfiguration and
    a VZUSBKeyboardConfiguration object. macOS 13.0 and later guests will use the Mac keyboard device,
    while earlier versions of macOS will use the USB keyboard device.
 */
void *newVZMacKeyboardConfiguration()
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        return [[VZMacKeyboardConfiguration alloc] init];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}

/*!
 @abstract Validate the configuration is savable.
 @discussion
    Verify that a virtual machine with this configuration is savable.
    Not all configuration options can be safely saved and restored from file.
    If this evaluates to NO, the caller should expect future calls to saveMachineStateToURL:completionHandler: to fail.
 @param error If not nil, assigned with an error describing the unsupported configuration option.
 @return YES if the configuration is savable.
 */
bool validateSaveRestoreSupportWithError(void *config, void **error)
{
#ifdef INCLUDE_TARGET_OSX_14
    if (@available(macOS 14, *)) {
        return (bool)[(VZVirtualMachineConfiguration *)config
            validateSaveRestoreSupportWithError:(NSError *_Nullable *_Nullable)error];
    }
#endif
    RAISE_UNSUPPORTED_MACOS_EXCEPTION();
}
