/* Blinker
   Copyright 2011-2019 Stefan Schuermans <stefan@blinkenarea.org>
   Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
   a blinkenarea.org project */

#ifndef BLINKER_PLAYER_H
#define BLINKER_PLAYER_H

#include <list>
#include <string>

#include <BlinkenLib/BlinkenMovie.h>

#include "Directory.h"
#include "File.h"
#include "InStreamFile.h"
#include "InSyncFile.h"
#include "ListTracker.h"
#include "Mgrs.h"
#include "Module.h"
#include "OutStreamFile.h"
#include "StreamRecv.h"
#include "SyncRecv.h"
#include "Time.h"
#include "TimeCallee.h"

namespace Blinker {

/// a movie player
class Player: public Module, public StreamRecv, public SyncRecv,
              public TimeCallee
{
protected:
  /// movie in playlist
  class Movie;

  /// playlist tracker
  typedef ListTracker<Player, Movie, File> PlaylistTracker;

  /// playlist iterator
  typedef PlaylistTracker::ListIt PlaylistIt;

public:
  /**
   * @brief constructor
   * @param[in] name module name
   * @param[in] mgrs managers
   * @param[in] dirBase base directory
   */
  Player(const std::string &name, Mgrs &mgrs, const Directory &dirBase);

  /// virtual destructor
  virtual ~Player();

private:
  /// copy constructor disabled
  Player(const Player &that);

  /// assignment operator disabled
  const Player & operator=(const Player &that);

public:
  /// check for update of configuration
  virtual void updateConfig();

  /**
   * @brief set current frame
   * @param[in] stream stream name
   * @param[in] pFrame current frame (NULL for none)
   */
  virtual void setFrame(const std::string &stream, stBlinkenFrame *pFrame);

  /**
   * @brief send synchronization information
   * @param[in] sync sync stream name
   * @param[in] pInfo synchronization information
   */
  virtual void sendInfo(const std::string &sync, Info &info);

  /// callback when requested time reached
  virtual void timeCall();

protected:
  /// halt player
  void halt();

  /// continue playing
  void cont();

  /// check if current movie changed and react
  void checkCurChanged();

  /// process current frame
  void procFrame();

  /// send current frame to output stream
  void sendFrame();

  /**
   * @brief seek to movie by name
   * @param[in] name name of movie to seek to (name cmp according to SyncRecv)
   */
  void seekToMovie(const std::string &name);

  /**
   * @brief seek to position in current movie
   * @param[in] tgtPos target position in current movie to seek to
   * @return true if movie position has been changed, false otherwise
   */
  bool seekToPos(const Time &tgtPos);

  /**
   * @brief seek backwards in current movie
   * @param[in] goback time to seek backwards in current movie
   */
  void seekBackwards(Time goback);

  /**
   * @brief seek forwards in current movie
   * @param[in] go time to seek forwards in current movie
   */
  void seekForwards(Time go);

protected:
  OutStreamFile   m_fileOutStream;   ///< output stream name file
  InStreamFile    m_fileHaltStream;  /**< halt stream name file
                                          (player halts if stream active) */
  InSyncFile      m_fileInSync;      ///< input sync stream
  PlaylistTracker m_playlistTracker; ///< current playlist
  bool            m_curValid;        ///< if there is a current frame
  bool            m_unknownMovie;    ///< unknown movie is playing (via sync)
  PlaylistIt      m_curEntry;        ///< current playlist entry
  int             m_curFrame;        ///< current frame in movie
  Time            m_curFrameStart;   /**< start time of current frame
                                          relative to start of movie */
  Time            m_curFrameEnd;     /**< end time of current frame
                                          relative to start of movie */
  bool            m_curChange;       ///< current movie changed
  bool            m_halted;          ///< if player is halted
  Time            m_remainTime;      /**< remaining time of current frame
                                          (valid if m_curValid && m_halted) */
  Time            m_nextTime;        /**< when to show next frame
                                          (valid if m_curValid && !m_halted) */
  Time            m_maxDeviation;    ///< max. deviation from sync stream
}; // class Player

} // namespace Blinker

#endif // #ifndef BLINKER_PLAYER_H

