//--------------------------------------------------------------------------------------------------
// 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';

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

/// Represents document information.
class DocumentInfo implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3DocumentInfo>> _pHandle;
  bool _disposable = true;

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

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

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

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

  // Copyable methods

  /// Creates a copy of the DocumentInfo object.
  ///
  /// return The newly created DocumentInfo object.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentInfo clone() {
    DocumentInfo clone = DocumentInfo();
    var err = documentSDK.id3DocumentInfo_CopyTo(_pHandle.value, clone.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
    return clone;
  }


  ///
  /// The document category.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentCategory get category => getCategory();

  ///
  /// The ISO 3166-1 alpha-3 code identifying the country issuing the document.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  String get country => getCountry();

  ///
  /// The document's date of first issue, in the form `YYYY-MM-DD`.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  String get date => getDate();

  ///
  /// The document description.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  String get description => getDescription();

  ///
  /// The document format.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentFormat get format => getFormat();

  ///
  /// The document identifier.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  String get identifier => getIdentifier();

  ///
  /// The type of machine-readable zone (MRZ), if applicable.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  MrzType get mrzType => getMrzType();

  ///
  /// The document type name.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  String get name => getName();

  ///
  /// The page number of the document.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get pageNumber => getPageNumber();

  // Public methods
  /// Gets the the document category.
  ///
  /// return The document category.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentCategory getCategory() {
    Pointer<Int32> pCategory = calloc();
    try {
      var err = documentSDK.id3DocumentInfo_GetCategory(_pHandle.value, pCategory);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vCategory = DocumentCategoryX.fromValue(pCategory.value);
      return vCategory;
    } finally {
      calloc.free(pCategory);
    }
  }

  /// Gets the the ISO 3166-1 alpha-3 code identifying the country issuing the document.
  ///
  /// return The ISO 3166-1 alpha-3 code identifying the country issuing the document.
  /// throws DocumentException An error has occurred during Document Library execution.
  String getCountry() {
    Pointer<Char> pCountry = nullptr;
    Pointer<Int> pCountrySize = calloc.allocate(1);
    pCountrySize[0] = -1;
    try {
      var err = documentSDK.id3DocumentInfo_GetCountry(_pHandle.value, pCountry, pCountrySize);
      if (err == DocumentError.insufficientBuffer.value) {
        pCountry = calloc.allocate(pCountrySize.value);
        err = documentSDK.id3DocumentInfo_GetCountry(_pHandle.value, pCountry, pCountrySize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vCountry = utf8.decode(Uint8List.fromList(pCountry.cast<Uint8>().asTypedList(pCountrySize.value)));
      return vCountry;
    } finally {
      calloc.free(pCountry);
      calloc.free(pCountrySize);
    }
  }

  /// Gets the the document's date of first issue, in the form `YYYY-MM-DD`.
  ///
  /// return The document's date of first issue, in the form `YYYY-MM-DD`.
  /// throws DocumentException An error has occurred during Document Library execution.
  String getDate() {
    Pointer<Char> pDate = nullptr;
    Pointer<Int> pDateSize = calloc.allocate(1);
    pDateSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentInfo_GetDate(_pHandle.value, pDate, pDateSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pDate = calloc.allocate(pDateSize.value);
        err = documentSDK.id3DocumentInfo_GetDate(_pHandle.value, pDate, pDateSize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vDate = utf8.decode(Uint8List.fromList(pDate.cast<Uint8>().asTypedList(pDateSize.value)));
      return vDate;
    } finally {
      calloc.free(pDate);
      calloc.free(pDateSize);
    }
  }

  /// Gets the the document description.
  ///
  /// return The document description.
  /// throws DocumentException An error has occurred during Document Library execution.
  String getDescription() {
    Pointer<Char> pDescription = nullptr;
    Pointer<Int> pDescriptionSize = calloc.allocate(1);
    pDescriptionSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentInfo_GetDescription(_pHandle.value, pDescription, pDescriptionSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pDescription = calloc.allocate(pDescriptionSize.value);
        err = documentSDK.id3DocumentInfo_GetDescription(_pHandle.value, pDescription, pDescriptionSize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vDescription = utf8.decode(Uint8List.fromList(pDescription.cast<Uint8>().asTypedList(pDescriptionSize.value)));
      return vDescription;
    } finally {
      calloc.free(pDescription);
      calloc.free(pDescriptionSize);
    }
  }

  /// Gets the the document format.
  ///
  /// return The document format.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentFormat getFormat() {
    Pointer<Int32> pFormat = calloc();
    try {
      var err = documentSDK.id3DocumentInfo_GetFormat(_pHandle.value, pFormat);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vFormat = DocumentFormatX.fromValue(pFormat.value);
      return vFormat;
    } finally {
      calloc.free(pFormat);
    }
  }

  /// Gets the the document identifier.
  ///
  /// return The document identifier.
  /// throws DocumentException An error has occurred during Document Library execution.
  String getIdentifier() {
    Pointer<Char> pIdentifier = nullptr;
    Pointer<Int> pIdentifierSize = calloc.allocate(1);
    pIdentifierSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentInfo_GetIdentifier(_pHandle.value, pIdentifier, pIdentifierSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pIdentifier = calloc.allocate(pIdentifierSize.value);
        err = documentSDK.id3DocumentInfo_GetIdentifier(_pHandle.value, pIdentifier, pIdentifierSize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vIdentifier = utf8.decode(Uint8List.fromList(pIdentifier.cast<Uint8>().asTypedList(pIdentifierSize.value)));
      return vIdentifier;
    } finally {
      calloc.free(pIdentifier);
      calloc.free(pIdentifierSize);
    }
  }

  /// Gets the the type of machine-readable zone (MRZ), if applicable.
  ///
  /// return The type of machine-readable zone (MRZ), if applicable.
  /// throws DocumentException An error has occurred during Document Library execution.
  MrzType getMrzType() {
    Pointer<Int32> pMrzType = calloc();
    try {
      var err = documentSDK.id3DocumentInfo_GetMrzType(_pHandle.value, pMrzType);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vMrzType = MrzTypeX.fromValue(pMrzType.value);
      return vMrzType;
    } finally {
      calloc.free(pMrzType);
    }
  }

  /// Gets the the document type name.
  ///
  /// return The document type name.
  /// throws DocumentException An error has occurred during Document Library execution.
  String getName() {
    Pointer<Char> pName = nullptr;
    Pointer<Int> pNameSize = calloc.allocate(1);
    pNameSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentInfo_GetName(_pHandle.value, pName, pNameSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pName = calloc.allocate(pNameSize.value);
        err = documentSDK.id3DocumentInfo_GetName(_pHandle.value, pName, pNameSize);
        if (err != DocumentError.success.value) {
          throw DocumentException(err);
        }
      }
      final vName = utf8.decode(Uint8List.fromList(pName.cast<Uint8>().asTypedList(pNameSize.value)));
      return vName;
    } finally {
      calloc.free(pName);
      calloc.free(pNameSize);
    }
  }

  /// Gets the the page number of the document.
  ///
  /// return The page number of the document.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getPageNumber() {
    Pointer<Int> pPageNumber = calloc();
    try {
      var err = documentSDK.id3DocumentInfo_GetPageNumber(_pHandle.value, pPageNumber);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vPageNumber = pPageNumber.value;
      return vPageNumber;
    } finally {
      calloc.free(pPageNumber);
    }
  }

}

