import 'dart:collection';

import 'image.dart';

/**
 * Stores multiple images, most often as the frames of an animation.
 *
 * Some formats, such as [TiffDecoder], support multiple images that are not
 * to be interpreted as animation, but rather multiple pages of a document.
 * The [Animation] container is still used to store the images for these files.
 * The [frameType] property is used to differentiate multi-page documents from
 * multi-frame animations, where it is set to [PAGE] for documents and
 * [ANIMATION] for animated frames.
 *
 * All [Decoder] classes support decoding to an [Animation], where the
 * [Animation] will only contain a single frame for single image formats
 * such as JPEG, or if the file doesn't contain any animation such as a single
 * image GIF.  If you want to generically support both animated and non-animated
 * files, you can always decode to an animation and if the animation has only
 * a single frame, then it's a non-animated image.
 *
 * In some cases, the frames of the animation may only provide a portion of the
 * canvas, such as the case of animations encoding only the changing pixels
 * from one frame to the next.  The [width] and [height] and [backgroundColor]
 * properties of the [Animation] provide information about the canvas that
 * contains the animation, and the [Image] frames provide information about
 * how to draw the particular frame, such as the area of the canvas to draw
 * into, and if the canvas should be cleared prior to drawing the frame.
 */
class Animation extends IterableBase<Image> {
  /// The frames of this document are to be interpreted as animation.
  static const int ANIMATION = 0;
  /// The frames of this document are to be interpreted as pages of a document.
  static const int PAGE = 1;

  /// The canvas width for containing the animation.
  int width;
  /// The canvas height for containing the animation.
  int height;
  /// The suggested background color to clear the canvas with.
  int backgroundColor = 0xffffffff;
  /// The frames of the animation.
  List<Image> frames = [];
  /// How many times should the animation loop (0 means forever)?
  int loopCount = 0;
  /// How should the frames be interpreted?  If [ANIMATION], the frames
  /// are part of an animated sequence.  If [PAGE], the frames are the pages
  /// of a document.
  int frameType = ANIMATION;

  /**
   * How many frames are in the animation?
   */
  int get numFrames => frames.length;

  /**
   * How many frames are in the animation?
   */
  int get length => frames.length;

  /**
   * Get the frame at the given [index].
   */
  Image operator[](int index) => frames[index];

  /**
   * Add a frame to the animation.
   */
  void addFrame(Image image) {
    frames.add(image);
  }

  /**
   * The first frame of the animation.
   */
  Image get first => frames.first;

  /**
   * The last frame of the animation.
   */
  Image get last => frames.last;

  /**
   * Is the animation empty (no frames)?
   */
  bool get isEmpty => frames.isEmpty;

  /**
   * Returns true if there is at least one frame in the animation.
   */
  bool get isNotEmpty => frames.isNotEmpty;

  /**
   * Get the iterator for looping over the animation.  This allows the
   * Animation to be used in for-each loops:
   * for (AnimationFrame frame in animation) { ... }
   */
  Iterator<Image> get iterator => frames.iterator;
}
