//--------------------------------------------------------------------------------------------------
// 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 'document_sdk_generated_bindings.dart';
import 'document_native.dart';

import '../id3_document.dart';

/// Initializes the SDK library.
class DocumentLibrary {

  // Public methods
  /// Retrieves the library version as a 'X.Y.Z' formatted string.
  ///
  /// return A string that identifies the library version.
  /// throws DocumentException An error has occurred during Document Library execution.
  static String getVersion() {
    Pointer<Char> pLibraryVersion = calloc.allocate(8);
    Pointer<Int> pLibraryVersionSize = calloc.allocate(1);
    pLibraryVersionSize[0] = 8;
    try {
      var err = documentSDK.id3DocumentLibrary_GetVersion(pLibraryVersion, pLibraryVersionSize);
      if (err == DocumentError.insufficientBuffer.value) {
        calloc.free(pLibraryVersion);
        pLibraryVersion = calloc.allocate(pLibraryVersionSize.value);
        err = documentSDK.id3DocumentLibrary_GetVersion(pLibraryVersion, pLibraryVersionSize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vLibraryVersion = utf8.decode(Uint8List.fromList(pLibraryVersion.cast<Uint8>().asTypedList(pLibraryVersionSize.value)));
      return vLibraryVersion;
    } finally {
      calloc.free(pLibraryVersion);
      calloc.free(pLibraryVersionSize);
    }
  }

  /// Retrieves the library version as a structure.
  ///
  /// return The version.
  /// throws DocumentException An error has occurred during Document Library execution.
  static LibVersion getVersionEx() {
    Pointer<id3DocumentLibVersion> pVersion = calloc();
    var err = documentSDK.id3DocumentLibrary_GetVersionEx(pVersion);
    if (err != DocumentError.success.value) {
    	calloc.free(pVersion);
    	throw DocumentException(err);
    }
    return LibVersion(pVersion);
  }

  /// Loads the specified document template from a file.
  ///
  /// param path A string that contains the full path to the document template.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void loadDocumentTemplate(String? path) {
    Pointer<Char>? pPath = path?.toNativeUtf8().cast<Char>();
    try {
      var err = documentSDK.id3DocumentLibrary_LoadDocumentTemplate(pPath ?? nullptr);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pPath != null) {
        calloc.free(pPath);
      }
    }
  }

  /// Loads a document template from a data buffer.
  ///
  /// param buffer A buffer containing the document template data.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void loadDocumentTemplateBuffer(Uint8List? buffer) {
    Pointer<UnsignedChar>? pBuffer;
    if (buffer != null) {
    	pBuffer = calloc.allocate<UnsignedChar>(buffer.length);
    	pBuffer.cast<Uint8>().asTypedList(buffer.length).setAll(0, buffer);
    }
    try {
      var err = documentSDK.id3DocumentLibrary_LoadDocumentTemplateBuffer(pBuffer ?? nullptr, buffer?.length ?? 0);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pBuffer != null) {
        calloc.free(pBuffer);
      }
    }
  }

  /// Loads a model into memory from the specified directory.
  ///
  /// param modelPath The path to directory containing the AI model files.
  /// param documentModel The AI model to be loaded.
  /// param processingUnit Processing unit to load the model into.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void loadModel(String? modelPath, DocumentModel documentModel, ProcessingUnit processingUnit) {
    Pointer<Char>? pModelPath = modelPath?.toNativeUtf8().cast<Char>();
    try {
      var err = documentSDK.id3DocumentLibrary_LoadModel(pModelPath ?? nullptr, documentModel.value, processingUnit.value);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pModelPath != null) {
        calloc.free(pModelPath);
      }
    }
  }

  /// Loads a model into memory from the specified buffer.
  ///
  /// param modelBuffer A buffer containing the AI model to be loaded.
  /// param documentModel Doc model to load.
  /// param processingUnit The processing unit to use for the model.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void loadModelBuffer(Uint8List? modelBuffer, DocumentModel documentModel, ProcessingUnit processingUnit) {
    Pointer<UnsignedChar>? pModelBuffer;
    if (modelBuffer != null) {
    	pModelBuffer = calloc.allocate<UnsignedChar>(modelBuffer.length);
    	pModelBuffer.cast<Uint8>().asTypedList(modelBuffer.length).setAll(0, modelBuffer);
    }
    try {
      var err = documentSDK.id3DocumentLibrary_LoadModelBuffer(pModelBuffer ?? nullptr, modelBuffer?.length ?? 0, documentModel.value, processingUnit.value);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pModelBuffer != null) {
        calloc.free(pModelBuffer);
      }
    }
  }

  /// Unloads a document template.
  ///
  /// param documentName The document name.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void unloadDocumentTemplate(String? documentName) {
    Pointer<Char>? pDocumentName = documentName?.toNativeUtf8().cast<Char>();
    try {
      var err = documentSDK.id3DocumentLibrary_UnloadDocumentTemplate(pDocumentName ?? nullptr);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pDocumentName != null) {
        calloc.free(pDocumentName);
      }
    }
  }

  /// Unloads a model from memory.
  ///
  /// param documentModel The AI model to be unloaded.
  /// param processingUnit The processing unit used for the model.
  /// throws DocumentException An error has occurred during Document Library execution.
  static void unloadModel(DocumentModel documentModel, ProcessingUnit processingUnit) {
    var err = documentSDK.id3DocumentLibrary_UnloadModel(documentModel.value, processingUnit.value);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

}

