//--------------------------------------------------------------------------------------------------
// 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.id3DocumentMrzReader_Dispose.cast());

/// Detects and reads an MRZ in an image.
class MrzReader implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3DocumentMrzReader>> _pHandle;
  bool _disposable = true;

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

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

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

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


  ///
  /// Selection of the binarization method internally used in the algorithm.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get binarizationMethod => getBinarizationMethod();
  set binarizationMethod(int value) => setBinarizationMethod(value);

  ///
  /// AI model used to detect the MRZ.
  /// Hint: Default value is MrzDetector2A.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentModel get model => getModel();
  set model(DocumentModel value) => setModel(value);

  ///
  /// Processing unit where to run the detection process.
  /// Hint: Default value is CPU.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  ProcessingUnit get processingUnit => getProcessingUnit();
  set processingUnit(ProcessingUnit value) => setProcessingUnit(value);

  ///
  /// Number of threads to use for reading.
  /// 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 selection of the binarization method internally used in the algorithm.
  ///
  /// return Selection of the binarization method internally used in the algorithm.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getBinarizationMethod() {
    Pointer<Int> pBinarizationMethod = calloc();
    try {
      var err = documentSDK.id3DocumentMrzReader_GetBinarizationMethod(_pHandle.value, pBinarizationMethod);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vBinarizationMethod = pBinarizationMethod.value;
      return vBinarizationMethod;
    } finally {
      calloc.free(pBinarizationMethod);
    }
  }

  /// Sets the selection of the binarization method internally used in the algorithm.
  ///
  /// param binarizationMethod Selection of the binarization method internally used in the algorithm.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setBinarizationMethod(int binarizationMethod) {
    var err = documentSDK.id3DocumentMrzReader_SetBinarizationMethod(_pHandle.value, binarizationMethod);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Gets the AI model used to detect the MRZ.
  /// Hint: Default value is MrzDetector2A.
  ///
  /// return AI model used to detect the MRZ.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentModel getModel() {
    Pointer<Int32> pModel = calloc();
    try {
      var err = documentSDK.id3DocumentMrzReader_GetModel(_pHandle.value, pModel);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vModel = DocumentModelX.fromValue(pModel.value);
      return vModel;
    } finally {
      calloc.free(pModel);
    }
  }

  /// Sets the AI model used to detect the MRZ.
  /// Hint: Default value is MrzDetector2A.
  ///
  /// param model AI model used to detect the MRZ.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setModel(DocumentModel model) {
    var err = documentSDK.id3DocumentMrzReader_SetModel(_pHandle.value, model.value);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Gets the processing unit where to run the detection process.
  /// Hint: Default value is CPU.
  ///
  /// return Processing unit where to run the detection process.
  /// throws DocumentException An error has occurred during Document Library execution.
  ProcessingUnit getProcessingUnit() {
    Pointer<Int32> pProcessingUnit = calloc();
    try {
      var err = documentSDK.id3DocumentMrzReader_GetProcessingUnit(_pHandle.value, pProcessingUnit);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vProcessingUnit = ProcessingUnitX.fromValue(pProcessingUnit.value);
      return vProcessingUnit;
    } finally {
      calloc.free(pProcessingUnit);
    }
  }

  /// Sets the processing unit where to run the detection process.
  /// Hint: Default value is CPU.
  ///
  /// param processingUnit Processing unit where to run the detection process.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setProcessingUnit(ProcessingUnit processingUnit) {
    var err = documentSDK.id3DocumentMrzReader_SetProcessingUnit(_pHandle.value, processingUnit.value);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Gets the number of threads to use for reading.
  /// 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 reading.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getThreadCount() {
    Pointer<Int> pThreadCount = calloc();
    try {
      var err = documentSDK.id3DocumentMrzReader_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 reading.
  /// 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 reading.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setThreadCount(int threadCount) {
    var err = documentSDK.id3DocumentMrzReader_SetThreadCount(_pHandle.value, threadCount);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Detects and reads an MRZ in an image.
  ///
  /// param image Source image to process
  /// return MRZ reading output.
  /// throws DocumentException An error has occurred during Document Library execution.
  MrzReadingResult readMrz(DocumentImage image) {
    MrzReadingResult result = MrzReadingResult();
    var err = documentSDK.id3DocumentMrzReader_ReadMrz(_pHandle.value, image.handle, result.handle);
    if (err != DocumentError.success.value) {
      result.dispose();
      throw DocumentException(err);
    }
    return result;
  }

}

