/**
 * @file
 * $Id$
 * $Revision$
 * $Author$
 * $Date$
 *
 * This file is part of The iWear Framework.
 * In particular this file is part of the (WLAN) Location package
 *
 * The iWear Framework 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 as in version 2 of the License.

 * 
 * The iWear Framework 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
 * The iWear Framework; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __IWLOCATOR_LOCATOR_EVENT_H
#define __IWLOCATOR_LOCATOR_EVENT_H

#ifndef __IWEAR_EVENT_H
#include <iwear/eventbase.h>
#endif

#ifndef __IWEAR_FUNCTOR_H
#include <iwear/functor.h>
#endif

#ifndef __IWLOCATOR_LOCATION_H
#include <iwlocator/location.h>
#endif

namespace iwear
{
    namespace sensor
    {
	namespace location
	{
typedef DualFunctor<double,bool> LEFunctor;
typedef DualFunctor<Location, bool> LocFunctor;

/**
 * This is the base class for the iwlocator library events. It holds some
 * flags, and some commonly used functions.
 */
class LocatorEventBase
{
friend class LocationManager;
protected:
    bool need_dispatch : 1;
    mutable bool need_deliver : 1;
public:
    static inline void check_bufferzone( float dst,float distance,float bfzone,bool& within,bool& trigger_state )
    {
	if ( within )
	{
	    trigger_state = ((distance + bfzone) > dst );
	    within = trigger_state;
	}
	else
	{
	    trigger_state = ((distance - bfzone) > dst );
	    within = trigger_state;
	}
    }

    inline bool deliver_needed( void ) const 
    { 
	bool ret = need_deliver;
	need_deliver = false; return ret; 
    }
    virtual ~LocatorEventBase();
    LocatorEventBase();
};

/**
 * This is a simple event which checks if a given value is within certain
 * boundaries.
 * @note It is very similar to the DataSensorEvent from libiwsens, so we might
 * want to share some implementation in the future.
 */
class SpeedLocatorEvent : public LocatorEventBase, public Event<LEFunctor>/*{{{*/
{
friend class LocationManager;
private:
protected:
   /**
    * Store the value here, that lead to the event
    */
    double event_value;

   /**
    * This is the lower bound of the interval to check for
    */
    double lower_bound;

   /**
    * And this is the upper one
    */
    double upper_bound;

   /**
    * If the event_value was within the bound the last time we checked this
    * event (to tell the receiver of the event whether we have entered or
    * leaved the interval, and to check if the conditions have changed (in
    * which case we send the event))
    */
    bool last_state : 1;
public:
    /**
     * This does the actual call on the user-supplied functor, providing
     * information about the sensors value and if the interval was entered or
     * leaved.
     */
    virtual void dispatch( void );

    /**
     * Construct the event out of the lower and upper bound. We use doubles
     * here, since we might have a huge offset (like it is for seconds since
     * epoch)
     */
    SpeedLocatorEvent(LEFunctor&, double low, double up );
    virtual ~SpeedLocatorEvent();

    /**
     * Check if the event is triggered with the set value(s).
     */
    virtual bool is_triggered( void );
    virtual bool is_triggered( double val );
};/*}}}*/

/// In case one day we want to define an own class for the Heading we use an
/// typedef here
typedef SpeedLocatorEvent HeadLocatorEvent;

/**
 * For the location base checks, we currently have 4 main different checks we
 * can register for.
 */
enum location_check
{
    lcheck_symbolic,	///< Check if the symbolic information matches
    lcheck_coordinate,  ///< Check if the coordinate information matches
    lcheck_area,	///< Check if the coordinates are within a certain area
    lcheck_changed,	///< Just check if the symbolics have changed
    num_location_check
};

/**
 * This event is to check for all checks registered on certain Location
 * informations.
 */
class LocLocatorEvent : public LocatorEventBase, public Event<LocFunctor>/*{{{*/
{
friend class LocationManager;
private:
protected:

   /**
    * The location thats saved for comparison, to check if this is event is
    * triggered. It saves coordinates, area or symbols for the specific
    * registered event type.
    */
    Location mloc;

    /**
     * This is the location that triggered the event.
     */
    Location triggerloc;

    /**
     * We save the last trigger state because of the "big is_triggered"
     * function
     */
    float distance;
    union {
	float bfzone;
	bool lazy;
    } d;
    location_check sca : ENUM_MIN_BITS(location_check);

    /// @warning never make this a bitset, we need to take the adress sometimes
    bool trigger_state;
    /// @warning never make this a bitset, we need to take the adress sometimes
    bool within;
public:
    virtual void dispatch( void );
    virtual bool is_triggered(void);
    virtual bool is_triggered( const Location& tloc );
    LocLocatorEvent( LocFunctor&, const LocationSymbol&, bool lzy);
    LocLocatorEvent( LocFunctor&, const LocationCoordinate&, float dst, float bfz);
    LocLocatorEvent( LocFunctor&, const LocationArea&);
    LocLocatorEvent( LocFunctor& );
    virtual ~LocLocatorEvent( );
};/*}}}*/

/**
 * This Event is for checking of Buffer zone based checks, i.e. for value
 * similarities and a little jumpiness reduction in the boundaries.
 */
class BufferLocatorEvent : public LocatorEventBase, public Event<LocFunctor>/*{{{*/
{
friend class LocationManager;
private:
protected:
    Location trigloc;
    float trigdist;
    float distance;
    float bfzone;
    bool trigger_state;
    bool within;
public:
    virtual void dispatch( void );
    virtual bool is_triggered(void);
    virtual bool is_triggered( float dist, const Location&  );
    BufferLocatorEvent( LocFunctor&, float dist, float bfz = 0.0 );
    virtual ~BufferLocatorEvent();
};/*}}}*/

} // namespace iwear
} // namespace sensor
} // namespace location
#endif
