/* Network-Integrated Multimedia Middleware (NMM)
 * http://www.motama.com/nmm.html
 *  
 * Copyright (C) 2006-2007
 * Motama GmbH, Saarbruecken, Germany
 * http://www.motama.com
 *  
 * This file is part of NMM. 
 * 
 * NMM is free software; you can redistribute it and/or modify it    
 * under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; only version 2 of the License.      
 * 
 * NMM is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 
 * License for more details.  
 * 
 * You should have received a copy of the GNU General Public License 
 * along with NMM; if not, write to the Free Software Foundation,    
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */


#ifndef _NMM_SOURCE_CONTROLLER_HPP_
#define _NMM_SOURCE_CONTROLLER_HPP_ _NMM_SOURCE_CONTROLLER_HPP_

#include "nmm/nmm_prefix.hpp"

#include "Controller.hpp"
#include "nmm/multimedia/sync/interfaces/ISourceControllerImpl.hpp"
#include "nmm/utils/time/Interval.hpp"

namespace NMM {

  class Buffer;
  class GenericSyncSourceNode;

  //! This class represents a synchronization controller for source nodes.
  /*!
   */
  class SourceController : public Controller,
			   virtual public ISourceControllerImpl {
  protected:
    Interval parent_skew;       //!< The difference between the local clock
                                //!< (e.g. sound card clock) and the System clock
    Interval master_skew;       //!< The difference between the local clock
                                //!< and the System clock from the master of synchronization

    Time start_time;            ///< The time to start at; useful to avoid latencies
                                ///< between start of two different SyncSourceNodes

    Interval frame_time;        ///< The time for one frame from the SourceNode

    GenericSyncSourceNode* parent_node;

    ISourceSynchronizer* synchronizer;

    //! The states of the SourceController.
    /*! 
     *  The states are used to avoid problems with the sync_reset-event and multiple
     *  streams. If an sync_reset-event is sent and a demux distributes it to 
     *  multiple streams, the new events will not arrive at the source nodes in the 
     *  same moment. 
     */
    enum State {
      WORKING,         //!< The default state. Synchronization is active.
      RESET,           //!< All internal parameters are reset.
      PAUSE
    };

    //! The actual state of the SinkController.
    State state;

    //! Mutex to guarantee a consistent state variable.
    ThreadMutex state_mutex;

  public:
    //! The main constructor.
    /*!
     *  Sets the name and the mode, default values are "Controller"
     */
    SourceController(GenericSyncSourceNode* parent = 0,
		     const IController::Mode mode = Controller::DEFAULT_MODE);

    //! The main destructor.
    virtual ~SourceController();

    ////////////////////////////////////////////////////////
    //////////// Internal Methods, use to  /////////////////
    /////// communicate between Node and Controller ////////
    ////////////////////////////////////////////////////////

    //! This method is called by a Controller::isBufferValid - call. 
    /*!
     *  It checks if the buffer should be passed for further processing or discarded. 
     */
    virtual bool checkBufferValid(const Timestamp timestamp);

    //! This method checks if the buffer is too late and therefore some action should be taken
    bool isBufferLate();

    //! This method sets the skew between the system clock and the local clock (e.g. sound card clock). 
    void setParentSkew(const Interval& interval);

    //! This method sets the time for one frame from the source node (e.g. 40ms for a
    //! TVCardReadNode with PAL)
    void setFrameTime(Interval);

    //! This method returns the setted frame time
    Interval getFrameTime();

    //! This method corrects the timestamp of the given buffer
    void correctTimestamp(Buffer*);

  protected:
    // BEGIN> ISourceController interface
    /**
     * This method sets the time skew from the master of synchronization
     */
    virtual void setMasterSkew(const Interval& interval);

    /**
     * This method sets the start time for the controller. With the help of a start time, the nodes
     * can be told to start at e.g. 1 seconds after instantiating the Clock. This avoids scheduling
     * problems as one node would always be started some time after the other.
     */
    virtual void setStartTime(const Time& time);

    /**
     * This method sets the Synchronizer this Controller shall communicate with
     */
    virtual Result setSourceSynchronizer(const ISourceSynchronizer* value);

    /**
     * This method propagates the master flag to the node
     */
    void setSyncMaster(const nmm_bool& master);
    // END< ISourceController interface

    /**
     * The controller is told to pause the node via this method
     */
    virtual Result pause();

    /**
     * The controller is told to wake up the node via this method
     */
    virtual Result wakeup();

    /**
     * The controller is told to reset the node via this method
     */
    virtual Result reset();
  };

}

#include "nmm/nmm_suffix.hpp"

#endif // _NMM_SOURCE_CONTROLLER_HPP_
