//--------------------------------------------------------------------------------------------------
// 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 'face_sdk_generated_bindings.dart';
import 'face_native.dart';

import '../id3_face.dart';

final _finalizer = NativeFinalizer(faceSDK.addresses.id3FacePortrait_Dispose.cast());

/// Represents a portrait.
class Portrait implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3FacePortrait>> _pHandle;
  bool _disposable = true;

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

  /// Creates a new instance of the Portrait class.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  Portrait() {
    _pHandle = calloc();
    try {
      var err = faceSDK.id3FacePortrait_Initialize(_pHandle);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

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

  /// Releases all resources used by this Portrait.
  void dispose() {
    if (_disposable) {
      faceSDK.id3FacePortrait_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }

  // Copyable methods

  /// Creates a copy of the Portrait object.
  ///
  /// return The newly created Portrait object.
  /// throws FaceException An error has occurred during Face Library execution.
  Portrait clone() {
    Portrait clone = Portrait();
    var err = faceSDK.id3FacePortrait_CopyTo(_pHandle.value, clone.handle);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
    return clone;
  }


  ///
  /// Estimated age of the subject. -1 if not computed.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get age => getAge();

  ///
  /// Result of the background uniformity computation.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  BackgroundUniformity get backgroundUniformity => getBackgroundUniformity();

  ///
  /// Estimated expression of the subject (angriness, disgust, fear, happiness, sadness, surprise, or neutral). Unknown if not computed.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  FaceExpression get expression => getExpression();

  ///
  /// Estimated gaze.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  EyeGaze get eyeGaze => getEyeGaze();

  ///
  /// Unique face ID.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get faceId => getFaceId();

  ///
  /// Value indicating whether a face mask is detected. The range is 0-100, 100 meaning a mask is detected.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get faceMask => getFaceMask();

  ///
  /// Face template.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  FaceTemplate? get faceTemplate => getFaceTemplate();

  ///
  /// Value indicating whether the subject is a male. -1 if not computed. The range is 0 (female) -100 (male).
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get genderMale => getGenderMale();

  ///
  /// Geometric attributes.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  GeometricAttributes get geometricAttributes => getGeometricAttributes();

  ///
  /// Value indicating whether the subject wears glasses. -1 if not computed. The range is 0-100, 100 meaning glasses are detected.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get glasses => getGlasses();

  ///
  /// Value indicating whether the subject wears a hat. -1 if not computed. The range is 0-100, 100 meaning a hat is detected.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get hat => getHat();

  ///
  /// Source image.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  Image? get image => getImage();

  ///
  /// Center of the portrait in the source image.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  Point get imageCenter => getImageCenter();

  ///
  /// Scale to be applied to the source image to display the portrait.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  double get imageScale => getImageScale();

  ///
  /// Translation to be applied to the source image to display the portrait.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  Point get imageTranslation => getImageTranslation();

  ///
  /// Instruction to be given to the user for portrait capture.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitInstruction get instruction => getInstruction();

  ///
  /// 68-points landmarks.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PointList get landmarks => getLandmarks();

  ///
  /// Value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get leftEyeOpening => getLeftEyeOpening();

  ///
  /// Value estimating the visibility of the left eye. -1 if not computed. The range is 0-100, 100 meaning the left eye is fully visible.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get leftEyeVisibility => getLeftEyeVisibility();

  ///
  /// Value estimating if the user is looking straight towards the camera. -1 if not computed. The range is 0-100, 100 meaning the look is straight.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get lookStraightScore => getLookStraightScore();

  ///
  /// Value indicating whether makeup is detected. -1 if not computed. The range is 0-100, 100 meaning makeup is detected.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get makeup => getMakeup();

  ///
  /// Value indicating estimating the opening of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully open.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get mouthOpening => getMouthOpening();

  ///
  /// Value estimating the visibility of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully visible.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get mouthVisibility => getMouthVisibility();

  ///
  /// Value estimating the visibility of the nose. -1 if not computed. The range is 0-100, 100 meaning the nose is fully visible.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get noseVisibility => getNoseVisibility();

  ///
  /// Score of the presentation attack detection.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get padScore => getPadScore();

  ///
  /// Status of the presentation attack detection.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PadStatus get padStatus => getPadStatus();

  ///
  /// Photographic attributes.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PhotographicAttributes get photographicAttributes => getPhotographicAttributes();

  ///
  /// Face pose.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  FacePose get pose => getPose();

  ///
  /// Quality check points of the portrait.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitQualityCheckpoints get qualityCheckpoints => getQualityCheckpoints();

  ///
  /// Unified quality score, from 0 to 100. -1 if not computed.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get qualityScore => getQualityScore();

  ///
  /// Value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get rightEyeOpening => getRightEyeOpening();

  ///
  /// Value estimating the visibility of the right eye. -1 if not computed. The range is 0-100, 100 meaning the right eye is fully visible.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get rightEyeVisibility => getRightEyeVisibility();

  ///
  /// Value indicating whether the subject is smiling. -1 if not computed. The range is 0-100, 100 meaning the person is smiling.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get smile => getSmile();

  ///
  /// Status of the portrait.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitStatus get status => getStatus();

  ///
  /// Position of the subject in the image.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get subjectPosition => getSubjectPosition();

  ///
  /// Tracked face.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  TrackedFace? get trackedFace => getTrackedFace();

  // Public methods
  /// Gets the estimated age of the subject. -1 if not computed.
  ///
  /// return Estimated age of the subject. -1 if not computed.
  /// throws FaceException An error has occurred during Face Library execution.
  int getAge() {
    Pointer<Int> pAge = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetAge(_pHandle.value, pAge);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vAge = pAge.value;
      return vAge;
    } finally {
      calloc.free(pAge);
    }
  }

  /// Gets the result of the background uniformity computation.
  ///
  /// return Result of the background uniformity computation.
  /// throws FaceException An error has occurred during Face Library execution.
  BackgroundUniformity getBackgroundUniformity() {
    Pointer<id3FaceBackgroundUniformity> pBackgroundUniformity = calloc();
    var err = faceSDK.id3FacePortrait_GetBackgroundUniformity(_pHandle.value, pBackgroundUniformity);
    if (err != FaceError.success.value) {
    	calloc.free(pBackgroundUniformity);
    	throw FaceException(err);
    }
    return BackgroundUniformity(pBackgroundUniformity);
  }

  /// Gets the estimated expression of the subject (angriness, disgust, fear, happiness, sadness, surprise, or neutral). Unknown if not computed.
  ///
  /// return Estimated expression of the subject (angriness, disgust, fear, happiness, sadness, surprise, or neutral). Unknown if not computed.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceExpression getExpression() {
    Pointer<Int32> pExpression = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetExpression(_pHandle.value, pExpression);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vExpression = FaceExpressionX.fromValue(pExpression.value);
      return vExpression;
    } finally {
      calloc.free(pExpression);
    }
  }

  /// Gets the estimated gaze.
  ///
  /// return Estimated gaze.
  /// throws FaceException An error has occurred during Face Library execution.
  EyeGaze getEyeGaze() {
    Pointer<id3FaceEyeGaze> pEyeGaze = calloc();
    var err = faceSDK.id3FacePortrait_GetEyeGaze(_pHandle.value, pEyeGaze);
    if (err != FaceError.success.value) {
    	calloc.free(pEyeGaze);
    	throw FaceException(err);
    }
    return EyeGaze(pEyeGaze);
  }

  /// Gets the unique face ID.
  ///
  /// return Unique face ID.
  /// throws FaceException An error has occurred during Face Library execution.
  int getFaceId() {
    Pointer<Int> pFaceId = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetFaceId(_pHandle.value, pFaceId);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vFaceId = pFaceId.value;
      return vFaceId;
    } finally {
      calloc.free(pFaceId);
    }
  }

  /// Gets the value indicating whether a face mask is detected. The range is 0-100, 100 meaning a mask is detected.
  ///
  /// return Value indicating whether a face mask is detected. The range is 0-100, 100 meaning a mask is detected.
  /// throws FaceException An error has occurred during Face Library execution.
  int getFaceMask() {
    Pointer<Int> pFaceMask = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetFaceMask(_pHandle.value, pFaceMask);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vFaceMask = pFaceMask.value;
      return vFaceMask;
    } finally {
      calloc.free(pFaceMask);
    }
  }

  /// Gets the face template.
  ///
  /// return Face template.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceTemplate? getFaceTemplate() {
    FaceTemplate faceTemplate = FaceTemplate();
    var err = faceSDK.id3FacePortrait_GetFaceTemplate(_pHandle.value, faceTemplate.handle);
    if (err == FaceError.objectDoesNotExist.value) {
      faceTemplate.dispose();
      return null;
    }
    if (err != FaceError.success.value) {
      faceTemplate.dispose();
      throw FaceException(err);
    }
    return faceTemplate;
  }

  /// Gets the value indicating whether the subject is a male. -1 if not computed. The range is 0 (female) -100 (male).
  ///
  /// return Value indicating whether the subject is a male. -1 if not computed. The range is 0 (female) -100 (male).
  /// throws FaceException An error has occurred during Face Library execution.
  int getGenderMale() {
    Pointer<Int> pGenderMale = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetGenderMale(_pHandle.value, pGenderMale);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vGenderMale = pGenderMale.value;
      return vGenderMale;
    } finally {
      calloc.free(pGenderMale);
    }
  }

  /// Gets the geometric attributes.
  ///
  /// return Geometric attributes.
  /// throws FaceException An error has occurred during Face Library execution.
  GeometricAttributes getGeometricAttributes() {
    Pointer<id3FaceGeometricAttributes> pGeometricAttributes = calloc();
    var err = faceSDK.id3FacePortrait_GetGeometricAttributes(_pHandle.value, pGeometricAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pGeometricAttributes);
    	throw FaceException(err);
    }
    return GeometricAttributes(pGeometricAttributes);
  }

  /// Gets the value indicating whether the subject wears glasses. -1 if not computed. The range is 0-100, 100 meaning glasses are detected.
  ///
  /// return Value indicating whether the subject wears glasses. -1 if not computed. The range is 0-100, 100 meaning glasses are detected.
  /// throws FaceException An error has occurred during Face Library execution.
  int getGlasses() {
    Pointer<Int> pGlasses = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetGlasses(_pHandle.value, pGlasses);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vGlasses = pGlasses.value;
      return vGlasses;
    } finally {
      calloc.free(pGlasses);
    }
  }

  /// Gets the value indicating whether the subject wears a hat. -1 if not computed. The range is 0-100, 100 meaning a hat is detected.
  ///
  /// return Value indicating whether the subject wears a hat. -1 if not computed. The range is 0-100, 100 meaning a hat is detected.
  /// throws FaceException An error has occurred during Face Library execution.
  int getHat() {
    Pointer<Int> pHat = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetHat(_pHandle.value, pHat);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vHat = pHat.value;
      return vHat;
    } finally {
      calloc.free(pHat);
    }
  }

  /// Gets the source image.
  ///
  /// return Source image.
  /// throws FaceException An error has occurred during Face Library execution.
  Image? getImage() {
    Image image = Image();
    var err = faceSDK.id3FacePortrait_GetImage(_pHandle.value, image.handle);
    if (err == FaceError.objectDoesNotExist.value) {
      image.dispose();
      return null;
    }
    if (err != FaceError.success.value) {
      image.dispose();
      throw FaceException(err);
    }
    return image;
  }

  /// Gets the center of the portrait in the source image.
  ///
  /// return Center of the portrait in the source image.
  /// throws FaceException An error has occurred during Face Library execution.
  Point getImageCenter() {
    Pointer<id3FacePoint> pImageCenter = calloc();
    var err = faceSDK.id3FacePortrait_GetImageCenter(_pHandle.value, pImageCenter);
    if (err != FaceError.success.value) {
    	calloc.free(pImageCenter);
    	throw FaceException(err);
    }
    return Point(pImageCenter);
  }

  /// Gets the scale to be applied to the source image to display the portrait.
  ///
  /// return Scale to be applied to the source image to display the portrait.
  /// throws FaceException An error has occurred during Face Library execution.
  double getImageScale() {
    Pointer<Float> pImageScale = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetImageScale(_pHandle.value, pImageScale);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vImageScale = pImageScale.value;
      return vImageScale;
    } finally {
      calloc.free(pImageScale);
    }
  }

  /// Gets the translation to be applied to the source image to display the portrait.
  ///
  /// return Translation to be applied to the source image to display the portrait.
  /// throws FaceException An error has occurred during Face Library execution.
  Point getImageTranslation() {
    Pointer<id3FacePoint> pImageTranslation = calloc();
    var err = faceSDK.id3FacePortrait_GetImageTranslation(_pHandle.value, pImageTranslation);
    if (err != FaceError.success.value) {
    	calloc.free(pImageTranslation);
    	throw FaceException(err);
    }
    return Point(pImageTranslation);
  }

  /// Gets the instruction to be given to the user for portrait capture.
  ///
  /// return Instruction to be given to the user for portrait capture.
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitInstruction getInstruction() {
    Pointer<Int32> pInstruction = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetInstruction(_pHandle.value, pInstruction);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vInstruction = PortraitInstructionX.fromValue(pInstruction.value);
      return vInstruction;
    } finally {
      calloc.free(pInstruction);
    }
  }

  /// Gets the 68-points landmarks.
  ///
  /// return 68-points landmarks.
  /// throws FaceException An error has occurred during Face Library execution.
  PointList getLandmarks() {
    PointList landmarks = PointList();
    var err = faceSDK.id3FacePortrait_GetLandmarks(_pHandle.value, landmarks.handle);
    if (err != FaceError.success.value) {
      landmarks.dispose();
      throw FaceException(err);
    }
    return landmarks;
  }

  /// Gets the value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  ///
  /// return Value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  /// throws FaceException An error has occurred during Face Library execution.
  int getLeftEyeOpening() {
    Pointer<Int> pLeftEyeOpening = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetLeftEyeOpening(_pHandle.value, pLeftEyeOpening);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vLeftEyeOpening = pLeftEyeOpening.value;
      return vLeftEyeOpening;
    } finally {
      calloc.free(pLeftEyeOpening);
    }
  }

  /// Gets the value estimating the visibility of the left eye. -1 if not computed. The range is 0-100, 100 meaning the left eye is fully visible.
  ///
  /// return Value estimating the visibility of the left eye. -1 if not computed. The range is 0-100, 100 meaning the left eye is fully visible.
  /// throws FaceException An error has occurred during Face Library execution.
  int getLeftEyeVisibility() {
    Pointer<Int> pLeftEyeVisibility = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetLeftEyeVisibility(_pHandle.value, pLeftEyeVisibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vLeftEyeVisibility = pLeftEyeVisibility.value;
      return vLeftEyeVisibility;
    } finally {
      calloc.free(pLeftEyeVisibility);
    }
  }

  /// Gets the value estimating if the user is looking straight towards the camera. -1 if not computed. The range is 0-100, 100 meaning the look is straight.
  ///
  /// return Value estimating if the user is looking straight towards the camera. -1 if not computed. The range is 0-100, 100 meaning the look is straight.
  /// throws FaceException An error has occurred during Face Library execution.
  int getLookStraightScore() {
    Pointer<Int> pLookStraightScore = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetLookStraightScore(_pHandle.value, pLookStraightScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vLookStraightScore = pLookStraightScore.value;
      return vLookStraightScore;
    } finally {
      calloc.free(pLookStraightScore);
    }
  }

  /// Gets the value indicating whether makeup is detected. -1 if not computed. The range is 0-100, 100 meaning makeup is detected.
  ///
  /// return Value indicating whether makeup is detected. -1 if not computed. The range is 0-100, 100 meaning makeup is detected.
  /// throws FaceException An error has occurred during Face Library execution.
  int getMakeup() {
    Pointer<Int> pMakeup = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetMakeup(_pHandle.value, pMakeup);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vMakeup = pMakeup.value;
      return vMakeup;
    } finally {
      calloc.free(pMakeup);
    }
  }

  /// Gets the value indicating estimating the opening of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully open.
  ///
  /// return Value indicating estimating the opening of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully open.
  /// throws FaceException An error has occurred during Face Library execution.
  int getMouthOpening() {
    Pointer<Int> pMouthOpening = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetMouthOpening(_pHandle.value, pMouthOpening);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vMouthOpening = pMouthOpening.value;
      return vMouthOpening;
    } finally {
      calloc.free(pMouthOpening);
    }
  }

  /// Gets the value estimating the visibility of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully visible.
  ///
  /// return Value estimating the visibility of the mouth. -1 if not computed. The range is 0-100, 100 meaning the mouth is fully visible.
  /// throws FaceException An error has occurred during Face Library execution.
  int getMouthVisibility() {
    Pointer<Int> pMouthVisibility = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetMouthVisibility(_pHandle.value, pMouthVisibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vMouthVisibility = pMouthVisibility.value;
      return vMouthVisibility;
    } finally {
      calloc.free(pMouthVisibility);
    }
  }

  /// Gets the value estimating the visibility of the nose. -1 if not computed. The range is 0-100, 100 meaning the nose is fully visible.
  ///
  /// return Value estimating the visibility of the nose. -1 if not computed. The range is 0-100, 100 meaning the nose is fully visible.
  /// throws FaceException An error has occurred during Face Library execution.
  int getNoseVisibility() {
    Pointer<Int> pNoseVisibility = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetNoseVisibility(_pHandle.value, pNoseVisibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vNoseVisibility = pNoseVisibility.value;
      return vNoseVisibility;
    } finally {
      calloc.free(pNoseVisibility);
    }
  }

  /// Gets the score of the presentation attack detection.
  ///
  /// return Score of the presentation attack detection.
  /// throws FaceException An error has occurred during Face Library execution.
  int getPadScore() {
    Pointer<Int> pPadScore = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetPadScore(_pHandle.value, pPadScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vPadScore = pPadScore.value;
      return vPadScore;
    } finally {
      calloc.free(pPadScore);
    }
  }

  /// Gets the status of the presentation attack detection.
  ///
  /// return Status of the presentation attack detection.
  /// throws FaceException An error has occurred during Face Library execution.
  PadStatus getPadStatus() {
    Pointer<Int32> pPadStatus = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetPadStatus(_pHandle.value, pPadStatus);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vPadStatus = PadStatusX.fromValue(pPadStatus.value);
      return vPadStatus;
    } finally {
      calloc.free(pPadStatus);
    }
  }

  /// Gets the photographic attributes.
  ///
  /// return Photographic attributes.
  /// throws FaceException An error has occurred during Face Library execution.
  PhotographicAttributes getPhotographicAttributes() {
    Pointer<id3FacePhotographicAttributes> pPhotographicAttributes = calloc();
    var err = faceSDK.id3FacePortrait_GetPhotographicAttributes(_pHandle.value, pPhotographicAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pPhotographicAttributes);
    	throw FaceException(err);
    }
    return PhotographicAttributes(pPhotographicAttributes);
  }

  /// Gets the face pose.
  ///
  /// return Face pose.
  /// throws FaceException An error has occurred during Face Library execution.
  FacePose getPose() {
    Pointer<id3FacePose> pPose = calloc();
    var err = faceSDK.id3FacePortrait_GetPose(_pHandle.value, pPose);
    if (err != FaceError.success.value) {
    	calloc.free(pPose);
    	throw FaceException(err);
    }
    return FacePose(pPose);
  }

  /// Gets the quality check points of the portrait.
  ///
  /// return Quality check points of the portrait.
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitQualityCheckpoints getQualityCheckpoints() {
    Pointer<id3FacePortraitQualityCheckpoints> pQualityCheckpoints = calloc();
    var err = faceSDK.id3FacePortrait_GetQualityCheckpoints(_pHandle.value, pQualityCheckpoints);
    if (err != FaceError.success.value) {
    	calloc.free(pQualityCheckpoints);
    	throw FaceException(err);
    }
    return PortraitQualityCheckpoints(pQualityCheckpoints);
  }

  /// Gets the unified quality score, from 0 to 100. -1 if not computed.
  ///
  /// return Unified quality score, from 0 to 100. -1 if not computed.
  /// throws FaceException An error has occurred during Face Library execution.
  int getQualityScore() {
    Pointer<Int> pQualityScore = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetQualityScore(_pHandle.value, pQualityScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vQualityScore = pQualityScore.value;
      return vQualityScore;
    } finally {
      calloc.free(pQualityScore);
    }
  }

  /// Gets the value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  ///
  /// return Value estimating the opening of the left eye. -1 if not computed. The range is 0-100, 100 meaning the eye is fully opened.
  /// throws FaceException An error has occurred during Face Library execution.
  int getRightEyeOpening() {
    Pointer<Int> pRightEyeOpening = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetRightEyeOpening(_pHandle.value, pRightEyeOpening);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vRightEyeOpening = pRightEyeOpening.value;
      return vRightEyeOpening;
    } finally {
      calloc.free(pRightEyeOpening);
    }
  }

  /// Gets the value estimating the visibility of the right eye. -1 if not computed. The range is 0-100, 100 meaning the right eye is fully visible.
  ///
  /// return Value estimating the visibility of the right eye. -1 if not computed. The range is 0-100, 100 meaning the right eye is fully visible.
  /// throws FaceException An error has occurred during Face Library execution.
  int getRightEyeVisibility() {
    Pointer<Int> pRightEyeVisibility = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetRightEyeVisibility(_pHandle.value, pRightEyeVisibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vRightEyeVisibility = pRightEyeVisibility.value;
      return vRightEyeVisibility;
    } finally {
      calloc.free(pRightEyeVisibility);
    }
  }

  /// Gets the value indicating whether the subject is smiling. -1 if not computed. The range is 0-100, 100 meaning the person is smiling.
  ///
  /// return Value indicating whether the subject is smiling. -1 if not computed. The range is 0-100, 100 meaning the person is smiling.
  /// throws FaceException An error has occurred during Face Library execution.
  int getSmile() {
    Pointer<Int> pSmile = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetSmile(_pHandle.value, pSmile);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vSmile = pSmile.value;
      return vSmile;
    } finally {
      calloc.free(pSmile);
    }
  }

  /// Gets the status of the portrait.
  ///
  /// return Status of the portrait.
  /// throws FaceException An error has occurred during Face Library execution.
  PortraitStatus getStatus() {
    Pointer<Int32> pStatus = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetStatus(_pHandle.value, pStatus);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vStatus = PortraitStatusX.fromValue(pStatus.value);
      return vStatus;
    } finally {
      calloc.free(pStatus);
    }
  }

  /// Gets the position of the subject in the image.
  ///
  /// return Position of the subject in the image.
  /// throws FaceException An error has occurred during Face Library execution.
  int getSubjectPosition() {
    Pointer<Int32> pSubjectPosition = calloc();
    try {
      var err = faceSDK.id3FacePortrait_GetSubjectPosition(_pHandle.value, pSubjectPosition);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vSubjectPosition = pSubjectPosition.value;
      return vSubjectPosition;
    } finally {
      calloc.free(pSubjectPosition);
    }
  }

  /// Gets the tracked face.
  ///
  /// return Tracked face.
  /// throws FaceException An error has occurred during Face Library execution.
  TrackedFace? getTrackedFace() {
    TrackedFace trackedFace = TrackedFace();
    var err = faceSDK.id3FacePortrait_GetTrackedFace(_pHandle.value, trackedFace.handle);
    if (err == FaceError.objectDoesNotExist.value) {
      trackedFace.dispose();
      return null;
    }
    if (err != FaceError.success.value) {
      trackedFace.dispose();
      throw FaceException(err);
    }
    return trackedFace;
  }

  /// Clears all attributes.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  void clear() {
    var err = faceSDK.id3FacePortrait_Clear(_pHandle.value);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Imports the portrait object from a buffer.
  ///
  /// param data Buffer to import the portrait object from.
  /// return The newly created portrait.
  /// throws FaceException An error has occurred during Face Library execution.
  static Portrait fromBuffer(Uint8List? data) {
    Portrait portrait = Portrait();
    Pointer<UnsignedChar>? pData;
    if (data != null) {
    	pData = calloc.allocate<UnsignedChar>(data.length);
    	pData.cast<Uint8>().asTypedList(data.length).setAll(0, data);
    }
    try {
      var err = faceSDK.id3FacePortrait_FromBuffer(portrait.handle, pData ?? nullptr, data?.length ?? 0);
      if (err != FaceError.success.value) {
        portrait.dispose();
        throw FaceException(err);
      }
      return portrait;
    } finally {
      if (pData != null) {
        calloc.free(pData);
      }
    }
  }

  /// Exports the portrait to a buffer.
  ///
  /// return The buffer to which the portrait object is exported.
  /// throws FaceException An error has occurred during Face Library execution.
  Uint8List toBuffer() {
    Pointer<UnsignedChar> pData = nullptr;
    Pointer<Int> pDataSize = calloc();
    pDataSize[0] = -1;
    try {
      var err = faceSDK.id3FacePortrait_ToBuffer(_pHandle.value, pData, pDataSize);
      if (err == FaceError.insufficientBuffer.value) {
        pData = calloc.allocate(pDataSize.value);
        err = faceSDK.id3FacePortrait_ToBuffer(_pHandle.value, pData, pDataSize);
      }
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vData = Uint8List.fromList(pData.cast<Uint8>().asTypedList(pDataSize.value));
      return vData;
    } finally {
      calloc.free(pData);
      calloc.free(pDataSize);
    }
  }

}

