/* Interface for a movie linked list. Supports creating a movie, adding a frame,
 * inserting a movie within a movie, and applying a function to each frame.
 *
 *  Publicly visible types: 
 *    movie_t
 *  Publicly visible operations:
 *    create   - Create a new empty movie
 *    is_empty - Determine whether a given movie has any frames
 *    size     - Find the number of frames in the movie
 *    add      - Append a frame to the end of a given movie
 *    insert   - Insert a movie after a specified frame in another movie
 *    apply    - Apply an operation to each Picture frame of a movie
 *    clear    - Empty the list; remove any used resources from the heap 
 *
 * Original author:
 *  Jerod Weinman
 */

#ifndef __MOVIE_H__
#define __MOVIE_H__

#include <stddef.h>
#include <stdbool.h>
#include <MyroC.h>

typedef struct node node_t;   /* Shorthand type for nodes in the picture list */

typedef struct {     /* Wrapper struct for the movie as a linked list */
  node_t * first;
  node_t * last;
} movie_t;

struct node { /* Singly-linked list nodes contain a Picture and point to next */
  Picture frame;
  node_t * next;
};


/* Create a new empty movie. */
movie_t
create (void);


/* Determine whether the movie referred to is empty 
 * 
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 * Postconditions:
 *   Returns true if the movie contains no frames, false otherwise
 */
bool
is_empty (const movie_t * movie);


/* Determine the number of frames in the movie referred to
 *
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 * Postconditions
 *   Returns the number of frames in the movie
 */
size_t
size (const movie_t * movie);


/* Add a frame to the end of the movie referred to
 * 
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 * Postconditions:
 *   Returns true when:
 *     size (movie) has increased by one and is_empty (movie) is now false
 *     movie->last refers to a new node containing a copy of frame
 *   Returns false and prints an error when a new node cannot be allocated
 */
bool
add (movie_t * movie, Picture frame);


/* Insert a scene into an existing movie before the given index
 *
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 *   scene != NULL
 *   scene points to a valid movie struct
 *   ! is_empty (scene) [verified]
 *   0 <= index <= size (movie) [verified]
 * Postconditions:
 *   No new nodes are created
 *   The first node of scene appears at the given index (zero-based) in movie
 *   The last node of scene is updated to point to the node at index
 *     in the original movie, if index < size(movie).
 *  If index == 0, then movie->first == scene->first.
 *  If index == size(movie) [before modifications], then 
 *    movie->last == scene->last.
 */
void
insert (movie_t * movie, movie_t * scene, size_t index);


/* Apply a function (presumably with side-effects) to each movie frame in turn
 *
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 * Postconditions:
 *   Function process has been applied sequentially to the movie frames
 */
void
apply (movie_t * movie, void process (Picture * frame));


/* Free all resources associated with the movie and set it to be empty
 *
 * Preconditions:
 *   movie != NULL
 *   movie points to a valid movie struct
 * Postconditions:
 *   All heap resources for the movie nodes have been freed
 *   is_empty(movie)
 */
void
clear (movie_t * movie);

#endif
