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

/// Represents a detected document.
class DetectedDocument implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3DetectedDocument>> _pHandle;
  bool _disposable = true;

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

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

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

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

  // Copyable methods

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


  ///
  /// Boundaries of the document detected, in the following order: top-left, top-right, bottom-right, bottom-left.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  PointList get bounds => getBounds();
  set bounds(PointList value) => setBounds(value);

  ///
  /// Confidence score of the detected document, from 0 to 100.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get confidence => getConfidence();

  ///
  /// Document information.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentInfo get info => getInfo();

  ///
  /// Document orientation in source image. [0,0,0] means the document is in front of the camera.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentOrientation get orientation => getOrientation();

  // Public methods
  /// Gets the boundaries of the document detected, in the following order: top-left, top-right, bottom-right, bottom-left.
  ///
  /// return Boundaries of the document detected, in the following order: top-left, top-right, bottom-right, bottom-left.
  /// throws DocumentException An error has occurred during Document Library execution.
  PointList getBounds() {
    PointList bounds = PointList();
    var err = documentSDK.id3DetectedDocument_GetBounds(_pHandle.value, bounds.handle);
    if (err != DocumentError.success.value) {
      bounds.dispose();
      throw DocumentException(err);
    }
    return bounds;
  }

  /// Sets the boundaries of the document detected, in the following order: top-left, top-right, bottom-right, bottom-left.
  ///
  /// param bounds Boundaries of the document detected, in the following order: top-left, top-right, bottom-right, bottom-left.
  /// throws DocumentException An error has occurred during Document Library execution.
  void setBounds(PointList bounds) {
    var err = documentSDK.id3DetectedDocument_SetBounds(_pHandle.value, bounds.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Gets the confidence score of the detected document, from 0 to 100.
  ///
  /// return Confidence score of the detected document, from 0 to 100.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getConfidence() {
    Pointer<Int> pConfidence = calloc();
    try {
      var err = documentSDK.id3DetectedDocument_GetConfidence(_pHandle.value, pConfidence);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vConfidence = pConfidence.value;
      return vConfidence;
    } finally {
      calloc.free(pConfidence);
    }
  }

  /// Gets the document information.
  ///
  /// return Document information.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentInfo getInfo() {
    DocumentInfo info = DocumentInfo();
    var err = documentSDK.id3DetectedDocument_GetInfo(_pHandle.value, info.handle);
    if (err != DocumentError.success.value) {
      info.dispose();
      throw DocumentException(err);
    }
    return info;
  }

  /// Gets the document orientation in source image. (0,0,0) means the document is in front of the camera.
  ///
  /// return Document orientation in source image. (0,0,0) means the document is in front of the camera.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentOrientation getOrientation() {
    Pointer<id3DocumentOrientation> pOrientation = calloc();
    var err = documentSDK.id3DetectedDocument_GetOrientation(_pHandle.value, pOrientation);
    if (err != DocumentError.success.value) {
    	calloc.free(pOrientation);
    	throw DocumentException(err);
    }
    return DocumentOrientation(pOrientation);
  }

}

