// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/DataInputFactory.java
// public interface DataInputFactory {
//   public DataInput create(InputStream inputStream);
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/DatabasePage.java
// @EqualsAndHashCode
// @ToString
// public class DatabasePage {
//   private DatabasePageHeader pageHeader;
//   private byte[] pageData = new byte[500];
// 
//   public DatabasePage(DatabasePageHeader pageHeader, byte[] pageData) {
//     this.pageHeader = pageHeader;
//     this.pageData = pageData;
//   }
// 
//   public DatabasePageHeader getPageHeader() {
//     return pageHeader;
//   }
// 
//   public byte[] getPageData() {
//     return pageData;
//   }
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/DatabasePageHeader.java
// @EqualsAndHashCode
// @ToString
// public class DatabasePageHeader {
//   private long firstRecordIndex;
//   private long numberOfRecords;
//   private RecordType recordType;
//   private byte revision;
//   private long pageNumber;
//   private long reserved2;
//   private long reversed3;
//   private long reserved4;
//   private int crc;
// 
//   public DatabasePageHeader(long firstRecordIndex, long numberOfRecords, RecordType recordType, byte revision,
//                             long pageNumber, long reserved2, long reversed3, long reserved4, int crc) {
//     this.firstRecordIndex = firstRecordIndex;
//     this.numberOfRecords = numberOfRecords;
//     this.recordType = recordType;
//     this.revision = revision;
//     this.pageNumber = pageNumber;
//     this.reserved2 = reserved2;
//     this.reversed3 = reversed3;
//     this.reserved4 = reserved4;
//     this.crc = crc;
//   }
// 
//   public long getFirstRecordIndex() {
//     return firstRecordIndex;
//   }
// 
//   public long getNumberOfRecords() {
//     return numberOfRecords;
//   }
// 
//   public RecordType getRecordType() {
//     return recordType;
//   }
// 
//   public byte getRevision() {
//     return revision;
//   }
// 
//   public long getPageNumber() {
//     return pageNumber;
//   }
// 
//   public long getReserved2() {
//     return reserved2;
//   }
// 
//   public long getReversed3() {
//     return reversed3;
//   }
// 
//   public long getReserved4() {
//     return reserved4;
//   }
// 
//   public int getCrc() {
//     return crc;
//   }
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/GlucoseReadRecord.java
// @EqualsAndHashCode
// @ToString
// public class GlucoseReadRecord {
//   public static final int RECORD_LENGTH = 13;
// 
//   private long internalSecondsSinceDexcomEpoch;
//   private long localSecondsSinceDexcomEpoch;
//   private int glucoseValueWithFlags;
//   private byte trendArrowAndNoise;
//   private long recordNumber;
//   private long pageNumber;
// 
//   public GlucoseReadRecord(long internalSecondsSinceDexcomEpoch,
//                            long localSecondsSinceDexcomEpoch,
//                            int glucoseValueWithFlags,
//                            byte trendArrowAndNoise,
//                            long recordNumber,
//                            long pageNumber) {
//     this.internalSecondsSinceDexcomEpoch = internalSecondsSinceDexcomEpoch;
//     this.localSecondsSinceDexcomEpoch = localSecondsSinceDexcomEpoch;
//     this.glucoseValueWithFlags = glucoseValueWithFlags;
//     this.trendArrowAndNoise = trendArrowAndNoise;
//     this.recordNumber = recordNumber;
//     this.pageNumber = pageNumber;
//   }
// 
//   public long getInternalSecondsSinceDexcomEpoch() {
//     return internalSecondsSinceDexcomEpoch;
//   }
// 
//   public long getLocalSecondsSinceDexcomEpoch() {
//     return localSecondsSinceDexcomEpoch;
//   }
// 
//   public int getGlucoseValueWithFlags() {
//     return glucoseValueWithFlags;
//   }
// 
//   public byte getTrendArrowAndNoise() {
//     return trendArrowAndNoise;
//   }
// 
//   public long getRecordNumber() {
//     return recordNumber;
//   }
// 
//   public long getPageNumber() {
//     return pageNumber;
//   }
// }


import com.google.common.base.Throwables;
import org.glukit.dexcom.sync.DataInputFactory;
import org.glukit.dexcom.sync.model.DatabasePage;
import org.glukit.dexcom.sync.model.DatabasePageHeader;
import org.glukit.dexcom.sync.model.GlucoseReadRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
package org.glukit.dexcom.sync.responses;




/**
 * This handles common work to do for all record-based {@link DatabasePagesResponse}s such as
 * {@link org.glukit.dexcom.sync.model.RecordType#EGVData} and
 * {@link org.glukit.dexcom.sync.model.RecordType#UserEventData}.
 *
 * @author alexandre.normand
 */
public abstract class GenericRecordDatabasePagesResponse<T> extends DatabasePagesResponse {
  private Logger LOGGER = LoggerFactory.getLogger(this.getClass());

  public GenericRecordDatabasePagesResponse(DataInputFactory dataInputFactory) {
    super(dataInputFactory);
  }

