//
// Triple Play - utilities for use in PlayN-based games
// Copyright (c) 2011-2013, Three Rings Design, Inc. - All rights reserved.
// http://github.com/threerings/tripleplay/blob/master/LICENSE

package tripleplay.flump;

import playn.core.GroupLayer;
import playn.core.Layer;
import static playn.core.PlayN.*;

import tripleplay.anim.Animation;
import tripleplay.util.Destroyable;

/**
 * A convenient controller to play though multiple different movies. Designed for characters and
 * objects that have a separate Flump symbol for each of their animations, and need to switch
 * between them.
 */
public class MoviePlayer
    implements Destroyable
{
    public MoviePlayer (Library lib) {
        this(lib, graphics().createGroupLayer());
    }

    public MoviePlayer (Library lib, GroupLayer root) {
        _lib = lib;
        _root = root;
    }

    /** The layer the movies are placed on. */
    public Layer layer () {
        return _root;
    }

    /** The currently playing movie, if any. */
    public Movie movie () {
        return _currentMovie;
    }

    /** Whether the current movie is being looped. */
    public boolean looping () {
        return _oneshotMovie == null && _loopingMovie != null;
    }

    // TODO(bruno): public boolean setCache (CacheBuilder cache)

    /**
     * Shows a movie that plays once. When it completes, the last looping movie is returned to. It
     * is an error to call this without starting a loop() first.
     * @param name The symbol name of the movie to play.
     * @param restart If this movie is already being played, whether it will restart it from the
     *   beginning. Defaults to true.
     * @return This instance, for chaining.
     */
    public MoviePlayer play (String name, boolean restart) {
        if (_loopingMovie == null) {
            throw new IllegalStateException(
                "A loop must be started before the first call to play()");
        }
        if (restart || _oneshotMovie == null || !_oneshotMovie.symbol().name().equals(name)) {
            _oneshotMovie = setCurrent(createMovie(name));
        }
        return this;
    }

    public MoviePlayer play (String name) {
        return play(name, true);
    }

    /**
     * Shows a movie that loops forever.
     * @param name The symbol name of the movie to loop.
     * @param restart If this movie is already being looped, whether it will restart it from the
     *   beginning. Defaults to true.
     * @return This instance, for chaining.
     */
    public MoviePlayer loop (String name, boolean restart) {
        if (restart || _loopingMovie == null || !_loopingMovie.symbol().name().equals(name)) {
            _oneshotMovie = null;
            _loopingMovie = setCurrent(createMovie(name));
        }
        return this;
    }

    public MoviePlayer loop (String name) {
        return loop(name, true);
    }

    /** Creates an {@link Animation} that plays a one-shot movie. */
    public Animation animate (String name) {
        return new PlayAnimation(name);
    }

    public void update (float dt) {
        // If this update would end the oneshot movie, replace it with the looping movie
        if (_oneshotMovie != null && _oneshotMovie.position() + dt*_oneshotMovie.speed() >
                _oneshotMovie.symbol().duration) {
            _oneshotMovie = null;
            setCurrent(_loopingMovie);
        }
        _currentMovie.update(dt);
    }

    /** Override this to dress up avatars or any other custom initialization. */
    protected Movie createMovie (String name) {
        return _lib.createMovie(name);
    }

    /** Replace the currently active movie. */
    protected Movie setCurrent (Movie movie) {
        if (_currentMovie != null) {
            _root.remove(_currentMovie.layer());
        }
        _root.add(movie.layer());
        return _currentMovie = movie;
    }

    @Override public void destroy () {
        if (_currentMovie != null) {
            _currentMovie.layer().destroy();
        }
        _currentMovie = null;
        _loopingMovie = null;
        _oneshotMovie = null;
    }

    protected class PlayAnimation extends Animation {
        public PlayAnimation (String name) {
            _name = name;
        }

        @Override protected void init (float time) {
            play(_name);
            _playing = _currentMovie;
        }

        @Override protected float apply (float time) {
            // Wait until the original movie is no longer playing
            return (_currentMovie == _playing) ? 1 : 0;
        }

        protected String _name;
        protected Movie _playing;
    }

    protected Library _lib;
    protected GroupLayer _root;

    protected Movie _currentMovie;
    protected Movie _oneshotMovie;
    protected Movie _loopingMovie;
}


@@ -219,16 +219,37 @@
 flump;%0A%0A
+import react.Value;%0A%0A
 import p
@@ -266,24 +266,24 @@
 GroupLayer;%0A
-
 import playn
@@ -671,16 +671,173 @@
 yable%0A%7B%0A
+    /** The currently playing movie, if any. */%0A    public final Value%3CMovie%3E movie = Value.create(null);%0A    public Movie movie () %7B return movie.get(); %7D%0A%0A
     publ
@@ -1100,24 +1100,24 @@
  layer () %7B%0A
+
         retu
@@ -1137,121 +1137,8 @@
  %7D%0A%0A
-    /** The currently playing movie, if any. */%0A    public Movie movie () %7B%0A        return _currentMovie;%0A    %7D%0A%0A
     
@@ -3458,29 +3458,23 @@
         
-_currentM
+m
 ovie
+()
 .update(
@@ -3745,21 +3745,23 @@
  (Movie 
-movie
+current
 ) %7B%0A    
@@ -3764,37 +3764,31 @@
         if (
-_currentM
+m
 ovie
+()
  != null) %7B%0A
@@ -3812,29 +3812,23 @@
 .remove(
-_currentM
+m
 ovie
+()
 .layer()
@@ -3862,21 +3862,54 @@
 add(
-movie.layer()
+current.layer());%0A        movie.update(current
 );%0A 
@@ -3926,29 +3926,15 @@
 urn 
-_
 current
-Movie = movie
 ;%0A  
@@ -3989,29 +3989,23 @@
     if (
-_currentM
+m
 ovie
+()
  != null
@@ -4020,29 +4020,23 @@
         
-_currentM
+m
 ovie
+()
 .layer()
@@ -4061,38 +4061,8 @@
   %7D%0A
-        _currentMovie = null;%0A
     
@@ -4109,32 +4109,60 @@
 otMovie = null;%0A
+        movie.update(null);%0A
     %7D%0A%0A    prote
@@ -4389,29 +4389,23 @@
 aying = 
-_currentM
+m
 ovie
+()
 ;%0A      
@@ -4550,29 +4550,23 @@
 return (
-_currentM
+m
 ovie
+()
  == _pla
@@ -4729,43 +4729,8 @@
 t;%0A%0A
-    protected Movie _currentMovie;%0A
     

Make MoviePlayer.movie an observable Value.