/* 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_EDOBJECT_HPP
#define NMM_EDOBJECT_HPP NMM_EDOBJECT_HPP

#include "nmm/nmm_prefix.hpp"

#include "nmm/Result.hpp"

#include <memory>
#include <list>
#include <string>
#include <algorithm>

#include "visibility.hpp"

namespace NMM {
  
  class Event;
  
  /** Base class for all EventDispatcher objects (EDObjects).
   *
   * This is the base class for all EventDispatcher-objects (EDObjects). An EDObject is a simple function
   * wrapper, that receives its arguments from an event. The method disaptch must be implemented and executes
   * the method itself. After Excution return values must be stored in the Event.
   */
  class DLLEXPORT EDObject {
  public:
    /** Saves a pair of states. 
     */
    typedef std::pair<int, int> i_state;

    /** Constructor.
     */
    EDObject() { }

    /** Destructor.
     */
    virtual ~EDObject() {}

    /** Dispatches Event given as argument.
     *
     * Abstract method that every EventDispatcherObject must implement .
     */
    virtual Result dispatch(Event&) = 0;

    /** Check if pair of states is required.
     * 
     * @param from_state source state
     * @param to_state destination state
     * @return true, if state transition is required else false
     */
    inline bool  isRequired(int from_state, int to_state)   const { if (find(__required_list.begin(), __required_list.end(), i_state(from_state, to_state)) == __required_list.end()) return false; return true;}

    /** Checks if given state has been executed.
     * The return value is only valid, if the mandatory bit is also set for this state.
     *
     * @param s state to check
     * @return true if given state has been executed else false
     */
    inline bool isExecuted(int s)                           const { return ( find(__executed.begin(), __executed.end(), s) != __executed.end()); }

    /** Marks given state as executed.
     * This method is for internal use!!!!
     *
     * @param state state to be marked as executed
     */
    inline void setExecuted(int state)                            { if (!isExecuted(state) ) __executed.push_back(state); }

    /** Resets the execution value of state s. 
     * This method is for internal use!!!!
     *
     * @param s state to remove executed mark
     */
    inline void reset(int s)                                      { __executed.remove(s); }

    /** Resets the execution value for all states. 
     * This mehtod is for internal use!!!!
     */
    inline void reset()                                           { __executed.clear(); }

    /** Mark state transition as required. 
     *
     * @param from_state source state
     * @param to_state destination state
     */
    inline void addRequired(int from_state, int to_state)         { if (!isRequired(from_state, to_state)) __required_list.push_back(i_state(from_state, to_state)); }

    /** Mark state as limited.
     *
     * @param state state to mark as limited
     */
    inline void addLimited(int state)                             { if ( find(__limited_list.begin(), __limited_list.end(), state) == __limited_list.end() ) __limited_list.push_back(state); }

    /** Returns the states which allows the execution of this method. 
     * If the list is empty, the method can be executed in all states.
     *
     * @return list of states in which method can be executed
     */
    inline const std::list<int>& getLimited()                    const { return __limited_list; }

    /** Returns the states which allows the execution of this method. 
     * If the list is empty, the method can be executed in all states
     *
     * @return list of states in which method can be executed
     */
    inline       std::list<int>& getLimited()                          { return __limited_list; }

    /** Check if state is marked as limited.
     * 
     * @param state state to check
     * @return true if state has been marked as limited, false otherwise
     */
    inline bool isExecutionAllowed(int state)               const { if (__limited_list.empty()) return true; return ( find(__limited_list.begin(), __limited_list.end(), state) != __limited_list.end() );}

    /** Creates an Event with TInValues. 
     * The TInValues have correct type and can configured by a stream.
     */
    virtual Event* createEvent(const std::string& = std::string()) const = 0;

  private:
    std::list<i_state> __required_list;            ///< list for required states
    std::list<int>     __limited_list;             ///< list for limited states
    std::list<int>     __executed;                 ///< list for successfully executed states
  };

}

#include "nmm/nmm_suffix.hpp"

#endif
