//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
// ignore_for_file: unused_import
import 'dart:collection';
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'bioseal_sdk_generated_bindings.dart';
import 'bioseal_native.dart';

import '../id3_bioseal.dart';

final _finalizer = NativeFinalizer(biosealSDK.addresses.id3BiosealLog_Dispose.cast());

/// Represents the log.
class Log extends Object with IterableMixin<LogItem> implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3BiosealLog>> _pHandle;
  bool _disposable = true;

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

  /// Creates a new instance of the Log class.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Log() {
    _pHandle = calloc();
    try {
      var err = biosealSDK.id3BiosealLog_Initialize(_pHandle);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

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

  /// Releases all resources used by this Log.
  void dispose() {
    if (_disposable) {
      biosealSDK.id3BiosealLog_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }

  /// Gets or sets the element at the specified index.
  operator [](int key) => get(key);

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

  @override
  Iterator<LogItem> get iterator => LogIterator(this);

  // Public methods
  /// Gets an item of the Log object.
  ///
  /// param index Index of the LogItem item to get.
  /// return LogItem item to get.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  LogItem get(int index) {
    LogItem logItemItem = LogItem();
    var err = biosealSDK.id3BiosealLog_Get(_pHandle.value, index, logItemItem.handle);
    if (err != BiosealError.success.value) {
      logItemItem.dispose();
      throw BiosealException(err);
    }
    return logItemItem;
  }

  /// Gets the number of elements in the Log object.
  ///
  /// return Number of elements in the LogItem object.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  int getCount() {
    Pointer<Int> pCount = calloc();
    try {
      var err = biosealSDK.id3BiosealLog_GetCount(_pHandle.value, pCount);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      final vCount = pCount.value;
      return vCount;
    } finally {
      calloc.free(pCount);
    }
  }

  /// Exports a representation of the log, in JSON format.
  ///
  /// param indentation The indentation of the json string.
  /// param debug Indicates whether debug information is added to the log.
  /// return The result.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String exportToJson(String? indentation, bool debug) {
    Pointer<Char>? pIndentation = indentation?.toNativeUtf8().cast<Char>();
    Pointer<Char> pResult = nullptr;
    Pointer<Int> pResultSize = calloc.allocate(1);
    pResultSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealLog_ExportToJson(_pHandle.value, pIndentation ?? nullptr, debug, pResult, pResultSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pResult = calloc.allocate(pResultSize.value);
        err = biosealSDK.id3BiosealLog_ExportToJson(_pHandle.value, pIndentation ?? nullptr, debug, pResult, pResultSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vResult = utf8.decode(Uint8List.fromList(pResult.cast<Uint8>().asTypedList(pResultSize.value)));
      return vResult;
    } finally {
      if (pIndentation != null) {
        calloc.free(pIndentation);
      }
      calloc.free(pResult);
      calloc.free(pResultSize);
    }
  }

  /// Exports a representation of the log, in HTML format.
  ///
  /// param debug Indicates whether debug information is added to the log.
  /// return The result.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String exportToHtml(bool debug) {
    Pointer<Char> pResult = nullptr;
    Pointer<Int> pResultSize = calloc.allocate(1);
    pResultSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealLog_ExportToHtml(_pHandle.value, debug, pResult, pResultSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pResult = calloc.allocate(pResultSize.value);
        err = biosealSDK.id3BiosealLog_ExportToHtml(_pHandle.value, debug, pResult, pResultSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vResult = utf8.decode(Uint8List.fromList(pResult.cast<Uint8>().asTypedList(pResultSize.value)));
      return vResult;
    } finally {
      calloc.free(pResult);
      calloc.free(pResultSize);
    }
  }

}

class LogIterator implements Iterator<LogItem> {
  LogIterator(this._list) : _count = _list.getCount();
  final Log _list;
  final int _count;
  int _index = -1;

  @override
  LogItem get current => _list.get(_index);

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