// Path: esjc-axon-eventstore/lib/src/main/java/de/qyotta/axonframework/eventstore/utils/EsjcEventstoreUtil.java
// @UtilityClass
// @SuppressWarnings("nls")
// public final class EsjcEventstoreUtil {
//    private static final Type METADATA_TYPE = new TypeToken<Map<String, ?>>() {
//       //
//    }.getType();
// 
//    private static final Gson gson = new Gson();
//    private static final Charset UTF_8 = Charset.forName("UTF-8");
// 
//    public static final String getStreamName(final String type, final Object identifier, final String prefix) {
//       return prefix + "-" + type.toLowerCase() + "-" + identifier.toString();
//    }
// 
//    @SuppressWarnings({ "rawtypes", "unchecked" })
//    public static DomainEventMessage domainEventMessageOf(final ResolvedEvent event) {
//       try {
//          final RecordedEvent originalEvent = event.originalEvent();
//          final Class<?> payloadType = Class.forName(originalEvent.eventType);
//          final Object payload = gson.fromJson(new String(originalEvent.data, UTF_8), payloadType);
//          final Map<String, ?> metaData = gson.fromJson(new String(originalEvent.metadata, UTF_8), METADATA_TYPE);
// 
//          final Map<String, ?> eventMetadata = (Map<String, ?>) metaData.get(Constants.EVENT_METADATA_KEY);
//          final long sequenceNumber = originalEvent.eventNumber;
//          final DateTime dateTime = new DateTime(originalEvent.created.toEpochMilli(), DateTimeZone.UTC);
//          final String identifier = String.valueOf(originalEvent.eventId);
//          final Object aggregateIdentifier = metaData.get(Constants.AGGREGATE_ID_KEY);
//          return new GenericDomainEventMessage(identifier, dateTime, aggregateIdentifier, sequenceNumber, payload, new MetaData(eventMetadata));
//       } catch (final ClassNotFoundException e) {
//          throw new RuntimeException(e);
//       }
// 
//    }
// }


import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import org.axonframework.domain.DomainEventMessage;
import org.axonframework.domain.DomainEventStream;
import org.slf4j.LoggerFactory;
import com.github.msemys.esjc.EventStore;
import com.github.msemys.esjc.ResolvedEvent;
import com.github.msemys.esjc.StreamEventsSlice;
import de.qyotta.axonframework.eventstore.utils.EsjcEventstoreUtil;
      long from = firstSequenceNumber;

      long numberOfEventsTotal = lastSequenceNumber - firstSequenceNumber;
      int numberOfEventsPerSlice = DEFAULT_NUMBER_OF_EVENTS_PER_SLICE;
      if (numberOfEventsTotal < DEFAULT_NUMBER_OF_EVENTS_PER_SLICE) {
         numberOfEventsPerSlice = Math.toIntExact(numberOfEventsTotal);
      }

      while (numberOfEventsTotal > 0) {
         try {
            final StreamEventsSlice streamEventsSlice = client.readStreamEventsForward(streamName, from, numberOfEventsPerSlice, true)
                  .get();
            events.addAll(streamEventsSlice.events);
            from = streamEventsSlice.nextEventNumber;
            numberOfEventsTotal = numberOfEventsTotal - numberOfEventsPerSlice;
         } catch (InterruptedException | ExecutionException e) {
            LOGGER.error(e.getMessage(), e);
         }
      }
   }

   @Override
   public boolean hasNext() {
      return !events.isEmpty() && currentEventNumber < events.size();
   }

   @Override
   public DomainEventMessage next() {
      final ResolvedEvent resolvedEvent = events.get(currentEventNumber);
      currentEventNumber++;
// Path: esjc-axon-eventstore/lib/src/main/java/de/qyotta/axonframework/eventstore/utils/EsjcEventstoreUtil.java
// @UtilityClass
// @SuppressWarnings("nls")
// public final class EsjcEventstoreUtil {
//    private static final Type METADATA_TYPE = new TypeToken<Map<String, ?>>() {
//       //
//    }.getType();
// 
//    private static final Gson gson = new Gson();
//    private static final Charset UTF_8 = Charset.forName("UTF-8");
// 
//    public static final String getStreamName(final String type, final Object identifier, final String prefix) {
//       return prefix + "-" + type.toLowerCase() + "-" + identifier.toString();
//    }
// 
//    @SuppressWarnings({ "rawtypes", "unchecked" })
//    public static DomainEventMessage domainEventMessageOf(final ResolvedEvent event) {
//       try {
//          final RecordedEvent originalEvent = event.originalEvent();
//          final Class<?> payloadType = Class.forName(originalEvent.eventType);
//          final Object payload = gson.fromJson(new String(originalEvent.data, UTF_8), payloadType);
//          final Map<String, ?> metaData = gson.fromJson(new String(originalEvent.metadata, UTF_8), METADATA_TYPE);
// 
//          final Map<String, ?> eventMetadata = (Map<String, ?>) metaData.get(Constants.EVENT_METADATA_KEY);
//          final long sequenceNumber = originalEvent.eventNumber;
//          final DateTime dateTime = new DateTime(originalEvent.created.toEpochMilli(), DateTimeZone.UTC);
//          final String identifier = String.valueOf(originalEvent.eventId);
//          final Object aggregateIdentifier = metaData.get(Constants.AGGREGATE_ID_KEY);
//          return new GenericDomainEventMessage(identifier, dateTime, aggregateIdentifier, sequenceNumber, payload, new MetaData(eventMetadata));
//       } catch (final ClassNotFoundException e) {
//          throw new RuntimeException(e);
//       }
// 
//    }
// }


// Path: esjc-axon-eventstore/lib/src/main/java/de/qyotta/axonframework/eventstore/EsjcEventStreamBackedDomainEventStream.java
import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import org.axonframework.domain.DomainEventMessage;
import org.axonframework.domain.DomainEventStream;
import org.slf4j.LoggerFactory;
import com.github.msemys.esjc.EventStore;
import com.github.msemys.esjc.ResolvedEvent;
import com.github.msemys.esjc.StreamEventsSlice;
import de.qyotta.axonframework.eventstore.utils.EsjcEventstoreUtil;

      long from = firstSequenceNumber;

      long numberOfEventsTotal = lastSequenceNumber - firstSequenceNumber;
      int numberOfEventsPerSlice = DEFAULT_NUMBER_OF_EVENTS_PER_SLICE;
      if (numberOfEventsTotal < DEFAULT_NUMBER_OF_EVENTS_PER_SLICE) {
         numberOfEventsPerSlice = Math.toIntExact(numberOfEventsTotal);
      }

      while (numberOfEventsTotal > 0) {
         try {
            final StreamEventsSlice streamEventsSlice = client.readStreamEventsForward(streamName, from, numberOfEventsPerSlice, true)
                  .get();
            events.addAll(streamEventsSlice.events);
            from = streamEventsSlice.nextEventNumber;
            numberOfEventsTotal = numberOfEventsTotal - numberOfEventsPerSlice;
         } catch (InterruptedException | ExecutionException e) {
            LOGGER.error(e.getMessage(), e);
         }
      }
   }

   @Override
   public boolean hasNext() {
      return !events.isEmpty() && currentEventNumber < events.size();
   }

   @Override
   public DomainEventMessage next() {
      final ResolvedEvent resolvedEvent = events.get(currentEventNumber);
      currentEventNumber++;
      return EsjcEventstoreUtil.domainEventMessageOf(resolvedEvent);