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

/// This class represents a ImageDict
class ImageDict extends Object with IterableMixin<Image> implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3FaceImageDict>> _pHandle;
  bool _disposable = true;

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

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

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

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

  // Copyable methods

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

  /// Gets or sets the element at the specified index.
  operator [](String key) => get(key);
  operator []=(String key, Image item) => set(key, item);

  /// Gets the number of elements contained in the list or dictionary.
  int get count => getCount();

  @override
  Iterator<Image> get iterator => ImageDictIterator(this);

  ///
  /// Gets a string list containing the keys in the dict.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  StringList get keys => getKeys();

  // Public methods
  /// Clears the ImageDict object.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  void clear() {
    var err = faceSDK.id3FaceImageDict_Clear(_pHandle.value);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Adds an item to the ImageDict object.
  ///
  /// param key Unique key of the Image item to add.
  /// param imageItem Image item to add.
  /// throws FaceException An error has occurred during Face Library execution.
  void add(String? key, Image imageItem) {
    Pointer<Char>? pKey = key?.toNativeUtf8().cast<Char>();
    try {
      var err = faceSDK.id3FaceImageDict_Add(_pHandle.value, pKey ?? nullptr, imageItem.handle);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
    } finally {
      if (pKey != null) {
        calloc.free(pKey);
      }
    }
  }

  /// Gets an item of the ImageDict object.
  ///
  /// param key Unique key of the Image item to get.
  /// return Image item to get.
  /// throws FaceException An error has occurred during Face Library execution.
  Image get(String? key) {
    Pointer<Char>? pKey = key?.toNativeUtf8().cast<Char>();
    Image imageItem = Image();
    try {
      var err = faceSDK.id3FaceImageDict_Get(_pHandle.value, pKey ?? nullptr, imageItem.handle);
      if (err != FaceError.success.value) {
        imageItem.dispose();
        throw FaceException(err);
      }
      return imageItem;
    } finally {
      if (pKey != null) {
        calloc.free(pKey);
      }
    }
  }

  /// Sets an item of the ImageDict object.
  ///
  /// param key Unique key of the Image item to set.
  /// param imageItem Image item to set.
  /// throws FaceException An error has occurred during Face Library execution.
  void set(String? key, Image imageItem) {
    Pointer<Char>? pKey = key?.toNativeUtf8().cast<Char>();
    try {
      var err = faceSDK.id3FaceImageDict_Set(_pHandle.value, pKey ?? nullptr, imageItem.handle);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
    } finally {
      if (pKey != null) {
        calloc.free(pKey);
      }
    }
  }

  /// Gets the number of elements in the ImageDict object.
  ///
  /// return Number of elements in the Image object.
  /// throws FaceException An error has occurred during Face Library execution.
  int getCount() {
    Pointer<Int> pCount = calloc();
    try {
      var err = faceSDK.id3FaceImageDict_GetCount(_pHandle.value, pCount);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vCount = pCount.value;
      return vCount;
    } finally {
      calloc.free(pCount);
    }
  }

  /// Determines whether the ImageDictobject contains the specified key.
  ///
  /// param key The key to locate in the Image object.
  /// return true if the Image object contains an element with the specified key, otherwise false.
  /// throws FaceException An error has occurred during Face Library execution.
  bool containsKey(String? key) {
    Pointer<Char>? pKey = key?.toNativeUtf8().cast<Char>();
    Pointer<Bool> pResult = calloc();
    try {
      var err = faceSDK.id3FaceImageDict_ContainsKey(_pHandle.value, pKey ?? nullptr, pResult);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vResult = pResult.value;
      return vResult;
    } finally {
      if (pKey != null) {
        calloc.free(pKey);
      }
      calloc.free(pResult);
    }
  }

  /// Removes an element of the ImageDict object.
  ///
  /// param key Unique key of the Image item to remove.
  /// throws FaceException An error has occurred during Face Library execution.
  void remove(String? key) {
    Pointer<Char>? pKey = key?.toNativeUtf8().cast<Char>();
    try {
      var err = faceSDK.id3FaceImageDict_Remove(_pHandle.value, pKey ?? nullptr);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
    } finally {
      if (pKey != null) {
        calloc.free(pKey);
      }
    }
  }

  /// Gets the gets a string list containing the keys in the dict.
  ///
  /// return Gets a string list containing the keys in the dict.
  /// throws FaceException An error has occurred during Face Library execution.
  StringList getKeys() {
    StringList keys = StringList();
    var err = faceSDK.id3FaceImageDict_GetKeys(_pHandle.value, keys.handle);
    if (err != FaceError.success.value) {
      keys.dispose();
      throw FaceException(err);
    }
    return keys;
  }

}

class ImageDictIterator implements Iterator<Image> {
  ImageDictIterator(this._list)
      : _count = _list.getCount(),
        _keys = [] {
    final StringList keys = _list.getKeys();
    for (var key in keys) {
      _keys.add(key);
    }
    keys.dispose();
  }
  final ImageDict _list;
  final int _count;
  int _index = -1;
  final List<String> _keys;

  @override
  Image get current => _list.get(_keys[_index]);

  @override
  bool moveNext() {
    _index++;
    return _index < _count;
  }
}
