//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
// ignore_for_file: unused_import
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';

final _finalizer = NativeFinalizer(documentSDK.addresses.id3DocumentReader_Dispose.cast());

/// Reads text field on a document using optical character recognition (OCR).
class DocumentReader implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3DocumentReader>> _pHandle;
  bool _disposable = true;

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

  /// Creates a new instance of the DocumentReader class.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentReader() {
    _pHandle = calloc();
    try {
      var err = documentSDK.id3DocumentReader_Initialize(_pHandle);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

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

  /// Releases all resources used by this DocumentReader.
  void dispose() {
    if (_disposable) {
      documentSDK.id3DocumentReader_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }


  ///
  /// Number of threads to use for OCR.
  /// Hint: Default value is 1. Allocating more than 1 thread here can increase the speed of the process.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get threadCount => getThreadCount();
  set threadCount(int value) => setThreadCount(value);

  // Public methods
  /// Gets the number of threads to use for OCR.
  /// Hint: Default value is 1. Allocating more than 1 thread here can increase the speed of the process.
  ///
  /// return Number of threads to use for OCR.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getThreadCount() {
    Pointer<Int> pThreadCount = calloc();
    try {
      var err = documentSDK.id3DocumentReader_GetThreadCount(_pHandle.value, pThreadCount);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vThreadCount = pThreadCount.value;
      return vThreadCount;
    } finally {
      calloc.free(pThreadCount);
    }
  }

  /// Sets the number of threads to use for OCR.
  /// Hint: Default value is 1. Allocating more than 1 thread here can increase the speed of the process.
  ///
  /// param threadCount Number of threads to use for OCR.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setThreadCount(int threadCount) {
    var err = documentSDK.id3DocumentReader_SetThreadCount(_pHandle.value, threadCount);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Extracts a crop of the face in a document.
  ///
  /// param image The image that contains the document. Must be a realigned BGR image of the document.
  /// param documentName The name of the document to be searched. Must be a key loaded in DocumentLibrary.
  /// return The cropped image of the face.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage extractFace(DocumentImage image, String? documentName) {
    Pointer<Char>? pDocumentName = documentName?.toNativeUtf8().cast<Char>();
    DocumentImage croppedFace = DocumentImage();
    try {
      var err = documentSDK.id3DocumentReader_ExtractFace(_pHandle.value, image.handle, pDocumentName ?? nullptr, croppedFace.handle);
      if (err != DocumentError.success.value) {
        croppedFace.dispose();
        throw DocumentException(err);
      }
      return croppedFace;
    } finally {
      if (pDocumentName != null) {
        calloc.free(pDocumentName);
      }
    }
  }

  /// Reads all the fields in a document.
  ///
  /// param image The image that contains the document. Must be a realigned BGR image of the document.
  /// param documentName The name of the document to be searched. Must be a key loaded in DocumentLibrary.
  /// return A list of all the text fields read in the document.
  /// throws DocumentException An error has occurred during Document Library execution.
  TextFieldList readDocument(DocumentImage image, String? documentName) {
    Pointer<Char>? pDocumentName = documentName?.toNativeUtf8().cast<Char>();
    TextFieldList readTexts = TextFieldList();
    try {
      var err = documentSDK.id3DocumentReader_ReadDocument(_pHandle.value, image.handle, pDocumentName ?? nullptr, readTexts.handle);
      if (err != DocumentError.success.value) {
        readTexts.dispose();
        throw DocumentException(err);
      }
      return readTexts;
    } finally {
      if (pDocumentName != null) {
        calloc.free(pDocumentName);
      }
    }
  }

  /// Reads a single field in a document.
  ///
  /// param image The image that contains the document. Must be a realigned BGR image of the document.
  /// param documentName The name of the document to be searched. Must be a key loaded in DocumentLibrary.
  /// param fieldName The name of the field to search.
  /// return Read Text in the specified field.
  /// throws DocumentException An error has occurred during Document Library execution.
  TextField readField(DocumentImage image, String? documentName, String? fieldName) {
    Pointer<Char>? pDocumentName = documentName?.toNativeUtf8().cast<Char>();
    Pointer<Char>? pFieldName = fieldName?.toNativeUtf8().cast<Char>();
    TextField readText = TextField();
    try {
      var err = documentSDK.id3DocumentReader_ReadField(_pHandle.value, image.handle, pDocumentName ?? nullptr, pFieldName ?? nullptr, readText.handle);
      if (err != DocumentError.success.value) {
        readText.dispose();
        throw DocumentException(err);
      }
      return readText;
    } finally {
      if (pDocumentName != null) {
        calloc.free(pDocumentName);
      }
      if (pFieldName != null) {
        calloc.free(pFieldName);
      }
    }
  }

}

