
// ImagesPlayer.java
// Andrew Davison, April 2005, ad@fivedots.coe.psu.ac.th

/* Cílem třídy ImagesPlayer je zobrazování sekvence obrázků
   tvořenou 'n', 's' nebo 'g' obrázky načtené pomocí třídy ImagesLoader.

   Konstruktor třídy ImagesPlayer obdrží požadovanou dobu zobrazení
   celé sekvence (seqDuration). S její pomocí spočítá hodnotu proměnné 
   showPeriod, což je doba, po kterou budou zobrazeny jednotlivé obrázky
   sekvence.

   Animační interval (animPeriod) řídká, jak často se bude volat metoda
   updateTick(). Záměrem je, aby se tato metoda volala periodicky z metody
   update() animačního rámce.

   Při zavolání metody updateTick() se spočítá aktuální čas animace, s jehož
   pomocí se spočítá hodnota proměnné imPosition, která určí, který
   obrázek vrátí metoda getCurrentImage().

   Objekt typu ImagesPlayer lze nastavit tak, aby animaci přehrával cyklicky, aby ji
   zastavil, opětovně spustil nebo restartoval od daného obrázku.

   Po skončení sekvence lze zavolat metodu zpětného volání sequenceEnded(),
   realizovanou v nějaké implementaci rozhraní ImagesPlayerWatcher. 
*/

import java.awt.image.*;


public class ImagesPlayer
{
  private String imName;
  private boolean isRepeating, ticksIgnored;
  private ImagesLoader imsLoader;

  private int animPeriod;
         // inverval používaný v animačním cyklu (v milisekudnách)
  private long animTotalTime;

  private int showPeriod;     
         // doba zobrazení aktuálního obrázku (v milisekundách)
  private double seqDuration;   
         // celková doba zobrazení celé sekvence obrázků (v sekundách)

  private int numImages;
  private int imPosition;     // pozice aktuálního zobrazitelného obrázku

  private ImagesPlayerWatcher watcher = null;


  public ImagesPlayer(String nm, int ap, double d, 
                                boolean isr, ImagesLoader il) 
  {
    imName = nm;
    animPeriod = ap; 
    seqDuration = d;
    isRepeating = isr;
    imsLoader = il;

    animTotalTime = 0L;

    if (seqDuration < 0.5) {
      System.out.println("Varování: minimální doba trvání sekvence je 0,5 sekund.");
      seqDuration = 0.5;
    }

    if (!imsLoader.isLoaded(imName)) {
      System.out.println(imName + " ImagesLoader jej nezná");
      numImages = 0;
      imPosition = -1;
      ticksIgnored = true;
    }
    else {
      numImages = imsLoader.numImages(imName);
      imPosition = 0;
      ticksIgnored = false;
      showPeriod = (int) (1000 * seqDuration / numImages);
    }
  } // konec metody: konstruktoru: ImagesPlayer()



  public void updateTick()
  /* Předpokládáme, že se tato metoda volá každých animPeriod milisekudn. */
  {
    if (!ticksIgnored) {
      // aktualizuj celkový čas animace, modulo doba animační sekvence
      animTotalTime = (animTotalTime + animPeriod) % (long)(1000 * seqDuration);

      // spočti aktuální pozici obrázku (snímku) pro zobrazení
      imPosition = (int) (animTotalTime / showPeriod);   // mezi 0 a num-1
      if ((imPosition == numImages-1) && (!isRepeating)) {  // na konci sekvence
        ticksIgnored = true;   // u tohoto obrázku zastav
        if (watcher != null)
          watcher.sequenceEnded(imName);   // proveď zpětné volání
      }
    }
  }  // konec metody: metody: updateTick()



  public BufferedImage getCurrentImage()
  { if (numImages != 0)
      return imsLoader.getImage(imName, imPosition); 
    else
      return null; 
  } // konec metody: metody: getCurrentImage()


  public int getCurrentPosition()
  {  return imPosition;  }



  public void setWatcher(ImagesPlayerWatcher w)
  {  watcher = w;  }
   

  public void stop()
  /* volání metody updateTick() již nebudou aktualizovat 
     čas animace ani hodnotu proměnné imPosition. */

  {  ticksIgnored = true;  }


  public boolean isStopped()
  {  return ticksIgnored;  }


  public boolean atSequenceEnd()
  // nacházíme se na posledním obrázku a není aktivované cyklické přehráváhí?
  {  return ((imPosition == numImages-1) && (!isRepeating));  }



  public void restartAt(int imPosn)
  /* Začne znovu zobrazovat obrázky, počínaje obrázkem s číslem imPosn.
     S tím ovšem souvisí resetování času animace. */
  {
    if (numImages != 0) {
      if ((imPosn < 0) || (imPosn > numImages-1)) {
        System.out.println("Out of range restart, starting at 0");
        imPosn = 0;
      }

      imPosition = imPosn;
      // vypočítej vhodný čas animace
      animTotalTime = (long) imPosition * showPeriod;
      ticksIgnored = false;
    }
  }  // konec metody: metody: restartAt()


  public void resume()
  // začni na pozici předchozího obrázku
  { 
    if (numImages != 0)
      ticksIgnored = false;
  } 


} // konec metody: třídy: ImagesPlayer
