//[skeleton1.

package visual.dynamic.sampled;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

import collectionframework.*;
import event.*;
import visual.*;
import visual.statik.SimpleContent;

/**
 * A component that renders a sequence of Content objects
 * (i.e., static visual content)
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Screen extends    Visualization 
                    implements MetronomeListener
{
    private   boolean                     repeating;    
    private   int                         frameNumber, height, width;
    private   Iterator<SimpleContent>     frames;    
    protected Metronome                   metronome;
    protected SimpleContent               currentFrame;    

    public static final int               FRAME_DELAY = 42;    
//]skeleton1.
//[iterator1.

    protected NullIterator<SimpleContent> currentFrameIterator;    
//]iterator1.
//[transition1.

    // Attributes used for transitions
    private IntervalIndexedCollection<Transition> transitions;
//]transition1.
//[superimposition1.

    // Attributes used for superimpositions
    private IntervalIndexedCollection<Superimposition> superimpositions;
//]superimposition1.
//[skeleton2.

    /**
     * Default Constructor
     */
    public Screen()
    {
       super();
       metronome = new Metronome(FRAME_DELAY);
       metronome.addListener(this);       
       setRepeating(false);       
//]skeleton2.
//[iterator2.

       currentFrameIterator = new NullIterator<SimpleContent>();
//]iterator2.
//[transition2.

       transitions = new IntervalIndexedCollection<Transition>();       
//]transition2.
//[superimposition2.

       superimpositions = new IntervalIndexedCollection<Superimposition>();
//]superimposition2.
//[skeleton3.

    }
//]skeleton3.
//[superimposition3.

    /**
     * Add a Superimposition
     *
     * Note: This method does not ensure that 
     * the order is correct
     *
     * @param si      The Superimposition to add
     */
    public void addSuperimposition(Superimposition si)
    {
       superimpositions.add(si, si.getFirstFrame(), si.getLastFrame());
    }
//]superimposition3.
//[transition3.

    /**
     * Add a Transition
     *
     * Note: This method does not ensure that 
     * the order is correct
     *
     * @param t   The Transition to add
     */
    public void addTransition(Transition t)
    {
       transitions.add(t, t.getFirstFrame(), t.getLastFrame());       
    }
//]transition3.
//[advanceFrame.

    /**
     * Advance to the next frame
     */
    private void advanceFrame()
    {
       if ((frames != null) && (frames.hasNext()))
       {
          currentFrame = frames.next();
          frameNumber++;          
       }
       else
       {
          currentFrame = null;
          frameNumber  = -1;          
       }
    }
//]advanceFrame.


//[skeleton4.

    /**
     * Create the default view associated with this Visualization
     *
     * Note: This method should only be called by constructors.
     *       It should be overridden by derived classes that 
     *       need to use a specialized view
     */
    protected VisualizationView createDefaultView()
    {
       ScreenRenderer    renderer;
       
       renderer = new ScreenRenderer(new PlainVisualizationRenderer());       

       return new VisualizationView(this, renderer);
    }

    /**
     * Get the numebr of the current frame
     *
     * @return  The number of the current frame
     */
    public int getFrameNumber()
    {
       return frameNumber;       
    }
//]skeleton4.
//[superimposition4.

    /**
     * Get the current superimpositions (if any)
     *
     * @return   The current superimpositions
     */
    public Iterator<Superimposition> getSuperimpositions()
    {
       Iterator<Superimposition>    result;
       
       result = null;
       if (frameNumber >= 0) result = superimpositions.iterator(frameNumber);

       return result;
    }
//]superimposition4.
//[transition4.

    /**
     * Get the current transitions (if any)
     *
     * @return   The current transitions
     */
    public Iterator<Transition> getTransitions()
    {
       Iterator<Transition>    result;
       
       result = null;
       if (frameNumber >= 0) result = transitions.iterator(frameNumber);

       return result;
    }
//]transition4.  
//[handleTick1.

    /**
     * Handle tick events (required by MetronomeListener)
     *
     * Specifically, make the current frame the "current" Content
     * and call repaint() to start the rendering process.
     * 
     * @param evt  The ActionEvent
     */
    public void handleTick(int time)
    {
       if (frames != null)
       {
          // See if we're done
          if (frameNumber < 0)
          {
             if   (repeating) reset();
             else             stop();             
          }

          // Start the rendering process (i.e., request that the
          // paint() method be called)
          repaint();

          // Advance the frame
          advanceFrame();          
       }
    }
//]handleTick1.

//[iterator3.

    /**
     * Get an Iterator that contains the current SimpleContent
     * object
     *
     * @return   The Iterator (containing 0 or 1 elements)
     */
    public Iterator<SimpleContent> iterator()
    {
       currentFrameIterator.setElement(currentFrame);
       if (frameNumber < 0) currentFrameIterator.clear();

       return currentFrameIterator;       
    }

    /**
     * Get an Iterator that contains either all of the SimpleContent
     * objects or the current SimpleContent Object
     *
     * @param  all  true to get all frames; false to get the current frame
     * @return   The SimpleContent objects
     */
    public Iterator<SimpleContent> iterator(boolean all)
    {
       Iterator<SimpleContent>       result;       

       if  (all) result = super.iterator();
       else      result = iterator();       

       return result;
    }
//]iterator3.


    /**
     * Reset the state of this Screen 
     * (e.g., so that it can "repeat")
     */
    private void reset()
    {
       // Initialize
       frameNumber = -1;       
       frames      = iterator(true);       
       
       // Advance the frame
       advanceFrame();
    }
    

//[skeleton5.

    /**
     * Set the frame rate (i.e., the number of frames per second)
     *
     * @param frameRate
     */
    public void setFrameRate(double frameRate)
    {
       int      delay;
       
       delay = (int)(1000.0 / frameRate);
       metronome.setDelay(delay);       
    }


    /**
     * Set whether this presentation should repeat/loop
     *
     * @param repeating    true to repeat/loop; false otherwise
     */
    public void setRepeating(boolean repeating)
    {
       this.repeating = repeating;       
    }


    /**
     * Start the presentation
     */
    public void start()
    {
       reset();          
       if (frames != null) metronome.start();
    }


    /**
     * Stop the presentation
     *
     */
    public void stop()
    {
       metronome.stop();          
    }

}
//]skeleton5.