  public List<T> getRecords() {
    List<T> records = newArrayList();
    try {
      for (DatabasePage page : getPages()) {
        DatabasePageHeader header = page.getPageHeader();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(page.getPageData());
        DataInput input = this.dataInputFactory.create(inputStream);

        LOGGER.debug(format("Parsing [%d] records...", header.getNumberOfRecords()));
        for (int i = 0; i < header.getNumberOfRecords(); i++) {
          byte[] recordBytes = new byte[getRecordLength()];
          input.readFully(recordBytes, 0, getRecordLength());

          T record = parseRecord(recordBytes, header, header.getFirstRecordIndex() + i);

// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/DataInputFactory.java
// public interface DataInputFactory {
//   public DataInput create(InputStream inputStream);
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/DatabasePage.java
// @EqualsAndHashCode
// @ToString
// public class DatabasePage {
//   private DatabasePageHeader pageHeader;
//   private byte[] pageData = new byte[500];
// 
//   public DatabasePage(DatabasePageHeader pageHeader, byte[] pageData) {
//     this.pageHeader = pageHeader;
//     this.pageData = pageData;
//   }
// 
//   public DatabasePageHeader getPageHeader() {
//     return pageHeader;
//   }
// 
//   public byte[] getPageData() {
//     return pageData;
//   }
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/DatabasePageHeader.java
// @EqualsAndHashCode
// @ToString
// public class DatabasePageHeader {
//   private long firstRecordIndex;
//   private long numberOfRecords;
//   private RecordType recordType;
//   private byte revision;
//   private long pageNumber;
//   private long reserved2;
//   private long reversed3;
//   private long reserved4;
//   private int crc;
// 
//   public DatabasePageHeader(long firstRecordIndex, long numberOfRecords, RecordType recordType, byte revision,
//                             long pageNumber, long reserved2, long reversed3, long reserved4, int crc) {
//     this.firstRecordIndex = firstRecordIndex;
//     this.numberOfRecords = numberOfRecords;
//     this.recordType = recordType;
//     this.revision = revision;
//     this.pageNumber = pageNumber;
//     this.reserved2 = reserved2;
//     this.reversed3 = reversed3;
//     this.reserved4 = reserved4;
//     this.crc = crc;
//   }
// 
//   public long getFirstRecordIndex() {
//     return firstRecordIndex;
//   }
// 
//   public long getNumberOfRecords() {
//     return numberOfRecords;
//   }
// 
//   public RecordType getRecordType() {
//     return recordType;
//   }
// 
//   public byte getRevision() {
//     return revision;
//   }
// 
//   public long getPageNumber() {
//     return pageNumber;
//   }
// 
//   public long getReserved2() {
//     return reserved2;
//   }
// 
//   public long getReversed3() {
//     return reversed3;
//   }
// 
//   public long getReserved4() {
//     return reserved4;
//   }
// 
//   public int getCrc() {
//     return crc;
//   }
// }
// 
// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/model/GlucoseReadRecord.java
// @EqualsAndHashCode
// @ToString
// public class GlucoseReadRecord {
//   public static final int RECORD_LENGTH = 13;
// 
//   private long internalSecondsSinceDexcomEpoch;
//   private long localSecondsSinceDexcomEpoch;
//   private int glucoseValueWithFlags;
//   private byte trendArrowAndNoise;
//   private long recordNumber;
//   private long pageNumber;
// 
//   public GlucoseReadRecord(long internalSecondsSinceDexcomEpoch,
//                            long localSecondsSinceDexcomEpoch,
//                            int glucoseValueWithFlags,
//                            byte trendArrowAndNoise,
//                            long recordNumber,
//                            long pageNumber) {
//     this.internalSecondsSinceDexcomEpoch = internalSecondsSinceDexcomEpoch;
//     this.localSecondsSinceDexcomEpoch = localSecondsSinceDexcomEpoch;
//     this.glucoseValueWithFlags = glucoseValueWithFlags;
//     this.trendArrowAndNoise = trendArrowAndNoise;
//     this.recordNumber = recordNumber;
//     this.pageNumber = pageNumber;
//   }
// 
//   public long getInternalSecondsSinceDexcomEpoch() {
//     return internalSecondsSinceDexcomEpoch;
//   }
// 
//   public long getLocalSecondsSinceDexcomEpoch() {
//     return localSecondsSinceDexcomEpoch;
//   }
// 
//   public int getGlucoseValueWithFlags() {
//     return glucoseValueWithFlags;
//   }
// 
//   public byte getTrendArrowAndNoise() {
//     return trendArrowAndNoise;
//   }
// 
//   public long getRecordNumber() {
//     return recordNumber;
//   }
// 
//   public long getPageNumber() {
//     return pageNumber;
//   }
// }


// Path: dexcom-receiver/src/main/java/org/glukit/dexcom/sync/responses/GenericRecordDatabasePagesResponse.java
import com.google.common.base.Throwables;
import org.glukit.dexcom.sync.DataInputFactory;
import org.glukit.dexcom.sync.model.DatabasePage;
import org.glukit.dexcom.sync.model.DatabasePageHeader;
import org.glukit.dexcom.sync.model.GlucoseReadRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;

package org.glukit.dexcom.sync.responses;




/**
 * This handles common work to do for all record-based {@link DatabasePagesResponse}s such as
 * {@link org.glukit.dexcom.sync.model.RecordType#EGVData} and
 * {@link org.glukit.dexcom.sync.model.RecordType#UserEventData}.
 *
 * @author alexandre.normand
 */
public abstract class GenericRecordDatabasePagesResponse<T> extends DatabasePagesResponse {
  private Logger LOGGER = LoggerFactory.getLogger(this.getClass());

  public GenericRecordDatabasePagesResponse(DataInputFactory dataInputFactory) {
    super(dataInputFactory);
  }

  public List<T> getRecords() {
    List<T> records = newArrayList();
    try {
      for (DatabasePage page : getPages()) {
        DatabasePageHeader header = page.getPageHeader();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(page.getPageData());
        DataInput input = this.dataInputFactory.create(inputStream);

        LOGGER.debug(format("Parsing [%d] records...", header.getNumberOfRecords()));
        for (int i = 0; i < header.getNumberOfRecords(); i++) {
          byte[] recordBytes = new byte[getRecordLength()];
          input.readFully(recordBytes, 0, getRecordLength());

          T record = parseRecord(recordBytes, header, header.getFirstRecordIndex() + i);

          records.add(record);