import 'package:petitparser/core.dart';

import '../xml/entities/entity_mapping.dart';
import '../xml/exceptions/parser_exception.dart';
import 'annotations/annotator.dart';
import 'event.dart';
import 'parser.dart';

class XmlEventIterator implements Iterator<XmlEvent> {
  XmlEventIterator(
    String input,
    XmlEntityMapping entityMapping,
    this._annotator,
  ) : _eventParser = eventParserCache[entityMapping],
      _context = Failure(input, 0, '');

  final Parser<XmlEvent> _eventParser;
  final XmlAnnotator _annotator;

  Result<XmlEvent>? _context;
  XmlEvent? _current;

  @override
  XmlEvent get current => _current!;

  @override
  bool moveNext() {
    final context = _context;
    if (context != null) {
      final result = _eventParser.parseOn(context);
      if (result is Success) {
        _context = result;
        _current = result.value;
        _annotator.annotate(
          result.value,
          buffer: context.buffer,
          start: context.position,
          stop: result.position,
        );
        return true;
      } else if (context.position < context.buffer.length) {
        // In case of an error, skip one character and throw an exception.
        _context = context.failure(result.message, context.position + 1);
        _current = null;
        throw XmlParserException(
          result.message,
          buffer: result.buffer,
          position: result.position,
        );
      } else {
        // In case of reaching the end, terminate the iterator.
        _context = null;
        _current = null;
        _annotator.close(buffer: context.buffer, position: context.position);
        return false;
      }
    }
    return false;
  }
}
