//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
// ignore_for_file: unused_import
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'bioseal_sdk_generated_bindings.dart';
import 'bioseal_native.dart';

import '../id3_bioseal.dart';

final _finalizer = NativeFinalizer(biosealSDK.addresses.id3BiosealResourceCallbackArgs_Dispose.cast());

/// Contains resource callback data.
class ResourceCallbackArgs implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3BiosealResourceCallbackArgs>> _pHandle;
  bool _disposable = true;

  /// Gets the native handle.
  /// return The native handle.
  Pointer<id3BiosealResourceCallbackArgs> get handle => _pHandle.value;

  /// Creates a new instance of the ResourceCallbackArgs class.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  ResourceCallbackArgs() {
    _pHandle = calloc();
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_Initialize(_pHandle);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

  /// Creates a new instance of the ResourceCallbackArgs class.
  ///
  /// param handle     Handle to the ResourceCallbackArgs.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  ResourceCallbackArgs.fromHandle(Pointer<id3BiosealResourceCallbackArgs> handle) {
    _pHandle = calloc();
    _pHandle.value = handle;
    _disposable = false;
  }

  /// Releases all resources used by this ResourceCallbackArgs.
  void dispose() {
    if (_disposable) {
      biosealSDK.id3BiosealResourceCallbackArgs_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }


  ///
  /// The URI used to retrieve the external resource.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String get uri => getUri();

  ///
  /// The resource name corresponing to the uri.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String get resourceName => getResourceName();

  ///
  /// The resource type corresponding to the uri.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  ResourceType get resourceType => getResourceType();

  ///
  /// The external resource data must be updated.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  bool get requiresUpdate => getRequiresUpdate();

  ///
  /// The external resource data as a byte array.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Uint8List get outputData => getOutputData();
  set outputData(Uint8List value) => setOutputData(value);

  // Public methods
  /// Gets the the URI used to retrieve the external resource.
  ///
  /// return The URI used to retrieve the external resource.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String getUri() {
    Pointer<Char> pUri = nullptr;
    Pointer<Int> pUriSize = calloc.allocate(1);
    pUriSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_GetUri(_pHandle.value, pUri, pUriSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pUri = calloc.allocate(pUriSize.value);
        err = biosealSDK.id3BiosealResourceCallbackArgs_GetUri(_pHandle.value, pUri, pUriSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vUri = utf8.decode(Uint8List.fromList(pUri.cast<Uint8>().asTypedList(pUriSize.value)));
      return vUri;
    } finally {
      calloc.free(pUri);
      calloc.free(pUriSize);
    }
  }

  /// Gets the the resource name corresponing to the uri.
  ///
  /// return The resource name corresponing to the uri.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String getResourceName() {
    Pointer<Char> pResourceName = nullptr;
    Pointer<Int> pResourceNameSize = calloc.allocate(1);
    pResourceNameSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_GetResourceName(_pHandle.value, pResourceName, pResourceNameSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pResourceName = calloc.allocate(pResourceNameSize.value);
        err = biosealSDK.id3BiosealResourceCallbackArgs_GetResourceName(_pHandle.value, pResourceName, pResourceNameSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vResourceName = utf8.decode(Uint8List.fromList(pResourceName.cast<Uint8>().asTypedList(pResourceNameSize.value)));
      return vResourceName;
    } finally {
      calloc.free(pResourceName);
      calloc.free(pResourceNameSize);
    }
  }

  /// Gets the the resource type corresponding to the uri.
  ///
  /// return The resource type corresponding to the uri.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  ResourceType getResourceType() {
    Pointer<Int32> pResourceType = calloc();
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_GetResourceType(_pHandle.value, pResourceType);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      final vResourceType = ResourceTypeX.fromValue(pResourceType.value);
      return vResourceType;
    } finally {
      calloc.free(pResourceType);
    }
  }

  /// Gets the the external resource data must be updated.
  ///
  /// return The external resource data must be updated.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  bool getRequiresUpdate() {
    Pointer<Bool> pRequiresUpdate = calloc();
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_GetRequiresUpdate(_pHandle.value, pRequiresUpdate);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      final vRequiresUpdate = pRequiresUpdate.value;
      return vRequiresUpdate;
    } finally {
      calloc.free(pRequiresUpdate);
    }
  }

  /// Gets the the external resource data as a byte array.
  ///
  /// return The external resource data as a byte array.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Uint8List getOutputData() {
    Pointer<UnsignedChar> pOutputData = nullptr;
    Pointer<Int> pOutputDataSize = calloc();
    pOutputDataSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_GetOutputData(_pHandle.value, pOutputData, pOutputDataSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pOutputData = calloc.allocate(pOutputDataSize.value);
        err = biosealSDK.id3BiosealResourceCallbackArgs_GetOutputData(_pHandle.value, pOutputData, pOutputDataSize);
      }
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      final vOutputData = Uint8List.fromList(pOutputData.cast<Uint8>().asTypedList(pOutputDataSize.value));
      return vOutputData;
    } finally {
      calloc.free(pOutputData);
      calloc.free(pOutputDataSize);
    }
  }

  /// Sets the the external resource data as a byte array.
  ///
  /// param outputData The external resource data as a byte array.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  void setOutputData(Uint8List? outputData) {
    Pointer<UnsignedChar>? pOutputData;
    if (outputData != null) {
    	pOutputData = calloc.allocate<UnsignedChar>(outputData.length);
    	pOutputData.cast<Uint8>().asTypedList(outputData.length).setAll(0, outputData);
    }
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_SetOutputData(_pHandle.value, pOutputData ?? nullptr, outputData?.length ?? 0);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
    } finally {
      if (pOutputData != null) {
        calloc.free(pOutputData);
      }
    }
  }

  /// Downloads a resource.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  void download() {
    var err = biosealSDK.id3BiosealResourceCallbackArgs_Download(_pHandle.value);
    if (err != BiosealError.success.value) {
      throw BiosealException(err);
    }
  }

  /// Downloads a file from the specified URL and returns a string.
  ///
  /// param url The URL to the file.
  /// return The file as a string.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String downloadStringFile(String? url) {
    Pointer<Char>? pUrl = url?.toNativeUtf8().cast<Char>();
    Pointer<Char> pData = nullptr;
    Pointer<Int> pDataSize = calloc.allocate(1);
    pDataSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_DownloadStringFile(_pHandle.value, pUrl ?? nullptr, pData, pDataSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pData = calloc.allocate(pDataSize.value);
        err = biosealSDK.id3BiosealResourceCallbackArgs_DownloadStringFile(_pHandle.value, pUrl ?? nullptr, pData, pDataSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vData = utf8.decode(Uint8List.fromList(pData.cast<Uint8>().asTypedList(pDataSize.value)));
      return vData;
    } finally {
      if (pUrl != null) {
        calloc.free(pUrl);
      }
      calloc.free(pData);
      calloc.free(pDataSize);
    }
  }

  /// Computes the SHA-256 of the external resource's data.
  ///
  /// return A string that contains the SHA-256.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String computeSha256() {
    Pointer<Char> pResult = nullptr;
    Pointer<Int> pResultSize = calloc.allocate(1);
    pResultSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealResourceCallbackArgs_ComputeSha256(_pHandle.value, pResult, pResultSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pResult = calloc.allocate(pResultSize.value);
        err = biosealSDK.id3BiosealResourceCallbackArgs_ComputeSha256(_pHandle.value, pResult, pResultSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vResult = utf8.decode(Uint8List.fromList(pResult.cast<Uint8>().asTypedList(pResultSize.value)));
      return vResult;
    } finally {
      calloc.free(pResult);
      calloc.free(pResultSize);
    }
  }

}

