package com.bumptech.glide.load;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.bumptech.glide.load.ImageHeaderParser.ImageType;
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool;
import com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.List;

/**
 * Utilities for the ImageHeaderParser.
 */
public final class ImageHeaderParserUtils {
  // 5MB. This is the max image header size we can handle, we preallocate a much smaller buffer but
  // will resize up to this amount if necessary.
  private static final int MARK_POSITION = 5 * 1024 * 1024;

  private ImageHeaderParserUtils() { }

  /** Returns the ImageType for the given InputStream. */
  @NonNull
  public static ImageType getType(@NonNull List<ImageHeaderParser> parsers,
      @Nullable InputStream is, @NonNull ArrayPool byteArrayPool) throws IOException {
    if (is == null) {
      return ImageType.UNKNOWN;
    }

    if (!is.markSupported()) {
      is = new RecyclableBufferedInputStream(is, byteArrayPool);
    }

    is.mark(MARK_POSITION);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = parsers.size(); i < size; i++) {
      ImageHeaderParser parser = parsers.get(i);
      try {
        ImageType type = parser.getType(is);
        if (type != ImageType.UNKNOWN) {
          return type;
        }
      } finally {
        is.reset();
      }
    }

    return ImageType.UNKNOWN;
  }

  /** Returns the ImageType for the given ByteBuffer. */
  @NonNull
  public static ImageType getType(@NonNull List<ImageHeaderParser> parsers,
      @Nullable ByteBuffer buffer)
      throws IOException {
    if (buffer == null) {
      return ImageType.UNKNOWN;
    }

    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = parsers.size(); i < size; i++) {
      ImageHeaderParser parser = parsers.get(i);
      ImageType type = parser.getType(buffer);
      if (type != ImageType.UNKNOWN) {
        return type;
      }
    }

    return ImageType.UNKNOWN;
  }

  /**
   * Returns the orientation for the given InputStream.
   */
  public static int getOrientation(@NonNull List<ImageHeaderParser> parsers,
      @Nullable InputStream is, @NonNull ArrayPool byteArrayPool) throws IOException {
    if (is == null) {
      return ImageHeaderParser.UNKNOWN_ORIENTATION;
    }

    if (!is.markSupported()) {
      is = new RecyclableBufferedInputStream(is, byteArrayPool);
    }

    is.mark(MARK_POSITION);
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = parsers.size(); i < size; i++) {
      ImageHeaderParser parser = parsers.get(i);
      try {
        int orientation = parser.getOrientation(is, byteArrayPool);
        if (orientation != ImageHeaderParser.UNKNOWN_ORIENTATION) {
          return orientation;
        }
      } finally {
        is.reset();
      }
    }

    return ImageHeaderParser.UNKNOWN_ORIENTATION;
  }
}
